From cdcec5b3f9824d111bfb668df2902f43db41a780 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 1 Jun 2022 22:59:07 +0200 Subject: [PATCH] drivers/saul: use flash_utils --- drivers/include/saul.h | 38 +++++- drivers/saul/saul_str.c | 239 ++++++++++++++++++++++++++++--------- sys/shell/cmds/saul_reg.c | 30 +++-- tests/driver_bmx055/main.c | 5 +- tests/saul/main.c | 5 +- 5 files changed, 242 insertions(+), 75 deletions(-) diff --git a/drivers/include/saul.h b/drivers/include/saul.h index e8d73bc68f..d72b6c2464 100644 --- a/drivers/include/saul.h +++ b/drivers/include/saul.h @@ -48,8 +48,9 @@ #ifndef SAUL_H #define SAUL_H -#include #include +#include +#include #include "phydat.h" @@ -315,11 +316,42 @@ int saul_read_notsup(const void *dev, phydat_t *dat); * * @param[in] class_id device class ID * - * @return string representation of the device class - * @return NULL if class ID is not known + * @return string representation of the device class + * @retval NULL class ID is not known + * + * @deprecated Use @ref saul_class_print or @ref saul_class_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 *saul_class_to_str(const uint8_t class_id); +/** + * @brief Prints the class string of the given class ID + * + * @param[in] class_id ID of the device class to print + */ +void saul_class_print(uint8_t class_id); + +/** + * @brief Write the string representation of the given device class to the + * given buffer + * + * @param[out] dest destination buffer to write to + * @param[in] max_size size of the buffer at @p dest + * @param[in] class_id ID of the device class to write + * + * @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 saul_class_write(char *dest, size_t max_size, uint8_t class_id); + #ifdef __cplusplus } #endif diff --git a/drivers/saul/saul_str.c b/drivers/saul/saul_str.c index 354e302f99..d9ea6abe91 100644 --- a/drivers/saul/saul_str.c +++ b/drivers/saul/saul_str.c @@ -23,77 +23,206 @@ #include #include +#include "flash_utils.h" #include "saul.h" -static const char *actuators[] = { - [SAUL_ACT_ID_ANY] = "ACT_ANY", - [SAUL_ACT_ID_LED_RGB] = "ACT_LED_RGB", - [SAUL_ACT_ID_SERVO] = "ACT_SERVO", - [SAUL_ACT_ID_MOTOR] = "ACT_MOTOR", - [SAUL_ACT_ID_SWITCH] = "ACT_SWITCH", - [SAUL_ACT_ID_DIMMER] = "ACT_DIMMER", +static FLASH_ATTR const char _act_id_any[] = "ACT_ANY"; +static FLASH_ATTR const char _act_id_led_rgb[] = "ACT_LED_RGB"; +static FLASH_ATTR const char _act_id_servo[] = "ACT_SERVO"; +static FLASH_ATTR const char _act_id_motor[] = "ACT_MOTOR"; +static FLASH_ATTR const char _act_id_switch[] = "ACT_SWITCH"; +static FLASH_ATTR const char _act_id_dimmer[] = "ACT_DIMMER"; + +static FLASH_ATTR const char * FLASH_ATTR const actuators[] = { + [SAUL_ACT_ID_ANY] = _act_id_any, + [SAUL_ACT_ID_LED_RGB] = _act_id_led_rgb, + [SAUL_ACT_ID_SERVO] = _act_id_servo, + [SAUL_ACT_ID_MOTOR] = _act_id_motor, + [SAUL_ACT_ID_SWITCH] = _act_id_switch, + [SAUL_ACT_ID_DIMMER] = _act_id_dimmer, }; -static const char *sensors[] = { - [SAUL_SENSE_ID_ANY] = "SENSE_ANY", - [SAUL_SENSE_ID_BTN] = "SENSE_BTN", - [SAUL_SENSE_ID_TEMP] = "SENSE_TEMP", - [SAUL_SENSE_ID_HUM] = "SENSE_HUM", - [SAUL_SENSE_ID_LIGHT] = "SENSE_LIGHT", - [SAUL_SENSE_ID_ACCEL] = "SENSE_ACCEL", - [SAUL_SENSE_ID_MAG] = "SENSE_MAG", - [SAUL_SENSE_ID_GYRO] = "SENSE_GYRO", - [SAUL_SENSE_ID_COLOR] = "SENSE_COLOR", - [SAUL_SENSE_ID_PRESS] = "SENSE_PRESS", - [SAUL_SENSE_ID_ANALOG] = "SENSE_ANALOG", - [SAUL_SENSE_ID_UV] = "SENSE_UV", - [SAUL_SENSE_ID_OBJTEMP] = "SENSE_OBJTEMP", - [SAUL_SENSE_ID_COUNT] = "SENSE_PULSE_COUNT", - [SAUL_SENSE_ID_DISTANCE] = "SENSE_DISTANCE", - [SAUL_SENSE_ID_CO2] = "SENSE_CO2", - [SAUL_SENSE_ID_TVOC] = "SENSE_TVOC", - [SAUL_SENSE_ID_GAS] = "SENSE_GAS", - [SAUL_SENSE_ID_PROXIMITY] = "SENSE_PROXIMITY", - [SAUL_SENSE_ID_RSSI] = "SENSE_RSSI", - [SAUL_SENSE_ID_CHARGE] = "SENSE_CHARGE", - [SAUL_SENSE_ID_CURRENT] = "SENSE_CURRENT", - [SAUL_SENSE_ID_OCCUP] = "SENSE_OCCUP", - [SAUL_SENSE_ID_PM] = "SENSE_PM", - [SAUL_SENSE_ID_CAPACITANCE] = "SENSE_CAPACITANCE", - [SAUL_SENSE_ID_VOLTAGE] = "SENSE_VOLTAGE", - [SAUL_SENSE_ID_PH] = "SENSE_PH", - [SAUL_SENSE_ID_POWER] = "SENSE_POWER", - [SAUL_SENSE_ID_SIZE] = "SENSE_SIZE", +static FLASH_ATTR const char _sense_any[] = "SENSE_ANY"; +static FLASH_ATTR const char _sense_btn[] = "SENSE_BTN"; +static FLASH_ATTR const char _sense_temp[] = "SENSE_TEMP"; +static FLASH_ATTR const char _sense_hum[] = "SENSE_HUM"; +static FLASH_ATTR const char _sense_light[] = "SENSE_LIGHT"; +static FLASH_ATTR const char _sense_accel[] = "SENSE_ACCEL"; +static FLASH_ATTR const char _sense_mag[] = "SENSE_MAG"; +static FLASH_ATTR const char _sense_gyro[] = "SENSE_GYRO"; +static FLASH_ATTR const char _sense_color[] = "SENSE_COLOR"; +static FLASH_ATTR const char _sense_press[] = "SENSE_PRESS"; +static FLASH_ATTR const char _sense_analog[] = "SENSE_ANALOG"; +static FLASH_ATTR const char _sense_uv[] = "SENSE_UV"; +static FLASH_ATTR const char _sense_objtemp[] = "SENSE_OBJTEMP"; +static FLASH_ATTR const char _sense_pulse_count[] = "SENSE_PULSE_COUNT"; +static FLASH_ATTR const char _sense_distance[] = "SENSE_DISTANCE"; +static FLASH_ATTR const char _sense_co2[] = "SENSE_CO2"; +static FLASH_ATTR const char _sense_tvoc[] = "SENSE_TVOC"; +static FLASH_ATTR const char _sense_gas[] = "SENSE_GAS"; +static FLASH_ATTR const char _sense_proximity[] = "SENSE_PROXIMITY"; +static FLASH_ATTR const char _sense_rssi[] = "SENSE_RSSI"; +static FLASH_ATTR const char _sense_charge[] = "SENSE_CHARGE"; +static FLASH_ATTR const char _sense_current[] = "SENSE_CURRENT"; +static FLASH_ATTR const char _sense_occup[] = "SENSE_OCCUP"; +static FLASH_ATTR const char _sense_pm[] = "SENSE_PM"; +static FLASH_ATTR const char _sense_capacitance[] = "SENSE_CAPACITANCE"; +static FLASH_ATTR const char _sense_voltage[] = "SENSE_VOLTAGE"; +static FLASH_ATTR const char _sense_ph[] = "SENSE_PH"; +static FLASH_ATTR const char _sense_power[] = "SENSE_POWER"; +static FLASH_ATTR const char _sense_size[] = "SENSE_SIZE"; + +static FLASH_ATTR const char * FLASH_ATTR const sensors[] = { + [SAUL_SENSE_ID_ANY] = _sense_any, + [SAUL_SENSE_ID_BTN] = _sense_btn, + [SAUL_SENSE_ID_TEMP] = _sense_temp, + [SAUL_SENSE_ID_HUM] = _sense_hum, + [SAUL_SENSE_ID_LIGHT] = _sense_light, + [SAUL_SENSE_ID_ACCEL] = _sense_accel, + [SAUL_SENSE_ID_MAG] = _sense_mag, + [SAUL_SENSE_ID_GYRO] = _sense_gyro, + [SAUL_SENSE_ID_COLOR] = _sense_color, + [SAUL_SENSE_ID_PRESS] = _sense_press, + [SAUL_SENSE_ID_ANALOG] = _sense_analog, + [SAUL_SENSE_ID_UV] = _sense_uv, + [SAUL_SENSE_ID_OBJTEMP] = _sense_objtemp, + [SAUL_SENSE_ID_COUNT] = _sense_pulse_count, + [SAUL_SENSE_ID_DISTANCE] = _sense_distance, + [SAUL_SENSE_ID_CO2] = _sense_co2, + [SAUL_SENSE_ID_TVOC] = _sense_tvoc, + [SAUL_SENSE_ID_GAS] = _sense_gas, + [SAUL_SENSE_ID_PROXIMITY] = _sense_proximity, + [SAUL_SENSE_ID_RSSI] = _sense_rssi, + [SAUL_SENSE_ID_CHARGE] = _sense_charge, + [SAUL_SENSE_ID_CURRENT] = _sense_current, + [SAUL_SENSE_ID_OCCUP] = _sense_occup, + [SAUL_SENSE_ID_PM] = _sense_pm, + [SAUL_SENSE_ID_CAPACITANCE] = _sense_capacitance, + [SAUL_SENSE_ID_VOLTAGE] = _sense_voltage, + [SAUL_SENSE_ID_PH] = _sense_ph, + [SAUL_SENSE_ID_POWER] = _sense_power, + [SAUL_SENSE_ID_SIZE] = _sense_size, }; +static FLASH_ATTR const char _class_undef[] = "CLASS_UNDEF"; +static FLASH_ATTR const char _class_any[] = "CLASS_ANY"; +static FLASH_ATTR const char _class_unknown[] = "CLASS_UNKNOWN"; + const char *saul_class_to_str(const uint8_t class_id) { +#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[32]; /* yes, whopping 32 byte ... */ + ssize_t len = saul_class_write(buf, sizeof(buf) - 1, class_id); + if (len < 0) { + flash_memcpy(buf, _class_unknown, sizeof(_class_unknown)); + len = sizeof(_class_unknown); + } + buf[len] = '\0'; + return buf; +#else const char *result = NULL; uint8_t id = class_id & SAUL_ID_MASK; uint8_t cat = class_id & SAUL_CAT_MASK; switch (cat) { - case SAUL_CAT_UNDEF: - return "CLASS_UNDEF"; - case SAUL_CAT_ACT: - if (id < SAUL_ACT_NUMOF) { - result = actuators[id]; - } - break; - case SAUL_CAT_SENSE: - if (id < SAUL_SENSE_NUMOF) { - result = sensors[id]; - } - break; - default: - if (class_id == SAUL_CLASS_ANY) { - return "CLASS_ANY"; - } - break; + case SAUL_CAT_UNDEF: + return _class_undef; + case SAUL_CAT_ACT: + if (id < SAUL_ACT_NUMOF) { + result = actuators[id]; + } + break; + case SAUL_CAT_SENSE: + if (id < SAUL_SENSE_NUMOF) { + result = sensors[id]; + } + break; + default: + if (class_id == SAUL_CLASS_ANY) { + return _class_any; + } + break; } if (result == NULL) { - result = "CLASS_UNKNOWN"; + result = _class_unknown; } return result; +#endif +} + +void saul_class_print(uint8_t class_id) +{ + uint8_t id = class_id & SAUL_ID_MASK; + uint8_t cat = class_id & SAUL_CAT_MASK; + FLASH_ATTR const char *str = NULL; + + switch (cat) { + case SAUL_CAT_UNDEF: + str = _class_undef; + break; + case SAUL_CAT_ACT: + if (id < SAUL_ACT_NUMOF) { + str = actuators[id]; + } + break; + case SAUL_CAT_SENSE: + if (id < SAUL_SENSE_NUMOF) { + str = sensors[id]; + } + break; + default: + if (class_id == SAUL_CLASS_ANY) { + str = _class_any; + } + break; + } + + if (str) { + flash_print_str(str); + } +} + +ssize_t saul_class_write(char *dest, size_t max_size, uint8_t class_id) +{ + uint8_t id = class_id & SAUL_ID_MASK; + uint8_t cat = class_id & SAUL_CAT_MASK; + FLASH_ATTR const char *str = NULL; + + switch (cat) { + case SAUL_CAT_UNDEF: + str = _class_undef; + break; + case SAUL_CAT_ACT: + if (id < SAUL_ACT_NUMOF) { + str = actuators[id]; + } + break; + case SAUL_CAT_SENSE: + if (id < SAUL_SENSE_NUMOF) { + str = sensors[id]; + } + break; + default: + if (class_id == SAUL_CLASS_ANY) { + str = _class_any; + } + break; + } + + if (!str) { + return -EINVAL; + } + size_t len = flash_strlen(str); + if (dest) { + if (len > max_size) { + return -EOVERFLOW; + } + flash_memcpy(dest, str, len); + } + + return len; } diff --git a/sys/shell/cmds/saul_reg.c b/sys/shell/cmds/saul_reg.c index b153eae6ae..f3e60046e5 100644 --- a/sys/shell/cmds/saul_reg.c +++ b/sys/shell/cmds/saul_reg.c @@ -24,6 +24,7 @@ #include #include +#include "flash_utils.h" #include "saul_reg.h" #include "shell.h" @@ -47,8 +48,9 @@ static void probe(int num, saul_reg_t *dev) return; } /* print results */ - printf("Reading from #%i (%s|%s)\n", num, _devname(dev), - saul_class_to_str(dev->driver->type)); + printf("Reading from #%i (%s|", num, _devname(dev)); + saul_class_print(dev->driver->type); + printf(")\n"); phydat_dump(&res, dim); } @@ -70,14 +72,15 @@ static void list(void) int i = 0; if (dev) { - puts("ID\tClass\t\tName"); + printf("ID\tClass\t\tName\n"); } else { - puts("No devices found"); + printf("No devices found\n"); } while (dev) { - printf("#%i\t%s\t%s\n", - i++, saul_class_to_str(dev->driver->type), _devname(dev)); + printf("#%i\t", i++); + saul_class_print(dev->driver->type); + printf("\t%s\n", _devname(dev)); dev = dev->next; } } @@ -88,10 +91,11 @@ static void read(int argc, char **argv) saul_reg_t *dev; if (argc < 3) { - printf("usage: %s %s |all\n", argv[0], argv[1]); + printf("usage: %s %s |all\n", + argv[0], argv[1]); return; } - if (strcmp(argv[2], "all") == 0) { + if (flash_strcmp(argv[2], TO_FLASH("all")) == 0) { probe_all(); return; } @@ -99,7 +103,7 @@ static void read(int argc, char **argv) num = atoi(argv[2]); dev = saul_reg_find_nth(num); if (dev == NULL) { - puts("error: undefined device id given"); + printf("error: undefined device id given\n"); return; } probe(num, dev); @@ -113,13 +117,13 @@ static void write(int argc, char **argv) if (argc < 4) { printf("usage: %s %s [ [ -#include "xtimer.h" +#include "flash_utils.h" #include "phydat.h" #include "saul_reg.h" +#include "xtimer.h" /** * @brief Read the sensors every second @@ -44,7 +45,7 @@ int main(void) while (dev) { int dim = saul_reg_read(dev, &res); - printf("\nDev: %s\tType: %s\n", dev->name, + printf("\nDev: %s\tType: %" PRIsflash "\n", dev->name, saul_class_to_str(dev->driver->type)); phydat_dump(&res, dim); dev = dev->next; diff --git a/tests/saul/main.c b/tests/saul/main.c index 1442f3197c..4695bc2967 100644 --- a/tests/saul/main.c +++ b/tests/saul/main.c @@ -19,9 +19,10 @@ #include -#include "xtimer.h" +#include "flash_utils.h" #include "phydat.h" #include "saul_reg.h" +#include "xtimer.h" /** * @brief Read th sensors every second @@ -45,7 +46,7 @@ int main(void) while (dev) { int dim = saul_reg_read(dev, &res); - printf("\nDev: %s\tType: %s\n", dev->name, + printf("\nDev: %s\tType: %" PRIsflash "\n", dev->name, saul_class_to_str(dev->driver->type)); phydat_dump(&res, dim); dev = dev->next;