1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys/phydat: use flash_utils

This commit is contained in:
Marian Buschsieweke 2022-05-31 21:09:12 +02:00
parent 2825f5f2ae
commit 29cfeb752e
No known key found for this signature in database
GPG Key ID: CB8E3238CE715A94
4 changed files with 206 additions and 94 deletions

View File

@ -37,6 +37,8 @@
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include "modules.h"
#ifdef __cplusplus
@ -177,30 +179,55 @@ void phydat_dump(phydat_t *data, uint8_t dim);
/**
* @brief Convert the given unit to a string
*
* @param[in] unit unit to convert
* @param[in] unit unit to convert
*
* @return string representation of given unit (e.g. V or m)
* @return NULL if unit was not recognized
*
* @deprecated Use @ref phydat_unit_print or @ref phydat_unit_write instead
*
* @warning For classic Harvard architectures a small buffer is used to store
* the string, so that subsequent (or concurrent!) calls will
* overwrite the output.
*/
const char *phydat_unit_to_str(uint8_t unit);
/**
* @brief Return a string representation for every unit, including
* non-physical units like 'none' or 'time'
* @brief Same as @ref phydat_unit_to_str
*
* This function is useful when converting phydat_t structures to non-binary
* representations like JSON or XML.
* In practise all users used the verbose function anyway. Hence,
* @ref phydat_unit_to_str just covers all units and this is just a backward
* compatibility wrapper.
*
* In practice, this function extends phydat_unit_to_str() with additional
* identifiers for non physical units.
*
* @param[in] unit unit to convert
*
* @return string representation of given unit
* @return empty string ("") if unit was not recognized
* @deprecated Use @ref phydat_unit_print or @ref phydat_unit_write instead
*/
const char *phydat_unit_to_str_verbose(uint8_t unit);
/**
* @brief Print a unit
*
* @param[in] unit unit to print
*/
void phydat_unit_print(uint8_t unit);
/**
* @brief Write the string representation of the given unit into the given
* buffer
*
* @param[out] dest destination buffer to write to
* @param[in] max_size size of the buffer at @p dest
* @param[in] unit unit to convert
*
* @return Number of bytes written
* @retval -EOVERFLOW buffer at @p dest is too small
* @retval -EINVAL invalid unit in @p unit
*
* @warning The function will never write a terminating zero byte
* @note If you pass `NULL` for @p dest, it will return the number of bytes
* it would write (regardless of @p max_size)
*/
ssize_t phydat_unit_write(char *dest, size_t max_size, uint8_t unit);
/**
* @brief Convert the given scale factor to an SI prefix
*

View File

@ -20,8 +20,9 @@
#include <string.h>
#include "fmt.h"
#include "assert.h"
#include "flash_utils.h"
#include "fmt.h"
#include "phydat.h"
#define STATIC_LEN (14U)
@ -32,11 +33,11 @@
static size_t _bool_to_str(int16_t val, char *buf)
{
if (val) {
memcpy(buf, "true", 4);
flash_memcpy(buf, TO_FLASH("true"), 4);
return 4;
}
else {
memcpy(buf, "false", 5);
flash_memcpy(buf, TO_FLASH("false"), 5);
return 5;
}
}
@ -60,10 +61,10 @@ size_t phydat_to_json(const phydat_t *data, size_t dim, char *buf)
pos += (data->val[i]) ? 4 : 5; /* true: 4, false: 5 */
}
}
pos += strlen(phydat_unit_to_str_verbose(data->unit));
pos += phydat_unit_write(NULL, 0, data->unit);
}
else {
memcpy(buf, "{\"d\":", 5);
flash_memcpy(buf, TO_FLASH("{\"d\":"), 5);
pos += 5;
/* write data */
if (dim > 1) {
@ -84,13 +85,11 @@ size_t phydat_to_json(const phydat_t *data, size_t dim, char *buf)
buf[pos++] = ',';
}
/* add unit */
memcpy(&buf[pos], "\"u\":\"", 5);
flash_memcpy(&buf[pos], TO_FLASH("\"u\":\""), 5);
pos += 5;
const char *u = phydat_unit_to_str_verbose(data->unit);
strcpy(&buf[pos], u);
pos += strlen(u);
pos += phydat_unit_write(&buf[pos], SIZE_MAX, data->unit);
/* terminate the JSON string */
memcpy(&buf[pos], "\"}", 2);
flash_memcpy(&buf[pos], TO_FLASH("\"}"), 2);
pos += 2;
buf[pos++] = '\0';
}

