From 91bca8899c30ffe7c0ef41778d6c9e957446bb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81yszczek?= Date: Sun, 24 Apr 2022 11:00:01 +0200 Subject: [PATCH] mosquitto_sub: add support to print floats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for two new format specifiers (%f and %d) to print float and double data. Generally it's not save to directly take native binary data of one machine and print it on another one (since mosquitto is multiarch). But in case of floats it's save to print representation of it, if __STDC_IEC_559__ is defined. In C99 Annex F, standard we can read: > This annex specifies C language support for the > IEC 60559 floating-point standard. > (...) > An implementation that defines __STDC_IEC_559__ > shall conform to the specifications in this annex All float printing code is behind __STDC_IEC_559__, so if that is not defined, floating print will be disabled and error returned to user. Documentation also describes restrictions about printing floats. Signed-off-by: Michał Łyszczek --- client/client_shared.c | 6 +++++ client/sub_client_output.c | 50 ++++++++++++++++++++++++++++++++++++++ man/mosquitto_sub.1.xml | 30 ++++++++++++++++++++--- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/client/client_shared.c b/client/client_shared.c index 852fb7c0..2988b0d1 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -140,6 +140,12 @@ static int check_format(const char *str) #endif }else if(str[i+1] == 'x' || str[i+1] == 'X'){ /* payload in hex */ + }else if(str[i+1] == 'f' || str[i+1] == 'd'){ + /* payload in float */ +#ifndef __STDC_IEC_559__ + fprintf(stderr, "Error: Can't print float, missing __STDC_IEC_559__ standard support.\n"); + return 1; +#endif }else{ fprintf(stderr, "Error: Invalid format specifier '%c'.\n", str[i+1]); return 1; diff --git a/client/sub_client_output.c b/client/sub_client_output.c index ecda4236..a749caaf 100644 --- a/client/sub_client_output.c +++ b/client/sub_client_output.c @@ -422,6 +422,42 @@ static void formatted_print_blank(char pad, int field_width) } +#ifdef __STDC_IEC_559__ +static int formatted_print_float(const unsigned char *payload, int payloadlen, char format, char align, char pad, int field_width, int precision) +{ + float float_value; + double value; + if (format == 'f'){ + if (sizeof(float_value) != payloadlen) { + return -1; + } + memcpy(&float_value, payload, sizeof(float_value)); + value = float_value; + }else if(format == 'd'){ + if (sizeof(value) != payloadlen) { + return -1; + } + memcpy(&value, payload, sizeof(value)); + } + + if(field_width == 0) { + printf("%.*f", precision, value); + }else{ + if(align == '-'){ + printf("%-*.*f", field_width, precision, value); + }else{ + if(pad == '0'){ + printf("%0*.*f", field_width, precision, value); + }else{ + printf("%*.*f", field_width, precision, value); + } + } + } + return 0; +} +#endif + + static void formatted_print_int(int value, char align, char pad, int field_width) { if(field_width == 0){ @@ -651,6 +687,20 @@ static void formatted_print_percent(const struct mosq_config *lcfg, const struct case 'X': write_payload(message->payload, message->payloadlen, 2, align, pad, field_width, precision); break; + +#ifdef __STDC_IEC_559__ + case 'f': + if(formatted_print_float(message->payload, message->payloadlen, 'f', align, pad, field_width, precision)) { + err_printf(lcfg, "requested float printing, but non-float data received"); + } + break; + + case 'd': + if(formatted_print_float(message->payload, message->payloadlen, 'd', align, pad, field_width, precision)) { + err_printf(lcfg, "requested double printing, but non-double data received"); + } + break; +#endif } } diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index b4fd2260..4ce52123 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -927,12 +927,12 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained Flag characters - The parameters %A, %C, %E, %F, %I, %l, %m, %p, %R, %S, %t, %x, and %X can have optional flags immediately after the % character. + The parameters %A, %C, %E, %F, %I, %l, %m, %p, %R, %S, %t, %f, %d, %x, and %X can have optional flags immediately after the % character. The value should be zero padded. - This applies to the parameters %A, %E, %F, %l, %m, %S, %X, and %x. + This applies to the parameters %A, %E, %F, %l, %m, %S, %f, %d, %X, and %x. It will be ignored for other parameters. If used with the flag, the flag will be ignored. @@ -954,7 +954,7 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained option to set their field width in a similar way to regular printf style formats, i.e. this sets the minimum width when printing this parameter. This applies to the options %A, %C, - %E, %F, %I, %l, %m, %p, %R, %S, %t, %x, %X. + %E, %F, %I, %l, %m, %p, %R, %S, %t, %f, %d, %x, %X. For example would set the minimum topic @@ -977,6 +977,28 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained + + Floating point number printing consideration + + Mosquitto supports only IEEE754 floating point standard as + described in Annex F of ISO/IEC 9899:1999. Don't try to + use %f or %d if publisher's platform uses different + floating point representation standard than IEEE754 or you + will get invalid data. If you are unsure what floating + representation your platform is using, then it's most + likely IEEE754. If you get malformed and unexpected values, + check if float number in payload from publisher is encoded + in IEEE754. + + + If want to print floats, make sure you subscribe only + to topics that send only IEEE754 formatted floats. + Mosquitto is very strict about floats and if anything + that is not float is received, an error message will + be printed. + + + MQTT related parameters @@ -1000,6 +1022,8 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained the message topic. the payload with each byte as a hexadecimal number (lower case). the payload with each byte as a hexadecimal number (upper case). + the payload is treated as 4byte IEEE754 float. + the payload is treated as 8byte IEEE754 float (double).