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 // 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 
41 const UBLOXCFG_ITEM_t *ubloxcfg_getItemByName(const char *name)
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 
74 const 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 
95 const 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 
120 bool 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  {
153  case UBLOXCFG_SIZE_BIT:
154  if ( (size - dataIx) < 1 )
155  {
156  res = false;
157  break;
158  }
159  data[dataIx++] = val._bytes[0];
160  break;
161  case UBLOXCFG_SIZE_ONE:
162  if ( (size - dataIx) < 1 )
163  {
164  res = false;
165  break;
166  }
167  data[dataIx++] = val._bytes[0];
168  break;
169  case UBLOXCFG_SIZE_TWO:
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;
178  case UBLOXCFG_SIZE_FOUR:
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;
189  case UBLOXCFG_SIZE_EIGHT:
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 
214 bool 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);
239  UBLOXCFG_VALUE_t val;
240  val.U8 = 0;
241  switch (valSize)
242  {
243  case UBLOXCFG_SIZE_BIT:
244  if ( dataIx > (size - 1) )
245  {
246  res = false;
247  break;
248  }
249  else
250  {
251  val._bytes[0] = data[dataIx++];
252  }
253  break;
254  case UBLOXCFG_SIZE_ONE:
255  if ( dataIx > (size - 1) )
256  {
257  res = false;
258  break;
259  }
260  else
261  {
262  val._bytes[0] = data[dataIx++];
263  }
264  break;
265  case UBLOXCFG_SIZE_TWO:
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;
277  case UBLOXCFG_SIZE_FOUR:
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;
291  case UBLOXCFG_SIZE_EIGHT:
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 
362 bool 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 
549 bool 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 
575 bool 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  {
590  case UBLOXCFG_SIZE_BIT:
591  len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?0) = 0x%"PRIx8,
592  keyVal->id, keyVal->val.X1);
593  break;
594  case UBLOXCFG_SIZE_ONE:
595  len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?1) = 0x%02"PRIx8,
596  keyVal->id, keyVal->val.X1);
597  break;
598  case UBLOXCFG_SIZE_TWO:
599  len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?2) = 0x%04"PRIx16,
600  keyVal->id, keyVal->val.X2);
601  break;
602  case UBLOXCFG_SIZE_FOUR:
603  len = snprintf(str, size, "CFG-?-? (0x%02" PRIx32 ", ?4) = 0x%08"PRIx32,
604  keyVal->id, keyVal->val.X4);
605  break;
606  case UBLOXCFG_SIZE_EIGHT:
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 
670 static bool strToValUnsigned(const char *str, const UBLOXCFG_TYPE_t type, uint64_t *val);
671 static bool strToValSigned(const char *str, const UBLOXCFG_TYPE_t type, int64_t *val);
672 static bool findEnumValue(const char *str, const UBLOXCFG_ITEM_t *item, int64_t *val);
673 static bool findConstValue(const char *str, const UBLOXCFG_ITEM_t *item, uint64_t *val);
674 
675 bool 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 
876 static 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 
951 static 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 
1039 static 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 
1108 static 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 
1126 const 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 
1138 bool 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 
1179 uint16_t ubloxcfg_getVersion(void)
1180 {
1181  return ((uint16_t)CONFIG_VERSION_MAJOR << 8 | ((uint16_t)CONFIG_VERSION_MINOR & 0xff));
1182 }
1183 
1184 const char **ubloxcfg_getSources(int *numSources)
1185 {
1186  *numSources = _UBLOXCFG_NUM_SOURCES;
1187  return _ubloxcfg_allSources();
1188 }
1189 
1190 /* ****************************************************************************************************************** */
1191 
1192 // 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:41
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:549
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:95
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:1184
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:114
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:89
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:336
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:120
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:362
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:1138
uint16_t ubloxcfg_getVersion(void)
Get library version.
Definition: ubloxcfg.c:1179
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:74
bool ubloxcfg_stringifyKeyVal(char *str, const int size, const UBLOXCFG_KEYVAL_t *keyVal)
Stringify key-value pair (for debugging)
Definition: ubloxcfg.c:575
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:214
Two bytes.
Definition: ubloxcfg.h:48
const char * ubloxcfg_layerName(const UBLOXCFG_LAYER_t layer)
Get name for layer.
Definition: ubloxcfg.c:1126
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
uint8_t _bytes[8]
raw bytes, unused bytes shall be 0x00
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