Skip to content

Commit 20a4d18

Browse files
rluboscfriedt
authored andcommitted
net: lwm2m: Fix plain text floating point handling
Floating point parser for plain text format was parsing floats wrongly, ignoring leading zeros after decimal points. Fix this, by reusing atof32() function, already avaialbe in a different part of the engine, which did the parsing correctly. Signed-off-by: Robert Lubos <[email protected]>
1 parent b6f69a6 commit 20a4d18

File tree

4 files changed

+95
-71
lines changed

4 files changed

+95
-71
lines changed

subsys/net/lib/lwm2m/lwm2m_engine.c

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
4343
#include "lwm2m_rw_link_format.h"
4444
#include "lwm2m_rw_plain_text.h"
4545
#include "lwm2m_rw_oma_tlv.h"
46+
#include "lwm2m_util.h"
4647
#ifdef CONFIG_LWM2M_RW_JSON_SUPPORT
4748
#include "lwm2m_rw_json.h"
4849
#endif
@@ -829,50 +830,6 @@ static uint16_t atou16(uint8_t *buf, uint16_t buflen, uint16_t *len)
829830
return val;
830831
}
831832

832-
static int atof32(const char *input, float32_value_t *out)
833-
{
834-
char *pos, *end, buf[24];
835-
long int val;
836-
int32_t base = 1000000, sign = 1;
837-
838-
if (!input || !out) {
839-
return -EINVAL;
840-
}
841-
842-
strncpy(buf, input, sizeof(buf) - 1);
843-
buf[sizeof(buf) - 1] = '\0';
844-
845-
if (strchr(buf, '-')) {
846-
sign = -1;
847-
}
848-
849-
pos = strchr(buf, '.');
850-
if (pos) {
851-
*pos = '\0';
852-
}
853-
854-
errno = 0;
855-
val = strtol(buf, &end, 10);
856-
if (errno || *end || val < INT_MIN) {
857-
return -EINVAL;
858-
}
859-
860-
out->val1 = (int32_t) val;
861-
out->val2 = 0;
862-
863-
if (!pos) {
864-
return 0;
865-
}
866-
867-
while (*(++pos) && base > 1 && isdigit((unsigned char)*pos)) {
868-
out->val2 = out->val2 * 10 + (*pos - '0');
869-
base /= 10;
870-
}
871-
872-
out->val2 *= sign * base;
873-
return !*pos || base == 1 ? 0 : -EINVAL;
874-
}
875-
876833
static int coap_options_to_path(struct coap_option *opt, int options_count,
877834
struct lwm2m_obj_path *path)
878835
{
@@ -2831,7 +2788,7 @@ static int lwm2m_write_attr_handler(struct lwm2m_engine_obj *obj,
28312788
val.val1 = v;
28322789
} else {
28332790
/* gt/lt/st: type float */
2834-
ret = atof32(opt_buf, &val);
2791+
ret = lwm2m_atof32(opt_buf, &val);
28352792
}
28362793

28372794
if (ret < 0) {

subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
7171
#include "lwm2m_object.h"
7272
#include "lwm2m_rw_plain_text.h"
7373
#include "lwm2m_engine.h"
74+
#include "lwm2m_util.h"
7475

7576
/* some temporary buffer space for format conversions */
7677
static char pt_buffer[42]; /* can handle float64 format */
@@ -176,22 +177,15 @@ static size_t put_objlnk(struct lwm2m_output_context *out,
176177
value->obj_inst);
177178
}
178179

179-
static size_t plain_text_read_number(struct lwm2m_input_context *in,
180-
int64_t *value1,
181-
int64_t *value2,
182-
bool accept_sign, bool accept_dot)
180+
static size_t plain_text_read_int(struct lwm2m_input_context *in,
181+
int64_t *value, bool accept_sign)
183182
{
184-
int64_t *counter = value1;
185183
int i = 0;
186184
bool neg = false;
187-
bool dot_found = false;
188185
uint8_t tmp;
189186

190187
/* initialize values to 0 */
191-
*value1 = 0;
192-
if (value2) {
193-
*value2 = 0;
194-
}
188+
*value = 0;
195189

196190
while (in->offset < in->in_cpkt->offset) {
197191
if (buf_read_u8(&tmp, CPKT_BUF_READ(in->in_cpkt),
@@ -201,12 +195,8 @@ static size_t plain_text_read_number(struct lwm2m_input_context *in,
201195

202196
if (tmp == '-' && accept_sign && i == 0) {
203197
neg = true;
204-
} else if (tmp == '.' && i > 0 && accept_dot && !dot_found &&
205-
value2) {
206-
dot_found = true;
207-
counter = value2;
208198
} else if (isdigit(tmp)) {
209-
*counter = *counter * 10 + (tmp - '0');
199+
*value = *value * 10 + (tmp - '0');
210200
} else {
211201
/* anything else stop reading */
212202
in->offset--;
@@ -217,7 +207,7 @@ static size_t plain_text_read_number(struct lwm2m_input_context *in,
217207
}
218208

219209
if (neg) {
220-
*value1 = -*value1;
210+
*value = -*value;
221211
}
222212

223213
return i;
@@ -228,7 +218,7 @@ static size_t get_s32(struct lwm2m_input_context *in, int32_t *value)
228218
int64_t tmp = 0;
229219
size_t len = 0;
230220

231-
len = plain_text_read_number(in, &tmp, NULL, true, false);
221+
len = plain_text_read_int(in, &tmp, true);
232222
if (len > 0) {
233223
*value = (int32_t)tmp;
234224
}
@@ -238,7 +228,7 @@ static size_t get_s32(struct lwm2m_input_context *in, int32_t *value)
238228

239229
static size_t get_s64(struct lwm2m_input_context *in, int64_t *value)
240230
{
241-
return plain_text_read_number(in, value, NULL, true, false);
231+
return plain_text_read_int(in, value, true);
242232
}
243233

244234
static size_t get_string(struct lwm2m_input_context *in,
@@ -266,13 +256,42 @@ static size_t get_string(struct lwm2m_input_context *in,
266256
static size_t get_float32fix(struct lwm2m_input_context *in,
267257
float32_value_t *value)
268258
{
269-
int64_t tmp1, tmp2;
270-
size_t len = 0;
259+
size_t i = 0, len = 0;
260+
bool has_dot = false;
261+
uint8_t tmp, buf[24];
271262

272-
len = plain_text_read_number(in, &tmp1, &tmp2, true, true);
273-
if (len > 0) {
274-
value->val1 = (int32_t)tmp1;
275-
value->val2 = (int32_t)tmp2;
263+
264+
while (in->offset < in->in_cpkt->offset) {
265+
if (buf_read_u8(&tmp, CPKT_BUF_READ(in->in_cpkt),
266+
&in->offset) < 0) {
267+
break;
268+
}
269+
270+
if ((tmp == '-' && i == 0) || (tmp == '.' && !has_dot) ||
271+
isdigit(tmp)) {
272+
len++;
273+
274+
/* Copy only if it fits into provided buffer - we won't
275+
* get better precision anyway.
276+
*/
277+
if (i < sizeof(buf) - 1) {
278+
buf[i++] = tmp;
279+
}
280+
281+
if (tmp == '.') {
282+
has_dot = true;
283+
}
284+
} else {
285+
/* anything else stop reading */
286+
in->offset--;
287+
break;
288+
}
289+
}
290+
291+
buf[i] = '\0';
292+
293+
if (lwm2m_atof32(buf, value) != 0) {
294+
LOG_ERR("Failed to parse float value");
276295
}
277296

278297
return len;
@@ -342,14 +361,14 @@ static size_t get_objlnk(struct lwm2m_input_context *in,
342361
int64_t tmp;
343362
size_t len;
344363

345-
len = plain_text_read_number(in, &tmp, NULL, false, false);
364+
len = plain_text_read_int(in, &tmp, false);
346365
value->obj_id = (uint16_t)tmp;
347366

348367
/* Skip ':' delimeter. */
349368
in->offset++;
350369
len++;
351370

352-
len += plain_text_read_number(in, &tmp, NULL, false, false);
371+
len += plain_text_read_int(in, &tmp, false);
353372
value->obj_inst = (uint16_t)tmp;
354373

355374
return len;

subsys/net/lib/lwm2m/lwm2m_util.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <kernel.h>
88
#include <stdlib.h>
9+
#include <ctype.h>
910
#include "lwm2m_util.h"
1011

1112
#define SHIFT_LEFT(v, o, m) (((v) << (o)) & (m))
@@ -296,3 +297,47 @@ int lwm2m_b64_to_f32(uint8_t *b64, size_t len, float32_value_t *f32)
296297

297298
return 0;
298299
}
300+
301+
int lwm2m_atof32(const char *input, float32_value_t *out)
302+
{
303+
char *pos, *end, buf[24];
304+
long val;
305+
int32_t base = LWM2M_FLOAT32_DEC_MAX, sign = 1;
306+
307+
if (!input || !out) {
308+
return -EINVAL;
309+
}
310+
311+
strncpy(buf, input, sizeof(buf) - 1);
312+
buf[sizeof(buf) - 1] = '\0';
313+
314+
if (strchr(buf, '-')) {
315+
sign = -1;
316+
}
317+
318+
pos = strchr(buf, '.');
319+
if (pos) {
320+
*pos = '\0';
321+
}
322+
323+
errno = 0;
324+
val = strtol(buf, &end, 10);
325+
if (errno || *end || val < INT_MIN) {
326+
return -EINVAL;
327+
}
328+
329+
out->val1 = (int32_t) val;
330+
out->val2 = 0;
331+
332+
if (!pos) {
333+
return 0;
334+
}
335+
336+
while (*(++pos) && base > 1 && isdigit((unsigned char)*pos)) {
337+
out->val2 = out->val2 * 10 + (*pos - '0');
338+
base /= 10;
339+
}
340+
341+
out->val2 *= sign * base;
342+
return !*pos || base == 1 ? 0 : -EINVAL;
343+
}

subsys/net/lib/lwm2m/lwm2m_util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ int lwm2m_f32_to_b64(float32_value_t *f32, uint8_t *b64, size_t len);
1717
int lwm2m_b32_to_f32(uint8_t *b32, size_t len, float32_value_t *f32);
1818
int lwm2m_b64_to_f32(uint8_t *b64, size_t len, float32_value_t *f32);
1919

20+
/* convert string to float struct */
21+
int lwm2m_atof32(const char *input, float32_value_t *out);
22+
2023
#endif /* LWM2M_UTIL_H_ */

0 commit comments

Comments
 (0)