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