
4 changed files with 273 additions and 0 deletions
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup sys_phydat Phydat |
||||
* @ingroup sys |
||||
* @brief Generic data container for physical data and utility functions |
||||
* |
||||
* The purpose of this module is to introduce a common view on physical data |
||||
* throughout RIOT. This data is typically the output from sensor readings, data |
||||
* aggregation, and also the input for actuators. |
||||
* |
||||
* The idea is to enable different sensor/actuator drivers and other RIOT |
||||
* modules to exchange and have the same view on this kind of data. Labeling |
||||
* data with a unit type it's scaling makes it possible to pipe data between |
||||
* modules in an automated fashion without the need of specialized software |
||||
* wrappers and/or data normalization modules. |
||||
* |
||||
* @todo It might make sense to introduce additional data types for |
||||
* increased precision, i.e. something like phydat_float_t... |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Generic data container for physical data interface |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef SECT_DATA_H |
||||
#define SECT_DATA_H |
||||
|
||||
#include <stdint.h> |
||||
#include <errno.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The fixed number of dimensions we work with |
||||
* |
||||
* We use a fixed number of 3 dimensions, as many physical values we encounter |
||||
* can be expressed this way. In practice we have e.g. readings from |
||||
* accelerometers, gyros, color sensors, or set data for RGB LEDs. |
||||
* |
||||
* When expressing 1-dimensional data we just ignore the 2 higher dimension. |
||||
* This leads to a slight overhead of some byte of memory - but we benefit from |
||||
* a unified data structure for passing around physical data. |
||||
*/ |
||||
#define PHYDAT_DIM (3U) |
||||
|
||||
/**
|
||||
* @brief The maximum length of a scaling string |
||||
*/ |
||||
#define PHYDAT_SCALE_STR_MAXLEN (sizeof("*E-128\0")) |
||||
|
||||
/**
|
||||
* @brief Definition of physical units and comparable data types |
||||
* |
||||
* This list should contain all needed physical units (e.g. SI units), but also |
||||
* non-physical units that can be used to define the type of data passed around. |
||||
* This can be for example BOOL or aggregate values. As rule of thumb, the unit |
||||
* list can contain anything that helps two modules automatically negotiate, if |
||||
* they can understand each other. |
||||
* |
||||
* @note Extent this list as needed. |
||||
*/ |
||||
enum { |
||||
/* generic values */ |
||||
UNIT_UNDEF, /**< unit undefined */ |
||||
UNIT_NONE, /**< data has no physical unit */ |
||||
/* temperature */ |
||||
UNIT_TEMP_C, /**< degree Celsius */ |
||||
UNIT_TEMP_F, /**< degree Fahrenheit */ |
||||
UNIT_TEMP_K, /**< Kelvin */ |
||||
/* dimension */ |
||||
UNIT_M, /**< meters */ |
||||
UNIT_M2, /**< square meters */ |
||||
UNIT_M3, /**< cubic meters */ |
||||
/* kinetic */ |
||||
UNIT_G, /**< gravitational force */ |
||||
UNIT_DPS, /**< degree per second */ |
||||
/* weight */ |
||||
UNIT_GR, /**< grams - not using the SI unit (kg) here to make scale
|
||||
* handling simpler */ |
||||
/* electricity */ |
||||
UNIT_A, /**< Ampere */ |
||||
UNIT_V, /**< Volts */ |
||||
UNIT_GS, /**< gauss */ |
||||
/* pressure */ |
||||
UNIT_BAR, /**< Beer? */ |
||||
UNIT_PA, /**< Pascal */ |
||||
/* light */ |
||||
UNIT_CD, /**< Candela */ |
||||
/* logical */ |
||||
UNIT_BOOL, /**< boolean value [0|1] */ |
||||
UNIT_PERCENT, /**< out of 100 */ |
||||
UNIT_PERMILL, /**< out of 1000 */ |
||||
UNIT_PPM, /**< part per million */ |
||||
/* aggregate values */ |
||||
UNIT_TIME, /**< the three dimensions contain sec, min, and hours */ |
||||
UNIT_DATE /**< the 3 dimensions contain days, months and years */ |
||||
/* extend this list as needed */ |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Generic data structure for expressing physical values |
||||
* |
||||
* Physical data is express in a 3-dimensional touple of values. In addition to |
||||
* the data fields, this struct contains further the (physical) unit and the |
||||
* scale factor of the data. The unit is expressed as constant. The scale factor |
||||
* is expressed as power of 10 (10^factor). |
||||
* |
||||
* The combination of signed 16-bit numbers with and the scale factor gives us a |
||||
* very high dynamic range (from -32*10^-131 to 32*10^130). I a wider sense we |
||||
* are saving the values as fixed floating points... |
||||
* |
||||
* The scale factor is identical for all 3 values. |
||||
* |
||||
* In a traditional (scientific) computational system the obvious choice for the |
||||
* used data type would be to use floats. We are however on heavily resource |
||||
* constrained (even 8-bit) embedded systems, so we use int16_t here. As most |
||||
* sensor are in some way ADC based, they normally do not use a higher accuracy |
||||
* than 12-14bit, so using 16-bit integers to represent this data is good enough |
||||
* in most cases. |
||||
*/ |
||||
typedef struct { |
||||
int16_t val[PHYDAT_DIM]; /**< the 3 generic dimensions of data */ |
||||
uint8_t unit; /**< the (physical) unit of the data */ |
||||
int8_t scale; /**< the scale factor, 10^*scale* */ |
||||
} phydat_t; |
||||
|
||||
/**
|
||||
* @brief Dump the given data container to STDIO |
||||
* |
||||
* @param[in] data data container to dump |
||||
* @param[in] dim number of dimension of @p data to dump |
||||
*/ |
||||
void phydat_dump(phydat_t *data, uint8_t dim); |
||||
|
||||
/**
|
||||
* @brief Convert the given unit to a string |
||||
* |
||||
* @param[in] unit unit to convert |
||||
* |
||||
* @return string representation of given unit (e.g. V or m) |
||||
* @return NULL if unit was not recognized |
||||
*/ |
||||
const char *phydat_unit_to_str(uint8_t unit); |
||||
|
||||
/**
|
||||
* @brief Convert the given scale factor to a NULL terminated string |
||||
* |
||||
* The given scaling factor will be given as SI unit (e.g. M for Mega, u for |
||||
* micro, etc) for obvious cases or in scientific notation (e.g. 2E11, 1E-22, |
||||
* etc) otherwise. |
||||
* |
||||
* @param[in] scale scale factor to convert |
||||
* @param[in] str buffer to write the result into, MUST be at least of |
||||
* length @p PHYDAT_SCALE_STR_MAXLEN |
||||
*/ |
||||
void phydat_scale_to_str(int8_t scale, char *str); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* SECT_DATA_H */ |
||||
/** @} */ |
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup driver_sensif |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Generic sensor/actuator data handling |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "fmt.h" |
||||
#include "phydat.h" |
||||
|
||||
void phydat_dump(phydat_t *data, uint8_t dim) |
||||
{ |
||||
if (data == NULL || dim > PHYDAT_DIM) { |
||||
puts("Unable to display data object"); |
||||
return; |
||||
} |
||||
printf("Data:"); |
||||
for (uint8_t i = 0; i < dim; i++) { |
||||
char tmp[PHYDAT_SCALE_STR_MAXLEN]; |
||||
phydat_scale_to_str(data->scale, tmp); |
||||
printf("\t[%i] %i%s%s\n", (int)i, (int)data->val[i], tmp, |
||||
phydat_unit_to_str(data->unit)); |
||||
} |
||||
} |
||||
|
||||
const char *phydat_unit_to_str(uint8_t unit) |
||||
{ |
||||
switch (unit) { |
||||
case UNIT_TEMP_C: return "°C"; |
||||
case UNIT_TEMP_F: return "°F"; |
||||
case UNIT_TEMP_K: return "K"; |
||||
case UNIT_M: return "m"; |
||||
case UNIT_G: return "g"; |
||||
case UNIT_DPS: return "dps"; |
||||
case UNIT_GR: return "G"; |
||||
case UNIT_A: return "A"; |
||||
case UNIT_V: return "V"; |
||||
case UNIT_GS: return "Gs"; |
||||
case UNIT_BAR: return "Bar"; |
||||
case UNIT_PA: return "Pa"; |
||||
case UNIT_CD: return "cd"; |
||||
default: return ""; |
||||
} |
||||
} |
||||
|
||||
void phydat_scale_to_str(int8_t scale, char *str) |
||||
{ |
||||
switch (scale) { |
||||
case 0: *str = '\0'; return; |
||||
case -3: *str = 'm'; break; |
||||
case -6: *str = 'u'; break; |
||||
case -9: *str = 'n'; break; |
||||
case -12: *str = 'p'; break; |
||||
case -15: *str = 'f'; break; |
||||
case 3: *str = 'k'; break; |
||||
case 6: *str = 'M'; break; |
||||
case 9: *str = 'G'; break; |
||||
case 12: *str = 'T'; break; |
||||
case 15: *str = 'P'; break; |
||||
default: |
||||
*str++ = 'E'; |
||||
str += fmt_s32_dec(str, scale) -1; |
||||
} |
||||
*++str = '\0'; |
||||
} |
Loading…
Reference in new issue