ubloxcfg
u-blox 9 configuration helpers
Loading...
Searching...
No Matches
ubloxcfg.c
Go to the documentation of this file.
1/* ************************************************************************************************/ // clang-format off
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <inttypes.h>
26#include <ctype.h>
27
28// Passed in by cmake or loaded from file
29#if !defined(CONFIG_VERSION_MAJOR) || !defined(CONFIG_VERSION_MINOR)
30# include "config.h"
31#endif
32
33#include "ubloxcfg.h"
34
35/* ****************************************************************************************************************** */
36
37#if (defined(__STDC__) && (__STDC_VERSION__ < 199901L))
38# error This needs C99 or later!
39#endif
40
42{
43 if ( (name == NULL) || (strlen(name) < 2) )
44 {
45 return NULL;
46 }
47 const UBLOXCFG_ITEM_t *item = NULL;
48 // Find by hex string of the ID
49 if ( (name[0] == '0') && (name[1] == 'x') )
50 {
51 uint32_t id = 0;
52 int numChar = 0;
53 if ( (sscanf(name, "%"SCNx32"%n", &id, &numChar) == 1) && (numChar == (int)strlen(name)) )
54 {
55 item = ubloxcfg_getItemById(id);
56 }
57 }
58 // Find by name
59 else
60 {
61 const UBLOXCFG_ITEM_t **allItems = (const UBLOXCFG_ITEM_t **)_ubloxcfg_allItems();
62 for (int ix = 0; ix < _UBLOXCFG_NUM_ITEMS; ix++)
63 {
64 if (strcmp(allItems[ix]->name, name) == 0)
65 {
66 item = allItems[ix];
67 break;
68 }
69 }
70 }
71 return item;
72}
73
74const UBLOXCFG_ITEM_t *ubloxcfg_getItemById(const uint32_t id)
75{
76 const UBLOXCFG_ITEM_t *item = NULL;
77 const UBLOXCFG_ITEM_t **allItems = (const UBLOXCFG_ITEM_t **)_ubloxcfg_allItems();
78 for (int ix = 0; ix < _UBLOXCFG_NUM_ITEMS; ix++)
79 {
80 if (allItems[ix]->id == id)
81 {
82 item = allItems[ix];
83 break;
84 }
85 }
86 return item;
87}
88
90{
91 *num = _UBLOXCFG_NUM_ITEMS;
92 return (const UBLOXCFG_ITEM_t **)_ubloxcfg_allItems();
93}
94
95const UBLOXCFG_MSGRATE_t *ubloxcfg_getMsgRateCfg(const char *msgName)
96{
97 if (msgName == NULL)
98 {
99 return NULL;
100 }
101 const UBLOXCFG_MSGRATE_t *rates = NULL;
102 const UBLOXCFG_MSGRATE_t **allRates = (const UBLOXCFG_MSGRATE_t **)_ubloxcfg_allRates();
103 for (int ix = 0; ix < _UBLOXCFG_NUM_RATES; ix++)
104 {
105 if (strcmp(allRates[ix]->msgName, msgName) == 0)
106 {
107 rates = allRates[ix];
108 break;
109 }
110 }
111 return rates;
112}
113
115{
116 *num = _UBLOXCFG_NUM_RATES;
117 return (const UBLOXCFG_MSGRATE_t **)_ubloxcfg_allRates();
118}
119
120bool ubloxcfg_makeData(uint8_t *data, const int size, const UBLOXCFG_KEYVAL_t *keyVal, const int nKeyVal, int *dataSize)
121{
122 if ( (data == NULL) || (size <= 0) || (keyVal == NULL) || (nKeyVal < 1) || (dataSize == NULL) )
123 {
124 return false;
125 }
126
127 bool res = true;
128 int dataIx = 0;
129 memset(data, 0, size);
130
131 for (int kvIx = 0; res && (kvIx < nKeyVal); kvIx++)
132 {
133 // enough space for key?
134 if ( (size - dataIx) < 4 )
135 {
136 res = false;
137 break;
138 }
139
140 // encode key ID
141 const UBLOXCFG_KEYVAL_t *kv = &keyVal[kvIx];
142 const uint32_t key = kv->id;
143 data[dataIx++] = (key >> 0) & 0xff;
144 data[dataIx++] = (key >> 8) & 0xff;
145 data[dataIx++] = (key >> 16) & 0xff;
146 data[dataIx++] = (key >> 24) & 0xff;
147
148 // encode value, and also check that there's enough space left in data
149 const UBLOXCFG_SIZE_t valSize = UBLOXCFG_ID2SIZE(kv->id);
150 const UBLOXCFG_VALUE_t val = kv->val;
151 switch (valSize)
152 {
154 if ( (size - dataIx) < 1 )
155 {
156 res = false;
157 break;
158 }
159 data[dataIx++] = val._bytes[0];
160 break;
162 if ( (size - dataIx) < 1 )
163 {
164 res = false;
165 break;
166 }
167 data[dataIx++] = val._bytes[0];
168 break;
170 if ( (size - dataIx) < 2 )
171 {
172 res = false;
173 break;
174 }
175 data[dataIx++] = val._bytes[0];
176 data[dataIx++] = val._bytes[1];
177 break;
179 if ( (size - dataIx) < 4 )
180 {
181 res = false;
182 break;
183 }
184 data[dataIx++] = val._bytes[0];
185 data[dataIx++] = val._bytes[1];
186 data[dataIx++] = val._bytes[2];
187 data[dataIx++] = val._bytes[3];
188 break;
190 if ( (size - dataIx) < 8 )
191 {
192 res = false;
193 break;
194 }
195 data[dataIx++] = val._bytes[0];
196 data[dataIx++] = val._bytes[1];
197 data[dataIx++] = val._bytes[2];
198 data[dataIx++] = val._bytes[3];
199 data[dataIx++] = val._bytes[4];
200 data[dataIx++] = val._bytes[5];
201 data[dataIx++] = val._bytes[6];
202 data[dataIx++] = val._bytes[7];
203 break;
204 default:
205 res = false;
206 break;
207 }
208 }
209 *dataSize = dataIx;
210
211 return res;
212}
213
214bool ubloxcfg_parseData(const uint8_t *data, const int size, UBLOXCFG_KEYVAL_t *keyVal, const int maxKeyVal, int *nKeyVal)
215{
216 if ( (data == NULL) || (size <= 0) || (keyVal == NULL) || (maxKeyVal < 1) || (nKeyVal == NULL) )
217 {
218 return false;
219 }
220
221 bool res = true;
222 int kvIx = 0;
223 int dataIx = 0;
224 memset(keyVal, 0, maxKeyVal * sizeof(*keyVal));
225
226 while (res)
227 {
228 // next key?
229 if ( dataIx > (size - 4) )
230 {
231 break;
232 }
233 const uint8_t k0 = data[dataIx++];
234 const uint8_t k1 = data[dataIx++];
235 const uint8_t k2 = data[dataIx++];
236 const uint8_t k3 = data[dataIx++];
237 const uint32_t id = k0 | (k1 << 8) | (k2 << 16) | (k3 << 24);
238 const UBLOXCFG_SIZE_t valSize = UBLOXCFG_ID2SIZE(id);
240 val.U8 = 0;
241 switch (valSize)
242 {
244 if ( dataIx > (size - 1) )
245 {
246 res = false;
247 break;
248 }
249 else
250 {
251 val._bytes[0] = data[dataIx++];
252 }
253 break;
255 if ( dataIx > (size - 1) )
256 {
257 res = false;
258 break;
259 }
260 else
261 {
262 val._bytes[0] = data[dataIx++];
263 }
264 break;
266 if ( dataIx > (size - 1) )
267 {
268 res = false;
269 break;
270 }
271 else
272 {
273 val._bytes[0] = data[dataIx++];
274 val._bytes[1] = data[dataIx++];
275 }
276 break;
278 if ( dataIx > (size - 1) )
279 {
280 res = false;
281 break;
282 }
283 else
284 {
285 val._bytes[0] = data[dataIx++];
286 val._bytes[1] = data[dataIx++];
287 val._bytes[2] = data[dataIx++];
288 val._bytes[3] = data[dataIx++];
289 }
290 break;
292 if ( dataIx > (size - 1) )
293 {
294 res = false;
295 break;
296 }
297 else
298 {
299 val._bytes[0] = data[dataIx++];
300 val._bytes[1] = data[dataIx++];
301 val._bytes[2] = data[dataIx++];
302 val._bytes[3] = data[dataIx++];
303 val._bytes[4] = data[dataIx++];
304 val._bytes[5] = data[dataIx++];
305 val._bytes[6] = data[dataIx++];
306 val._bytes[7] = data[dataIx++];
307 }
308 break;
309 default:
310 res = false;
311 break;
312 }
313
314 if (res)
315 {
316 // enough space in list?
317 if (kvIx < maxKeyVal)
318 {
319 keyVal[kvIx].id = id;
320 keyVal[kvIx].val = val;
321 kvIx++;
322 }
323 // output list too short, abort
324 else
325 {
326 res = 0;
327 }
328 }
329 }
330
331 *nKeyVal = kvIx;
332
333 return res;
334}
335
337{
338 switch (type)
339 {
340 case UBLOXCFG_TYPE_U1: return "U1";
341 case UBLOXCFG_TYPE_U2: return "U2";
342 case UBLOXCFG_TYPE_U4: return "U4";
343 case UBLOXCFG_TYPE_U8: return "U8";
344 case UBLOXCFG_TYPE_I1: return "I1";
345 case UBLOXCFG_TYPE_I2: return "I2";
346 case UBLOXCFG_TYPE_I4: return "I4";
347 case UBLOXCFG_TYPE_I8: return "I8";
348 case UBLOXCFG_TYPE_X1: return "X1";
349 case UBLOXCFG_TYPE_X2: return "X2";
350 case UBLOXCFG_TYPE_X4: return "X4";
351 case UBLOXCFG_TYPE_X8: return "X8";
352 case UBLOXCFG_TYPE_R4: return "R4";
353 case UBLOXCFG_TYPE_R8: return "R8";
354 case UBLOXCFG_TYPE_E1: return "E1";
355 case UBLOXCFG_TYPE_E2: return "E2";
356 case UBLOXCFG_TYPE_E4: return "E4";
357 case UBLOXCFG_TYPE_L: return "L";
358 }
359 return NULL;
360}
361
362bool ubloxcfg_stringifyValue(char *str, const int size, const UBLOXCFG_TYPE_t type, const UBLOXCFG_ITEM_t *item, const UBLOXCFG_VALUE_t *val)
363{
364 if ( (str == NULL) || (size <= 0) || ((item != NULL) && (item->type != type)) )
365 {
366 return false;
367 }
368
369 str[0] = '\0';
370 bool res = false;
371
372 switch (type)
373 {
374 case UBLOXCFG_TYPE_U1:
375 if (size >= 4) // 0..255
376 {
377 snprintf(str, size, "%" PRIu8, val->U1);
378 res = true;
379 }
380 break;
381 case UBLOXCFG_TYPE_U2:
382 if (size >= 6) // 0..65535
383 {
384 snprintf(str, size, "%" PRIu16, val->U2);
385 res = true;
386 }
387 break;
388 case UBLOXCFG_TYPE_U4:
389 if (size >= 11) // 0..4294967295
390 {
391 snprintf(str, size, "%" PRIu32, val->U4);
392 res = true;
393 }
394 break;
395 case UBLOXCFG_TYPE_U8:
396 if (size >= 21) // 0..18446744073709551615
397 {
398 snprintf(str, size, "%" PRIu64, val->U8);
399 res = true;
400 }
401 break;
402 case UBLOXCFG_TYPE_I1:
403 if (size >= 5) // -128..127
404 {
405 snprintf(str, size, "%" PRIi8, val->I1);
406 res = true;
407 }
408 break;
409 case UBLOXCFG_TYPE_I2:
410 if (size >= 7) // -32768..32767
411 {
412 snprintf(str, size, "%" PRIi16, val->I2);
413 res = true;
414 }
415 break;
416 case UBLOXCFG_TYPE_I4:
417 if (size >= 12) // −2147483648..2147483647
418 {
419 snprintf(str, size, "%" PRIi32, val->I4);
420 res = true;
421 }
422 break;
423 case UBLOXCFG_TYPE_I8:
424 if (size >= 21) // -9223372036854775808..9223372036854775807
425 {
426 snprintf(str, size, "%" PRIi64, val->I8);
427 res = true;
428 }
429 break;
430 case UBLOXCFG_TYPE_X1:
431 case UBLOXCFG_TYPE_X2:
432 case UBLOXCFG_TYPE_X4:
433 case UBLOXCFG_TYPE_X8:
434 if (size >= (19 + 20)) // 0x00 (...) // 0x0000 (...) // 0x00000000 (...) // 0x0000000000000000 (...)
435 {
436 const char *fmt1 = NULL;
437 const char *fmt2 = NULL;
438 uint64_t valX = 0;
439 switch (type)
440 {
441 case UBLOXCFG_TYPE_X1: fmt1 = "0x%02" PRIx64 " "; fmt2 = "|0x%02" PRIx64; valX = val->X1; break;
442 case UBLOXCFG_TYPE_X2: fmt1 = "0x%04" PRIx64 " "; fmt2 = "|0x%04" PRIx64; valX = val->X2; break;
443 case UBLOXCFG_TYPE_X4: fmt1 = "0x%08" PRIx64 " "; fmt2 = "|0x%08" PRIx64; valX = val->X4; break;
444 case UBLOXCFG_TYPE_X8: fmt1 = "0x%016" PRIx64 " "; fmt2 = "|0x%016" PRIx64; valX = val->X8; break;
445 default: break;
446 }
447 // render hex value
448 int len = snprintf(str, size, fmt1, valX);
449 const int ixBracket = len;
450 // add constant names for known bits
451 uint64_t usedBits = 0;
452 if (item != NULL)
453 {
454 for (int ix = 0; ix < item->nConsts; ix++)
455 {
456 if ((item->consts[ix].val.X & valX) != 0)
457 {
458 len += snprintf(&str[len], size - len, "|%s", item->consts[ix].name);
459 usedBits |= item->consts[ix].val.X;
460 if ((size - len - 1) <= 0)
461 {
462 break;
463 }
464 }
465 }
466 }
467 // add hex value of remaining bits (for which no constant was defined)
468 if ((size - len - 1) > 0)
469 {
470 const uint64_t unusedBits = valX & (~usedBits);
471 if (unusedBits == valX)
472 {
473 strncat(&str[len], "|n/a", size - len);
474 len += 4;
475 }
476 else if (unusedBits != 0)
477 {
478 len += snprintf(&str[len], size - len, fmt2, unusedBits);
479 }
480 }
481 // fix up and terminate string
482 str[ixBracket] = '('; // "|" --> "("
483 if ((size - len - 1) > 0)
484 {
485 str[len++] = ')';
486 str[len] = '\0';
487 res = true;
488 }
489 }
490 break;
491 case UBLOXCFG_TYPE_E1:
492 case UBLOXCFG_TYPE_E2:
493 case UBLOXCFG_TYPE_E4:
494 if (size > (15 + 30))
495 {
496 int32_t valE = 0;
497 switch (type)
498 {
499 case UBLOXCFG_TYPE_E1: valE = val->E1; break;
500 case UBLOXCFG_TYPE_E2: valE = val->E2; break;
501 case UBLOXCFG_TYPE_E4: valE = val->E4; break;
502 default: break;
503 }
504 if (item != NULL)
505 {
506 for (int ix = 0; ix < item->nConsts; ix++)
507 {
508 if ((int8_t)item->consts[ix].val.E == valE)
509 {
510 snprintf(str, size, "%s (%s)", item->consts[ix].value, item->consts[ix].name);
511 res = true;
512 break;
513 }
514 }
515 }
516 if (!res)
517 {
518 snprintf(str, size, "%" PRIi8 " (n/a)", valE);
519 res = true;
520 }
521 }
522 break;
523 case UBLOXCFG_TYPE_R4:
524 if (size >= 30) // -1.17549435082228750796874e-38..3.40282346638528859811704e+38
525 {
526 snprintf(str, size, "%.24g", val->R4);
527 res = true;
528 }
529 break;
530 case UBLOXCFG_TYPE_R8:
531 if (size >= 61) //-2.22507385850720138309023271733240406421921598046233183e-308..1.79769313486231570814527423731704356798070567525844997e+308
532 {
533 snprintf(str, size, "%.54g", val->R8);
534 res = true;
535 }
536 break;
537 case UBLOXCFG_TYPE_L:
538 if (size >= 10)
539 {
540 snprintf(str, size, val->L ? "1 (true)" : "0 (false)");
541 res = true;
542 }
543 break;
544 }
545
546 return res;
547}
548
549bool ubloxcfg_splitValueStr(char *str, char **valueStr, char **prettyStr)
550{
551 if ( (str == NULL) || (valueStr == NULL) || (prettyStr == NULL) )
552 {
553 return false;
554 }
555 *valueStr = str;
556 *prettyStr = NULL;
557 char *space = strchr(str, ' ');
558 if (space != NULL)
559 {
560 *prettyStr = &space[2];
561 char *bracket = strchr(space, ')');
562 *space = '\0';
563 if (bracket != NULL)
564 {
565 bracket[0] = '\0';
566 }
567 if (strcmp(*prettyStr, "n/a") == 0)
568 {
569 *prettyStr = NULL;
570 }
571 }
572 return true;
573}
574
575bool ubloxcfg_stringifyKeyVal(char *str, const int size, const UBLOXCFG_KEYVAL_t *keyVal)
576{
577 if ( (str == NULL) || (size <= 0) || (keyVal == NULL) )
578 {
579 return false;
580 }
581
582 const UBLOXCFG_ITEM_t *item = ubloxcfg_getItemById(keyVal->id);
583 str[0] = '\0';
584 if (item == NULL)
585 {
586 int len = 0;
587 const UBLOXCFG_SIZE_t valSize = UBLOXCFG_ID2SIZE(keyVal->id);
588 switch (valSize)
589 {
591 len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?0) = 0x%"PRIx8,
592 keyVal->id, keyVal->val.X1);
593 break;
595 len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?1) = 0x%02"PRIx8,
596 keyVal->id, keyVal->val.X1);
597 break;
599 len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?2) = 0x%04"PRIx16,
600 keyVal->id, keyVal->val.X2);
601 break;
603 len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?4) = 0x%08"PRIx32,
604 keyVal->id, keyVal->val.X4);
605 break;
607 len = snprintf(str, size, "CFG-?-? (0x%08" PRIx32 ", ?8) = 0x%016"PRIx64,
608 keyVal->id, keyVal->val.X8);
609 break;
610 }
611 return len < size;
612 }
613
614 // add "item name (ID, type) = "
615 const char *type = ubloxcfg_typeStr(item->type);
616 int len = snprintf(str, size, "%s (0x%08" PRIx32 ", %s) = ", item->name, item->id, type != NULL ? type : "?");
617 if ((size - 1) <= len)
618 {
619 str[0] = '\0';
620 return false;
621 }
622
623 // add stringified value
624 if (!ubloxcfg_stringifyValue(&str[len], size - len, item->type, item, &keyVal->val))
625 {
626 str[0] = '\0';
627 return false;
628 }
629
630 // was there enough space?
631 len = strlen(str);
632 if ((size - 1 - 3) <= len)
633 {
634 str[0] = '\0';
635 return false;
636 }
637
638 // add scale and/or unit
639 if ( (item->scale != NULL) || (item->unit != NULL) )
640 {
641 str[len++] = ' ';
642 str[len++] = '[';
643 str[len] = '\0';
644
645 if (item->scale != NULL)
646 {
647 len += snprintf(&str[len], size - len, "%s", item->scale);
648 }
649 if ((size - 1 - 2) <= len)
650 {
651 str[0] = '\0';
652 return false;
653 }
654 if (item->unit != NULL)
655 {
656 len += snprintf(&str[len], size - len, "%s", item->unit);
657 }
658 if ((size - 1 - 1) <= len)
659 {
660 str[0] = '\0';
661 return false;
662 }
663 str[len++] = ']';
664 str[len] = '\0';
665 }
666
667 return true;
668}
669
670static bool strToValUnsigned(const char *str, const UBLOXCFG_TYPE_t type, uint64_t *val);
671static bool strToValSigned(const char *str, const UBLOXCFG_TYPE_t type, int64_t *val);
672static bool findEnumValue(const char *str, const UBLOXCFG_ITEM_t *item, int64_t *val);
673static bool findConstValue(const char *str, const UBLOXCFG_ITEM_t *item, uint64_t *val);
674
675bool ubloxcfg_valueFromString(const char *str, UBLOXCFG_TYPE_t type, const UBLOXCFG_ITEM_t *item, UBLOXCFG_VALUE_t *value)
676{
677 if ( (str == NULL) || (value == NULL) || ((item != NULL) && (item->type != type)) )
678 {
679 return false;
680 }
681
682 bool res = false;
683
684 uint64_t valUnsigned;
685 int64_t valSigned;
686 float valFloat;
687 double valDouble;
688 int numChar;
689 const int len = strlen(str);
690 memset(value, 0, sizeof(*value));
691 switch (type)
692 {
693 case UBLOXCFG_TYPE_L:
694 if (strcmp(str, "false") == 0)
695 {
696 value->L = false;
697 res = true;
698 }
699 else if (strcmp(str, "true") == 0)
700 {
701 value->L = true;
702 res = true;
703 }
704 else if (strToValUnsigned(str, UBLOXCFG_TYPE_U8, &valUnsigned))
705 {
706 if (valUnsigned == 0)
707 {
708 value->L = false;
709 res = true;
710 }
711 else if (valUnsigned == 1)
712 {
713 value->L = true;
714 res = true;
715 }
716 }
717 break;
718 case UBLOXCFG_TYPE_U1:
719 if (strToValUnsigned(str, type, &valUnsigned))
720 {
721 value->U1 = (uint8_t)valUnsigned;
722 res = true;
723 }
724 break;
725 case UBLOXCFG_TYPE_U2:
726 if (strToValUnsigned(str, type, &valUnsigned))
727 {
728 value->U2 = (uint16_t)valUnsigned;
729 res = true;
730 }
731 break;
732 case UBLOXCFG_TYPE_U4:
733 if (strToValUnsigned(str, type, &valUnsigned))
734 {
735 value->U4 = (uint32_t)valUnsigned;
736 res = true;
737 }
738 break;
739 case UBLOXCFG_TYPE_U8:
740 if (strToValUnsigned(str, type, &valUnsigned))
741 {
742 value->U8 = valUnsigned;
743 res = true;
744 }
745 break;
746 case UBLOXCFG_TYPE_X1:
747 if (findConstValue(str, item, &valUnsigned))
748 {
749 value->X1 = (uint8_t)valUnsigned;
750 res = true;
751 }
752 else if (strToValUnsigned(str, type, &valUnsigned))
753 {
754 value->U1 = (uint8_t)valUnsigned;
755 res = true;
756 }
757 break;
758 case UBLOXCFG_TYPE_X2:
759 if (findConstValue(str, item, &valUnsigned))
760 {
761 value->X2 = (uint16_t)valUnsigned;
762 res = true;
763 }
764 else if (strToValUnsigned(str, type, &valUnsigned))
765 {
766 value->X2 = (uint16_t)valUnsigned;
767 res = true;
768 }
769 break;
770 case UBLOXCFG_TYPE_X4:
771 if (findConstValue(str, item, &valUnsigned))
772 {
773 value->X4 = (uint32_t)valUnsigned;
774 res = true;
775 }
776 else if (strToValUnsigned(str, type, &valUnsigned))
777 {
778 value->X4 = (uint32_t)valUnsigned;
779 res = true;
780 }
781 break;
782 case UBLOXCFG_TYPE_X8:
783 if (findConstValue(str, item, &valUnsigned))
784 {
785 value->X8 = valUnsigned;
786 res = true;
787 }
788 else if (strToValUnsigned(str, type, &valUnsigned))
789 {
790 value->X8 = valUnsigned;
791 res = true;
792 }
793 break;
794 case UBLOXCFG_TYPE_I1:
795 if (strToValSigned(str, type, &valSigned))
796 {
797 value->I1 = (int8_t)valSigned;
798 res = true;
799 }
800 break;
801 case UBLOXCFG_TYPE_I2:
802 if (strToValSigned(str, type, &valSigned))
803 {
804 value->I2 = (int16_t)valSigned;
805 res = true;
806 }
807 break;
808 case UBLOXCFG_TYPE_I4:
809 if (strToValSigned(str, type, &valSigned))
810 {
811 value->I4 = (int32_t)valSigned;
812 res = true;
813 }
814 break;
815 case UBLOXCFG_TYPE_I8:
816 if (strToValSigned(str, type, &valSigned))
817 {
818 value->I8 = valSigned;
819 res = true;
820 }
821 break;
822 case UBLOXCFG_TYPE_R4:
823 if ( (sscanf(str, "%f%n", &valFloat, &numChar) == 1) && (numChar == len) )
824 {
825 value->R4 = valFloat;
826 res = true;
827 }
828 break;
829 case UBLOXCFG_TYPE_R8:
830 if ( (sscanf(str, "%lf%n", &valDouble, &numChar) == 1) && (numChar == len) )
831 {
832 value->R8 = valDouble;
833 res = true;
834 }
835 break;
836 case UBLOXCFG_TYPE_E1:
837 if (findEnumValue(str, item, &valSigned))
838 {
839 value->E1 = (int8_t)valSigned;
840 res = true;
841 }
842 else if (strToValSigned(str, type, &valSigned))
843 {
844 value->I1 = (int8_t)valSigned;
845 res = true;
846 }
847 break;
848 case UBLOXCFG_TYPE_E2:
849 if (findEnumValue(str, item, &valSigned))
850 {
851 value->E2 = (int16_t)valSigned;
852 res = true;
853 }
854 else if (strToValSigned(str, type, &valSigned))
855 {
856 value->I2 = (int16_t)valSigned;
857 res = true;
858 }
859 break;
860 case UBLOXCFG_TYPE_E4:
861 if (findEnumValue(str, item, &valSigned))
862 {
863 value->E4 = (int32_t)valSigned;
864 res = true;
865 }
866 else if (strToValSigned(str, type, &valSigned))
867 {
868 value->I4= (int32_t)valSigned;
869 res = true;
870 }
871 break;
872 }
873 return res;
874}
875
876static bool strToValUnsigned(const char *str, const UBLOXCFG_TYPE_t type, uint64_t *val)
877{
878 if ( (str == NULL) || (val == NULL) )
879 {
880 return false;
881 }
882 const int len = strlen(str);
883 if ( (len < 1) || (isspace((int)str[0]) != 0) )
884 {
885 return false;
886 }
887
888 bool res = false;
889 uint64_t max = 0;
890 switch (type)
891 {
892 case UBLOXCFG_TYPE_U1:
893 case UBLOXCFG_TYPE_X1:
894 max = UINT8_MAX;
895 break;
896 case UBLOXCFG_TYPE_U2:
897 case UBLOXCFG_TYPE_X2:
898 max = UINT16_MAX;
899 break;
900 case UBLOXCFG_TYPE_U4:
901 case UBLOXCFG_TYPE_X4:
902 max = UINT32_MAX;
903 break;
904 case UBLOXCFG_TYPE_U8:
905 case UBLOXCFG_TYPE_X8:
906 max = UINT64_MAX;
907 break;
908 default: break;
909 }
910 uint64_t value;
911 if (len < 1)
912 {
913 return false;
914 }
915 // hex
916 else if ( (len > 1) && (str[0] == '0') && (str[1] == 'x') )
917 {
918 int numChar = 0;
919 if ( (len > 2) && (sscanf(str, "%" SCNx64"%n", &value, &numChar) == 1) && (numChar == len) )
920 {
921 res = true;
922 }
923 }
924 // octal
925 else if (str[0] == '0')
926 {
927 int numChar = 0;
928 if ( (sscanf(str, "%" SCNo64"%n", &value, &numChar) == 1) && (numChar == len) )
929 {
930 res = true;
931 }
932 }
933 // dec
934 else
935 {
936 int numChar = 0;
937 if ( (sscanf(str, "%" SCNu64"%n", &value, &numChar) == 1) && (numChar == len) )
938 {
939 res = true;
940 }
941 }
942
943 if (res)
944 {
945 *val = value;
946 }
947 return res && (value <= max);
948}
949
950
951static bool strToValSigned(const char *str, UBLOXCFG_TYPE_t type, int64_t *val)
952{
953 if ( (str == NULL) || (val == NULL) )
954 {
955 return false;
956 }
957 const int len = strlen(str);
958 if ( (len < 1) || (isspace((int)str[0]) != 0) )
959 {
960 return false;
961 }
962
963 bool res = false;
964 int64_t min = 0;
965 int64_t max = 0;
966 switch (type)
967 {
968 case UBLOXCFG_TYPE_I1:
969 case UBLOXCFG_TYPE_E1:
970 min = INT8_MIN;
971 max = INT8_MAX;
972 break;
973 case UBLOXCFG_TYPE_I2:
974 case UBLOXCFG_TYPE_E2:
975 min = INT16_MIN;
976 max = INT16_MAX;
977 break;
978 case UBLOXCFG_TYPE_I4:
979 case UBLOXCFG_TYPE_E4:
980 min = INT32_MIN;
981 max = INT32_MAX;
982 break;
983 case UBLOXCFG_TYPE_I8:
984 min = INT64_MIN;
985 max = INT64_MAX;
986 break;
987 default: break;
988 }
989 int64_t value;
990 // hex
991 if ( (len > 1) && (str[0] == '0') && (str[1] == 'x') )
992 {
993 uint64_t valUnsigned;
994 int numChar = 0;
995 if ( (len > 2) && ( sscanf(str, "%" SCNx64"%n", &valUnsigned, &numChar) == 1) && (numChar ==len) )
996 {
997 // sign extend to size
998 switch (type)
999 {
1000 case UBLOXCFG_TYPE_I1:
1001 case UBLOXCFG_TYPE_E1:
1002 value = (int64_t)(int8_t)valUnsigned;
1003 break;
1004 case UBLOXCFG_TYPE_I2:
1005 case UBLOXCFG_TYPE_E2:
1006 value = (int64_t)(int16_t)valUnsigned;
1007 break;
1008 case UBLOXCFG_TYPE_I4:
1009 case UBLOXCFG_TYPE_E4:
1010 value = (int64_t)(int32_t)valUnsigned;
1011 break;
1012 case UBLOXCFG_TYPE_I8:
1013 value = (int64_t)valUnsigned;
1014 break;
1015 default:
1016 break;
1017 }
1018 res = true;
1019 }
1020 }
1021 // dec
1022 else
1023 {
1024 int numChar = 0;
1025 if ( (sscanf(str, "%" SCNi64"%n", &value, &numChar) == 1) && (numChar == len) )
1026 {
1027 res = true;
1028 }
1029 }
1030
1031 if (res)
1032 {
1033 *val = value;
1034 }
1035 return res && (value >= min) && (value <= max);
1036}
1037
1038
1039static bool findConstValue(const char *str, const UBLOXCFG_ITEM_t *item, uint64_t *val)
1040{
1041 if ( (item == NULL) || (val == NULL) || (str == NULL) || (strlen(str) < 1) )
1042 {
1043 return false;
1044 }
1045
1046 bool res = true;
1047 uint64_t valRes = 0;
1048
1049 // iterate over parts of the string, separated by '|'
1050 const char sep = '|';
1051 const char *pStr = str;
1052 const char *pSep = strchr(pStr, sep);
1053 while (*pStr != '\0')
1054 {
1055 // number of characters at beginning of pStr to compare
1056 const int cmpLen = strlen(pStr) - ( (pSep != NULL) ? strlen(pSep) : 0 );
1057
1058 // interpret (part of) the string, which can be a 0x.. hex number or a constant name
1059 if ( (cmpLen > 2) && (pStr[0] == '0') && (pStr[1] == 'x') )
1060 {
1061 uint64_t v = 0;
1062 int numChar = 0;
1063 if ( (cmpLen < 3) || (sscanf(pStr, "%" SCNx64"%n", &v, &numChar) != 1) || (numChar != cmpLen) )
1064 {
1065 res = false;
1066 break; // bad hex, give up
1067 }
1068 valRes |= v;
1069 }
1070 else
1071 {
1072 bool found = false;
1073 for (int ix = 0; (ix < item->nConsts) && !found; ix++)
1074 {
1075 const int nameLen = strlen(item->consts[ix].name);
1076 if ( (nameLen == cmpLen) && (strncmp(item->consts[ix].name, pStr, cmpLen) == 0) )
1077 {
1078 valRes |= item->consts[ix].val.X;
1079 found = true;
1080 }
1081 }
1082 if (!found)
1083 {
1084 res = false;
1085 break; // bad part of string, give up
1086 }
1087 }
1088
1089 // next part or done
1090 if (pSep != NULL)
1091 {
1092 pStr = pSep + 1;
1093 pSep = strchr(pStr, sep);
1094 }
1095 else
1096 {
1097 break;
1098 }
1099 }
1100
1101 if (res)
1102 {
1103 *val = valRes;
1104 }
1105 return res;
1106}
1107
1108static bool findEnumValue(const char *str, const UBLOXCFG_ITEM_t *item, int64_t *val)
1109{
1110 bool res = false;
1111 if (item != NULL)
1112 {
1113 for (int ix = 0; ix < item->nConsts; ix++)
1114 {
1115 if (strcmp(str, item->consts[ix].name) == 0)
1116 {
1117 *val = (int64_t)item->consts[ix].val.E;
1118 res = true;
1119 break;
1120 }
1121 }
1122 }
1123 return res;
1124}
1125
1126const char *ubloxcfg_layerName(const UBLOXCFG_LAYER_t layer)
1127{
1128 switch (layer)
1129 {
1130 case UBLOXCFG_LAYER_RAM: return "RAM";
1131 case UBLOXCFG_LAYER_BBR: return "BBR";
1132 case UBLOXCFG_LAYER_FLASH: return "Flash";
1133 case UBLOXCFG_LAYER_DEFAULT: return "Default";
1134 }
1135 return "?";
1136}
1137
1138bool ubloxcfg_layerFromName(const char *name, UBLOXCFG_LAYER_t *layer)
1139{
1140 if ( (name == NULL) || (name[0] == '\0') )
1141 {
1142 return false;
1143 }
1144 char str[20];
1145 int len = strlen(name);
1146 if (len > ((int)sizeof(str) - 1))
1147 {
1148 return false;
1149 }
1150 str[len] = '\0';
1151 while (len > 0)
1152 {
1153 len--;
1154 str[len] = tolower(name[len]);
1155 }
1156 if (strcmp(str, "ram") == 0)
1157 {
1158 *layer = UBLOXCFG_LAYER_RAM;
1159 }
1160 else if (strcmp(str, "bbr") == 0)
1161 {
1162 *layer = UBLOXCFG_LAYER_BBR;
1163 }
1164 else if (strcmp(str, "flash") == 0)
1165 {
1166 *layer = UBLOXCFG_LAYER_FLASH;
1167 }
1168 else if (strcmp(str, "default") == 0)
1169 {
1170 *layer = UBLOXCFG_LAYER_DEFAULT;
1171 }
1172 else
1173 {
1174 return false;
1175 }
1176 return true;
1177}
1178
1180{
1181 return ((uint16_t)CONFIG_VERSION_MAJOR << 8 | ((uint16_t)CONFIG_VERSION_MINOR & 0xff));
1182}
1183
1184const char **ubloxcfg_getSources(int *numSources)
1185{
1186 *numSources = _UBLOXCFG_NUM_SOURCES;
1187 return _ubloxcfg_allSources();
1188}
1189
1190/* ****************************************************************************************************************** */
1191
1192// eof
bool ubloxcfg_valueFromString(const char *str, UBLOXCFG_TYPE_t type, const UBLOXCFG_ITEM_t *item, UBLOXCFG_VALUE_t *value)
Convert string to value.
Definition ubloxcfg.c:675
const char * ubloxcfg_typeStr(UBLOXCFG_TYPE_t type)
Stringify item type.
Definition ubloxcfg.c:336
bool ubloxcfg_parseData(const uint8_t *data, const int size, UBLOXCFG_KEYVAL_t *keyVal, const int maxKeyVal, int *nKeyVal)
Key-value list from configuration data.
Definition ubloxcfg.c:214
bool ubloxcfg_makeData(uint8_t *data, const int size, const UBLOXCFG_KEYVAL_t *keyVal, const int nKeyVal, int *dataSize)
Configuration data from key-value list.
Definition ubloxcfg.c:120
struct UBLOXCFG_KEYVAL_s UBLOXCFG_KEYVAL_t
Key-value pair.
bool ubloxcfg_splitValueStr(char *str, char **valueStr, char **prettyStr)
Split stringified value string.
Definition ubloxcfg.c:549
union UBLOXCFG_VALUE_u UBLOXCFG_VALUE_t
Configuration value storage (s.a. UBLOXCFG_TYPE_t)
bool ubloxcfg_stringifyValue(char *str, const int size, const UBLOXCFG_TYPE_t type, const UBLOXCFG_ITEM_t *item, const UBLOXCFG_VALUE_t *val)
Stringify item value.
Definition ubloxcfg.c:362
bool ubloxcfg_stringifyKeyVal(char *str, const int size, const UBLOXCFG_KEYVAL_t *keyVal)
Stringify key-value pair (for debugging)
Definition ubloxcfg.c:575
enum UBLOXCFG_SIZE_e UBLOXCFG_SIZE_t
Configuration item size.
const UBLOXCFG_ITEM_t * ubloxcfg_getItemByName(const char *name)
Get configuration item info by name.
Definition ubloxcfg.c:41
struct UBLOXCFG_ITEM_s UBLOXCFG_ITEM_t
Configuration item.
const UBLOXCFG_MSGRATE_t * ubloxcfg_getMsgRateCfg(const char *msgName)
Get configuration items for output message rate configuration.
Definition ubloxcfg.c:95
struct UBLOXCFG_MSGRATE_s UBLOXCFG_MSGRATE_t
Configuration items for output message rate configuration.
#define UBLOXCFG_ID2SIZE(id)
Get item size from item ID.
Definition ubloxcfg.h:60
const UBLOXCFG_ITEM_t ** ubloxcfg_getAllItems(int *num)
Get list of all items.
Definition ubloxcfg.c:89
enum UBLOXCFG_LAYER_e UBLOXCFG_LAYER_t
Configuration layers.
bool ubloxcfg_layerFromName(const char *name, UBLOXCFG_LAYER_t *layer)
Get layer from name.
Definition ubloxcfg.c:1138
const char * ubloxcfg_layerName(const UBLOXCFG_LAYER_t layer)
Get name for layer.
Definition ubloxcfg.c:1126
const UBLOXCFG_ITEM_t * ubloxcfg_getItemById(const uint32_t id)
Get configuration item info by key ID.
Definition ubloxcfg.c:74
enum UBLOXCFG_TYPE_e UBLOXCFG_TYPE_t
Configuration item storage type (s.a. UBLOXCFG_VALUE_t)
const UBLOXCFG_MSGRATE_t ** ubloxcfg_getAllMsgRateCfgs(int *num)
Get list of all output message rate configurations.
Definition ubloxcfg.c:114
@ UBLOXCFG_SIZE_EIGHT
Eight bytes.
Definition ubloxcfg.h:50
@ UBLOXCFG_SIZE_ONE
One byte.
Definition ubloxcfg.h:47
@ UBLOXCFG_SIZE_FOUR
Four bytes.
Definition ubloxcfg.h:49
@ UBLOXCFG_SIZE_BIT
One bit.
Definition ubloxcfg.h:46
@ UBLOXCFG_SIZE_TWO
Two bytes.
Definition ubloxcfg.h:48
@ UBLOXCFG_LAYER_DEFAULT
Default layer.
Definition ubloxcfg.h:186
@ UBLOXCFG_LAYER_FLASH
Flash layer.
Definition ubloxcfg.h:185
@ UBLOXCFG_LAYER_RAM
RAM layer (a.k.a. current configuration)
Definition ubloxcfg.h:183
@ UBLOXCFG_LAYER_BBR
BBR layer.
Definition ubloxcfg.h:184
@ UBLOXCFG_TYPE_I1
One byte signed, little-endian (int8_t)
Definition ubloxcfg.h:83
@ UBLOXCFG_TYPE_U8
Eight bytes unsigned, little-endian (uint64_t)
Definition ubloxcfg.h:82
@ UBLOXCFG_TYPE_X8
Eight bytes unsigned, little-endian (uint64_t)
Definition ubloxcfg.h:90
@ UBLOXCFG_TYPE_U2
Two bytes unsigned, little-endian (uint16_t)
Definition ubloxcfg.h:80
@ UBLOXCFG_TYPE_X4
Four bytes unsigned, little-endian (uint32_t)
Definition ubloxcfg.h:89
@ UBLOXCFG_TYPE_I8
Eight byte signed, little-endian (int64_t)
Definition ubloxcfg.h:86
@ UBLOXCFG_TYPE_L
One bit logical (0 = false, 1 = true)
Definition ubloxcfg.h:96
@ UBLOXCFG_TYPE_E2
Two bytes unsigned, little-endian (int16_t)
Definition ubloxcfg.h:94
@ UBLOXCFG_TYPE_E4
Four bytes unsigned, little-endian (int32_t)
Definition ubloxcfg.h:95
@ UBLOXCFG_TYPE_I4
Four bytes signed, little-endian (int32_t)
Definition ubloxcfg.h:85
@ UBLOXCFG_TYPE_I2
Two bytes signed, little-endian (int16_t)
Definition ubloxcfg.h:84
@ UBLOXCFG_TYPE_X2
Two bytes unsigned, little-endian (uint16_t)
Definition ubloxcfg.h:88
@ UBLOXCFG_TYPE_R8
Eight bytes IEEE754 double precision (double)
Definition ubloxcfg.h:92
@ UBLOXCFG_TYPE_R4
Four bytes IEEE754 single precision (float)
Definition ubloxcfg.h:91
@ UBLOXCFG_TYPE_U1
One byte unsigned, little-endian (uint8_t)
Definition ubloxcfg.h:79
@ UBLOXCFG_TYPE_X1
One byte unsigned, little-endian (uint8_t)
Definition ubloxcfg.h:87
@ UBLOXCFG_TYPE_E1
One byte unsigned, little-endian (int8_t)
Definition ubloxcfg.h:93
@ UBLOXCFG_TYPE_U4
Four bytes unsigned, little-endian (uint32_t)
Definition ubloxcfg.h:81
uint16_t ubloxcfg_getVersion(void)
Get library version.
Definition ubloxcfg.c:1179
const char ** ubloxcfg_getSources(int *numSources)
Get strings describing the data sources.
Definition ubloxcfg.c:1184
int32_t E
E type value as number.
Definition ubloxcfg.h:107
const char * name
Name of the constant.
Definition ubloxcfg.h:102
uint64_t X
X type value as number.
Definition ubloxcfg.h:108
union UBLOXCFG_CONST_s::@113126027024203123227301300211101055257152153302 val
Value.
const char * value
Value as string.
Definition ubloxcfg.h:104
const char * unit
Unit (or NULL)
Definition ubloxcfg.h:120
const char * scale
Scale factor as string (or NULL)
Definition ubloxcfg.h:121
UBLOXCFG_TYPE_t type
Storage type.
Definition ubloxcfg.h:116
uint32_t id
Item ID.
Definition ubloxcfg.h:115
int nConsts
Number of constants (or 0 if none)
Definition ubloxcfg.h:123
const char * name
Item name.
Definition ubloxcfg.h:118
const UBLOXCFG_CONST_t * consts
Constants (or NULL if none)
Definition ubloxcfg.h:122
UBLOXCFG_VALUE_t val
Configuration item value.
Definition ubloxcfg.h:238
uint32_t id
Configuration item ID.
Definition ubloxcfg.h:237
u-blox 9 positioning receivers configuration library
uint16_t U2
UBLOXCFG_TYPE_U2 type value
Definition ubloxcfg.h:213
int16_t I2
UBLOXCFG_TYPE_I2 type value
Definition ubloxcfg.h:217
uint32_t X4
UBLOXCFG_TYPE_X4 type value
Definition ubloxcfg.h:222
double R8
UBLOXCFG_TYPE_R8 type value
Definition ubloxcfg.h:225
int32_t E4
UBLOXCFG_TYPE_E4 type value
Definition ubloxcfg.h:228
int8_t E1
UBLOXCFG_TYPE_E1 type value
Definition ubloxcfg.h:226
uint64_t U8
UBLOXCFG_TYPE_U8 type value
Definition ubloxcfg.h:215
int8_t I1
UBLOXCFG_TYPE_I1 type value
Definition ubloxcfg.h:216
uint32_t U4
UBLOXCFG_TYPE_U4 type value
Definition ubloxcfg.h:214
uint8_t X1
UBLOXCFG_TYPE_X1 type value
Definition ubloxcfg.h:220
float R4
UBLOXCFG_TYPE_R4 type value
Definition ubloxcfg.h:224
bool L
UBLOXCFG_TYPE_L type value
Definition ubloxcfg.h:229
int64_t I8
UBLOXCFG_TYPE_I8 type value
Definition ubloxcfg.h:219
uint64_t X8
UBLOXCFG_TYPE_X8 type value
Definition ubloxcfg.h:223
uint8_t U1
UBLOXCFG_TYPE_U1 type value
Definition ubloxcfg.h:212
uint8_t _bytes[8]
raw bytes, unused bytes shall be 0x00
Definition ubloxcfg.h:230
uint16_t X2
UBLOXCFG_TYPE_X2 type value
Definition ubloxcfg.h:221
int32_t I4
UBLOXCFG_TYPE_I4 type value
Definition ubloxcfg.h:218
int16_t E2
UBLOXCFG_TYPE_E2 type value
Definition ubloxcfg.h:227