Browse Source

sys: added module for handling physical data

cc430
Hauke Petersen 7 years ago
parent
commit
786895a378
  1. 16
      Makefile.dep
  2. 175
      sys/include/phydat.h
  3. 1
      sys/phydat/Makefile
  4. 81
      sys/phydat/phydat_str.c

16
Makefile.dep

@ -390,3 +390,19 @@ endif
ifneq (,$(filter xtimer,$(USEMODULE)))
FEATURES_REQUIRED += periph_timer
endif
ifneq (,$(filter saul_reg,$(USEMODULE)))
USEMODULE += saul
endif
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul
endif
ifneq (,$(filter saul,$(USEMODULE)))
USEMODULE += phydat
endif
ifneq (,$(filter phydat,$(USEMODULE)))
USEMODULE += fmt
endif

175
sys/include/phydat.h

@ -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 */
/** @} */

1
sys/phydat/Makefile

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

81
sys/phydat/phydat_str.c

@ -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…
Cancel
Save