View File

@ -18,17 +18,19 @@
* @}
*/
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include "assert.h"
#include "flash_utils.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");
printf("Unable to display data object\n");
return;
}
printf("Data:");
@ -50,19 +52,19 @@ void phydat_dump(phydat_t *data, uint8_t dim)
char scale_prefix;
switch (data->unit) {
case UNIT_UNDEF:
case UNIT_NONE:
case UNIT_M2:
case UNIT_M3:
case UNIT_PERCENT:
case UNIT_TEMP_C:
case UNIT_TEMP_F:
case UNIT_DBM:
/* no string conversion */
scale_prefix = '\0';
break;
default:
scale_prefix = phydat_prefix_from_scale(data->scale);
case UNIT_UNDEF:
case UNIT_NONE:
case UNIT_M2:
case UNIT_M3:
case UNIT_PERCENT:
case UNIT_TEMP_C:
case UNIT_TEMP_F:
case UNIT_DBM:
/* no string conversion */
scale_prefix = '\0';
break;
default:
scale_prefix = phydat_prefix_from_scale(data->scale);
}
printf("\t");
@ -92,75 +94,158 @@ void phydat_dump(phydat_t *data, uint8_t dim)
printf("%11s ", num);
}
printf("%s\n", phydat_unit_to_str(data->unit));
if ((data->unit != UNIT_NONE) && (data->unit != UNIT_UNDEF)
&& (data->unit != UNIT_BOOL)) {
phydat_unit_print(data->unit);
}
puts("");
}
}
static FLASH_ATTR const char _unit_celsius[] = "°C";
static FLASH_ATTR const char _unit_fahrenheit[] = "°F";
static FLASH_ATTR const char _unit_kelvin[] = "K";
static FLASH_ATTR const char _unit_lux[] = "lx";
static FLASH_ATTR const char _unit_metre[] = "m";
static FLASH_ATTR const char _unit_square_metre[] = "m^2";
static FLASH_ATTR const char _unit_cubic_metre[] = "m^3";
static FLASH_ATTR const char _unit_g_force[] = "gₙ";
static FLASH_ATTR const char _unit_degree_per_second[] = "dps";
static FLASH_ATTR const char _unit_gram[] = "g";
static FLASH_ATTR const char _unit_ampere[] = "A";
static FLASH_ATTR const char _unit_volt[] = "V";
static FLASH_ATTR const char _unit_watt[] = "W";
static FLASH_ATTR const char _unit_decibel_milliwatts[] = "dBm";
static FLASH_ATTR const char _unit_gauss[] = "Gs";
static FLASH_ATTR const char _unit_tesla[] = "T";
static FLASH_ATTR const char _unit_bar[] = "Bar";
static FLASH_ATTR const char _unit_pascal[] = "Pa";
static FLASH_ATTR const char _unit_permille[] = "permille";
static FLASH_ATTR const char _unit_parts_per_million[] = "ppm";
static FLASH_ATTR const char _unit_parts_per_billion[] = "ppb";
static FLASH_ATTR const char _unit_candela[] = "cd";
static FLASH_ATTR const char _unit_percent[] = "%";
static FLASH_ATTR const char _unit_counts[] = "cts";
static FLASH_ATTR const char _unit_coulomb[] = "C";
static FLASH_ATTR const char _unit_gram_per_cubic_metre[] = "g/m^3";
static FLASH_ATTR const char _unit_farad[] = "F";
static FLASH_ATTR const char _unit_potential_of_hydrogen[] = "pH";
static FLASH_ATTR const char _unit_count_per_cubic_metre[] = "#/m^3";
static FLASH_ATTR const char _unit_ohm[] = "ohm";
static FLASH_ATTR const char _unit_undefined[] = "undefined";
static FLASH_ATTR const char _unit_none[] = "none";
static FLASH_ATTR const char _unit_time[] = "time";
static FLASH_ATTR const char _unit_date[] = "date";
static FLASH_ATTR const char * FLASH_ATTR const _unit_to_str[] = {
[UNIT_TEMP_C] = _unit_celsius,
[UNIT_TEMP_F] = _unit_fahrenheit,
[UNIT_TEMP_K] = _unit_kelvin,
[UNIT_LUX] = _unit_lux,
[UNIT_M] = _unit_metre,
[UNIT_M2] = _unit_square_metre,
[UNIT_M3] = _unit_cubic_metre,
[UNIT_G_FORCE] = _unit_g_force,
[UNIT_DPS] = _unit_degree_per_second,
[UNIT_GRAM] = _unit_gram,
[UNIT_A] = _unit_ampere,
[UNIT_V] = _unit_volt,
[UNIT_W] = _unit_watt,
[UNIT_DBM] = _unit_decibel_milliwatts,
[UNIT_GS] = _unit_gauss,
[UNIT_T] = _unit_tesla,
[UNIT_BAR] = _unit_bar,
[UNIT_PA] = _unit_pascal,
[UNIT_PERMILL] = _unit_permille,
[UNIT_PPM] = _unit_parts_per_million,
[UNIT_PPB] = _unit_parts_per_billion,
[UNIT_CD] = _unit_candela,
[UNIT_PERCENT] = _unit_percent,
[UNIT_CTS] = _unit_counts,
[UNIT_COULOMB] = _unit_coulomb,
[UNIT_GPM3] = _unit_gram_per_cubic_metre,
[UNIT_F] = _unit_farad,
[UNIT_PH] = _unit_potential_of_hydrogen,
[UNIT_CPM3] = _unit_count_per_cubic_metre,
[UNIT_OHM] = _unit_ohm,
[UNIT_UNDEF] = _unit_undefined,
[UNIT_NONE] = _unit_none,
[UNIT_BOOL] = _unit_none,
[UNIT_TIME] = _unit_time,
[UNIT_DATE] = _unit_date,
};
ssize_t phydat_unit_write(char *dest, size_t max_size, uint8_t unit)
{
if ((unit >= ARRAY_SIZE(_unit_to_str)) || (_unit_to_str[unit]) == NULL) {
return -EINVAL;
}
size_t len = flash_strlen(_unit_to_str[unit]);
if (dest) {
if (max_size < len) {
return -EOVERFLOW;
}
flash_memcpy(dest, _unit_to_str[unit], len);
}
return len;
}
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_LUX: return "lx";
case UNIT_M: return "m";
case UNIT_M2: return "m^2";
case UNIT_M3: return "m^3";
case UNIT_G_FORCE: return "gₙ";
case UNIT_DPS: return "dps";
case UNIT_GRAM: return "g";
case UNIT_A: return "A";
case UNIT_V: return "V";
case UNIT_W: return "W";
case UNIT_DBM: return "dBm";
case UNIT_GAUSS: return "Gs";
case UNIT_T: return "T";
case UNIT_BAR: return "Bar";
case UNIT_PA: return "Pa";
case UNIT_PERMILL: return "permille";
case UNIT_PPM: return "ppm";
case UNIT_PPB: return "ppb";
case UNIT_CD: return "cd";
case UNIT_PERCENT: return "%";
case UNIT_CTS: return "cts";
case UNIT_COULOMB: return "C";
case UNIT_GPM3: return "g/m^3";
case UNIT_F: return "F";
case UNIT_PH: return "pH";
case UNIT_CPM3: return "#/m^3";
case UNIT_OHM: return "ohm";
default: return "";
#if IS_ACTIVE(HAS_FLASH_UTILS_ARCH)
/* Yeah, this is as bad as it looks... The function is deprecated for this
* reason and it will only affect AVR users, for whom this is a good
* trade-off. */
static char buf[8];
ssize_t pos = phydat_unit_write(buf, sizeof(buf) - 1, unit);
assert(pos >= 0);
if (pos < 0) {
pos = 0;
}
buf[pos] = '\0';
return buf;
#else
if ((unit < ARRAY_SIZE(_unit_to_str)) && (_unit_to_str[unit])) {
return _unit_to_str[unit];
}
return "";
#endif
}
const char *phydat_unit_to_str_verbose(uint8_t unit)
{
switch (unit) {
case UNIT_UNDEF: return "undefined";
case UNIT_NONE: /* fall through */
case UNIT_BOOL:
return "none";
case UNIT_TIME: return "time";
case UNIT_DATE: return "date";
default: return phydat_unit_to_str(unit);
return phydat_unit_to_str(unit);
}
void phydat_unit_print(uint8_t unit)
{
if ((unit < ARRAY_SIZE(_unit_to_str)) && (_unit_to_str[unit]) != NULL) {
flash_print_str(_unit_to_str[unit]);
}
}
char phydat_prefix_from_scale(int8_t scale)
{
switch (scale) {
case -3: return 'm';
case -6: return 'u';
case -9: return 'n';
case -12: return 'p';
case -15: return 'f';
case 2: return 'h';
case 3: return 'k';
case 6: return 'M';
case 9: return 'G';
case 12: return 'T';
case 15: return 'P';
default: return '\0';
static FLASH_ATTR const char _prefix[] = {
'f', '\0', '\0',
'p', '\0', '\0',
'n', '\0', '\0',
'u', '\0', '\0',
'm', '\0', '\0',
'\0', '\0', 'h',
'k', '\0', '\0',
'M', '\0', '\0',
'G', '\0', '\0',
'T', '\0', '\0',
'P',
};
int8_t idx = scale + ARRAY_SIZE(_prefix) / 2;
if ((idx < 0) || (idx >= (int8_t)ARRAY_SIZE(_prefix))) {
return '\0';
}
return _prefix[idx];
}

View File

@ -23,6 +23,7 @@
#include <math.h>
#include "embUnit.h"
#include "flash_utils.h"
#include "senml/phydat.h"
#define ENABLE_DEBUG (0)
@ -114,7 +115,7 @@ void test_phydat_to_senml_float(void)
phydat_to_senml_float(&res, &(value_tests[i].phydat), value_tests[i].dim);
DEBUG("Float: %" PRIi16 "e%" PRIi16 " %s -> %.f %s\n",
DEBUG("Float: %" PRIi16 "e%" PRIi16 " %" PRIsflash " -> %.f %s\n",
value_tests[i].phydat.val[value_tests[i].dim], value_tests[i].phydat.scale,
phydat_unit_to_str(value_tests[i].phydat.unit),
res.value.value.f,
@ -137,7 +138,7 @@ void test_phydat_to_senml_decimal(void)
phydat_to_senml_decimal(&res, &(value_tests[i].phydat), value_tests[i].dim);
DEBUG("Decimal: %" PRIi16 "e%" PRIi16 " %s -> %" PRIi32 "e%" PRIi32 " %s\n",
DEBUG("Decimal: %" PRIi16 "e%" PRIi16 " %s -> %" PRIi32 "e%" PRIi32 " %" PRIsflash"\n",
value_tests[i].phydat.val[value_tests[i].dim], value_tests[i].phydat.scale,
phydat_unit_to_str(value_tests[i].phydat.unit),
res.value.value.df.m, res.value.value.df.e,