PX4 Firmware
PX4 Autopilot Software http://px4.io
parameters_shmem.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015 Vijay Venkatraman. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file param.c
36  *
37  * Global parameter store.
38  *
39  * Note that it might make sense to convert this into a driver. That would
40  * offer some interesting options regarding state for e.g. ORB advertisements
41  * and background parameter saving.
42  */
43 
44 #include "param.h"
45 #include <parameters/px4_parameters.h>
46 #include "tinybson/tinybson.h"
47 
48 #include <crc32.h>
49 #include <float.h>
50 #include <math.h>
51 
52 #include <drivers/drv_hrt.h>
53 #include <px4_platform_common/px4_config.h>
54 #include <px4_platform_common/defines.h>
55 #include <px4_platform_common/posix.h>
56 #include <px4_platform_common/sem.h>
57 #include <px4_platform_common/shutdown.h>
58 
59 #include <perf/perf_counter.h>
61 
62 //#define PARAM_NO_ORB ///< if defined, avoid uorb dependency. This disables publication of parameter_update on param change
63 //#define PARAM_NO_AUTOSAVE ///< if defined, do not autosave (avoids LP work queue dependency)
64 
65 #if !defined(PARAM_NO_ORB)
66 # include "uORB/uORB.h"
68 #endif
69 
70 #if defined(FLASH_BASED_PARAMS)
72 #endif
73 
74 #include <sys/stat.h>
75 
76 #include <px4_platform_common/shmem.h>
77 
78 #ifdef __PX4_QURT
79 static const char *param_default_file = "/dev/fs/params";
80 #else
81 static const char *param_default_file = "/usr/share/data/adsp/params";
82 #endif
83 static char *param_user_file = nullptr;
84 
85 #ifdef __PX4_QURT
86 //Mode not supported by qurt
87 #define PARAM_OPEN(a, b, ...) open(a, b)
88 #else
89 #define PARAM_OPEN open
90 #endif
91 #define PARAM_CLOSE close
92 
93 #ifndef PARAM_NO_AUTOSAVE
94 #include <px4_platform_common/workqueue.h>
95 /* autosaving variables */
97 static struct work_s autosave_work;
98 static bool autosave_scheduled = false;
99 static bool autosave_disabled = false;
100 #endif /* PARAM_NO_AUTOSAVE */
101 
102 /**
103  * Array of static parameter info.
104  */
105 static const param_info_s *param_info_base = (const param_info_s *) &px4_parameters;
106 #define param_info_count px4_parameters.param_count
107 
108 /**
109  * Storage for modified parameters.
110  */
111 struct param_wbuf_s {
112  union param_value_u val;
113  param_t param;
114  bool unsaved;
115 };
116 
117 
118 uint8_t *param_changed_storage = nullptr;
120 const int bits_per_allocation_unit = (sizeof(*param_changed_storage) * 8);
121 
122 //#define ENABLE_SHMEM_DEBUG
123 static void init_params();
124 
125 static int param_set_internal(param_t param, const void *val, bool mark_saved, bool notify_changes);
126 static unsigned char set_called_from_get = 0;
127 
128 static int param_import_done =
129  0; /*at startup, params are loaded from file, if present. we dont want to send notifications that time since muorb is not ready*/
130 
131 static int param_load_default_no_notify();
132 
133 static unsigned
135 {
136  /* Singleton creation of and array of bits to track changed values */
137  if (!param_changed_storage) {
138  /* Note that we have a (highly unlikely) race condition here: in the worst case the allocation is done twice */
141 
142  /* If the allocation fails we need to indicate failure in the
143  * API by returning PARAM_INVALID
144  */
145  if (param_changed_storage == nullptr) {
146  return 0;
147  }
148  }
149 
150  return param_info_count;
151 }
152 
153 /** flexible array holding modified parameter values */
155 
156 /** array info for the modified parameters array */
157 const UT_icd param_icd = {sizeof(param_wbuf_s), nullptr, nullptr, nullptr};
158 
159 #if !defined(PARAM_NO_ORB)
160 /** parameter update topic handle */
161 static orb_advert_t param_topic = nullptr;
162 static unsigned int param_instance = 0;
163 #endif
164 
166 
167 static param_t param_find_internal(const char *name, bool notification);
168 
169 // TODO: not working on Snappy just yet
170 // the following implements an RW-lock using 2 semaphores (used as mutexes). It gives
171 // priority to readers, meaning a writer could suffer from starvation, but in our use-case
172 // we only have short periods of reads and writes are rare.
173 //static px4_sem_t param_sem; ///< this protects against concurrent access to param_values
174 //static int reader_lock_holders = 0;
175 //static px4_sem_t reader_lock_holders_lock; ///< this protects against concurrent access to reader_lock_holders
176 
181 
182 //static px4_sem_t param_sem_save; ///< this protects against concurrent param saves (file or flash access).
183 ///< we use a separate lock to allow concurrent param reads and saves.
184 ///< a param_set could still be blocked by a param save, because it
185 ///< needs to take the reader lock
186 
187 /** lock the parameter store for read access */
188 static void
190 {
191  // TODO: this doesn't seem to work on Snappy
192 #if 0
193  do {} while (px4_sem_wait(&reader_lock_holders_lock) != 0);
194 
196 
197  if (reader_lock_holders == 1) {
198  // the first reader takes the lock, the next ones are allowed to just continue
199  do {} while (px4_sem_wait(&param_sem) != 0);
200  }
201 
202  px4_sem_post(&reader_lock_holders_lock);
203 #endif
204 }
205 
206 /** lock the parameter store for write access */
207 static void
209 {
210  // TODO: this doesn't seem to work on Snappy
211 #if 0
212  do {} while (px4_sem_wait(&param_sem) != 0);
213 
214 #endif
215 }
216 
217 /** unlock the parameter store */
218 static void
220 {
221  // TODO: this doesn't seem to work on Snappy
222 #if 0
223  do {} while (px4_sem_wait(&reader_lock_holders_lock) != 0);
224 
226 
227  if (reader_lock_holders == 0) {
228  // the last reader releases the lock
229  px4_sem_post(&param_sem);
230  }
231 
232  px4_sem_post(&reader_lock_holders_lock);
233 #endif
234 }
235 
236 /** unlock the parameter store */
237 static void
239 {
240  // TODO: this doesn't seem to work on Snappy
241 #if 0
242  px4_sem_post(&param_sem);
243 #endif
244 }
245 
246 /** assert that the parameter store is locked */
247 static void
249 {
250  /* XXX */
251 }
252 
253 void
255 {
256  // TODO: not needed on Snappy yet.
257  //px4_sem_init(&param_sem, 0, 1);
258  //px4_sem_init(&param_sem_save, 0, 1);
259  //px4_sem_init(&reader_lock_holders_lock, 0, 1);
260 
261  param_export_perf = perf_alloc(PC_ELAPSED, "param_export");
262  param_find_perf = perf_alloc(PC_ELAPSED, "param_find");
263  param_get_perf = perf_alloc(PC_ELAPSED, "param_get");
264  param_set_perf = perf_alloc(PC_ELAPSED, "param_set");
265 
266 #ifdef CONFIG_SHMEM
267  PX4_DEBUG("Syncing params to shared memory\n");
268  init_params();
269 #endif
270 }
271 
272 /**
273  * Test whether a param_t is value.
274  *
275  * @param param The parameter handle to test.
276  * @return True if the handle is valid.
277  */
278 bool
280 {
281  unsigned count = get_param_info_count();
282  return (count && param < count);
283 }
284 
285 /**
286  * Compare two modifid parameter structures to determine ordering.
287  *
288  * This function is suitable for passing to qsort or bsearch.
289  */
290 static int
291 param_compare_values(const void *a, const void *b)
292 {
293  struct param_wbuf_s *pa = (struct param_wbuf_s *)a;
294  struct param_wbuf_s *pb = (struct param_wbuf_s *)b;
295 
296  if (pa->param < pb->param) {
297  return -1;
298  }
299 
300  if (pa->param > pb->param) {
301  return 1;
302  }
303 
304  return 0;
305 }
306 
307 /**
308  * Locate the modified parameter structure for a parameter, if it exists.
309  *
310  * @param param The parameter being searched.
311  * @return The structure holding the modified value, or
312  * nullptr if the parameter has not been modified.
313  */
314 param_wbuf_s *
316 {
317  param_wbuf_s *s = nullptr;
318 
320 
321  if (param_values != nullptr) {
322  param_wbuf_s key{};
323  key.param = param;
325  }
326 
327  return s;
328 }
329 
330 static void
332 {
333 #if !defined(PARAM_NO_ORB)
334  parameter_update_s pup = {};
336  pup.instance = param_instance++;
337 
338  /*
339  * If we don't have a handle to our topic, create one now; otherwise
340  * just publish.
341  */
342  if (param_topic == nullptr) {
343  param_topic = orb_advertise(ORB_ID(parameter_update), &pup);
344 
345  } else {
346  orb_publish(ORB_ID(parameter_update), param_topic, &pup);
347  }
348 
349 #endif
350 }
351 
352 void
354 {
356 }
357 
358 param_t
359 param_find_internal(const char *name, bool notification)
360 {
361  perf_begin(param_find_perf);
362 
363  param_t param;
364 
365  /* perform a linear search of the known parameters */
366  for (param = 0; handle_in_range(param); param++) {
367  if (!strcmp(param_info_base[param].name, name)) {
368  if (notification) {
370  }
371 
372  perf_end(param_find_perf);
373  return param;
374  }
375  }
376 
377  perf_end(param_find_perf);
378 
379  /* not found */
380  return PARAM_INVALID;
381 }
382 
383 param_t
384 param_find(const char *name)
385 {
386  return param_find_internal(name, true);
387 }
388 
389 param_t
391 {
392  return param_find_internal(name, false);
393 }
394 
395 unsigned
397 {
398  return get_param_info_count();
399 }
400 
401 unsigned
403 {
404  //TODO FIXME: all params used right now
405 #if 0
406  unsigned count = 0;
407 
408  // ensure the allocation has been done
409  if (get_param_info_count()) {
410 
411  for (int i = 0; i < size_param_changed_storage_bytes; i++) {
412  for (int j = 0; j < bits_per_allocation_unit; j++) {
413  if (param_changed_storage[i] & (1 << j)) {
414  count++;
415  }
416  }
417  }
418  }
419 
420  return count;
421 #else
422  return get_param_info_count();
423 #endif
424 }
425 
426 param_t
427 param_for_index(unsigned index)
428 {
429  unsigned count = get_param_info_count();
430 
431  if (count && index < count) {
432  return (param_t)index;
433  }
434 
435  return PARAM_INVALID;
436 }
437 
438 param_t
439 param_for_used_index(unsigned index)
440 {
441 #if 0
442  int count = get_param_info_count();
443 
444  if (count && (int)index < count) {
445  /* walk all params and count used params */
446  unsigned used_count = 0;
447 
448  for (int i = 0; i < size_param_changed_storage_bytes; i++) {
449  for (int j = 0; j < bits_per_allocation_unit; j++) {
450  if (param_changed_storage[i] & (1 << j)) {
451 
452  /* we found the right used count,
453  * return the param value
454  */
455  if (index == used_count) {
456  return (param_t)(i * bits_per_allocation_unit + j);
457  }
458 
459  used_count++;
460  }
461  }
462  }
463  }
464 
465  return PARAM_INVALID;
466 #else
467  return param_for_index(index);
468 #endif
469 }
470 
471 int
473 {
474  if (handle_in_range(param)) {
475  return (unsigned)param;
476  }
477 
478  return -1;
479 }
480 
481 int
483 {
484  // TODO FIXME: the used bit is not supported right now, therefore just count all.
485 #if 0
486  /* this tests for out of bounds and does a constant time lookup */
487  if (!param_used(param)) {
488  return -1;
489  }
490 
491  /* walk all params and count, now knowing that it has a valid index */
492  int used_count = 0;
493 
494  for (int i = 0; i < size_param_changed_storage_bytes; i++) {
495  for (int j = 0; j < bits_per_allocation_unit; j++) {
496  if (param_changed_storage[i] & (1 << j)) {
497 
498  if ((int)param == i * bits_per_allocation_unit + j) {
499  return used_count;
500  }
501 
502  used_count++;
503  }
504  }
505  }
506 
507  return -1;
508 #else
509  return param;
510 #endif
511 
512 }
513 
514 const char *
516 {
517  return handle_in_range(param) ? param_info_base[param].name : nullptr;
518 }
519 
520 bool
522 {
523  return handle_in_range(param) ? param_info_base[param].volatile_param : false;
524 }
525 
526 bool
528 {
529  struct param_wbuf_s *s;
531  s = param_find_changed(param);
533  return s ? false : true;
534 }
535 
536 bool
538 {
539  struct param_wbuf_s *s;
541  s = param_find_changed(param);
542  bool ret = s && s->unsaved;
544  return ret;
545 }
546 
549 {
550  return handle_in_range(param) ? param_info_base[param].type : PARAM_TYPE_UNKNOWN;
551 }
552 
553 size_t
555 {
556  if (handle_in_range(param)) {
557 
558  switch (param_type(param)) {
559 
560  case PARAM_TYPE_INT32:
561  case PARAM_TYPE_FLOAT:
562  return 4;
563 
565  /* decode structure size from type value */
566  return param_type(param) - PARAM_TYPE_STRUCT;
567 
568  default:
569  return 0;
570  }
571  }
572 
573  return 0;
574 }
575 
576 /**
577  * Obtain a pointer to the storage allocated for a parameter.
578  *
579  * @param param The parameter whose storage is sought.
580  * @return A pointer to the parameter value, or nullptr
581  * if the parameter does not exist.
582  */
583 static const void *
585 {
586  const void *result = nullptr;
587 
589 
590  if (handle_in_range(param)) {
591 
592  const union param_value_u *v;
593 
594  /* work out whether we're fetching the default or a written value */
595  struct param_wbuf_s *s = param_find_changed(param);
596 
597  if (s != nullptr) {
598  v = &s->val;
599 
600  } else {
601  v = &param_info_base[param].val;
602  }
603 
604  if (param_type(param) >= PARAM_TYPE_STRUCT &&
605  param_type(param) <= PARAM_TYPE_STRUCT_MAX) {
606 
607  result = v->p;
608 
609  } else {
610  result = v;
611  }
612  }
613 
614  return result;
615 }
616 
617 int
619 {
620  int result = -1;
621 
623  perf_begin(param_get_perf);
624 
625  if (!handle_in_range(param)) {
626  return result;
627  }
628 
629  union param_value_u value;
630 
631  if (update_from_shmem(param, &value)) {
633  param_set_internal(param, &value, true, false);
635  }
636 
637  const void *v = param_get_value_ptr(param);
638 
639  if (val && v) {
640  memcpy(val, v, param_size(param));
641  result = 0;
642  }
643 
644 #ifdef ENABLE_SHMEM_DEBUG
645 
646  if (param_type(param) == PARAM_TYPE_INT32) {
647  PX4_INFO("param_get for %s : %d", param_name(param), ((union param_value_u *)val)->i);
648  }
649 
650  else if (param_type(param) == PARAM_TYPE_FLOAT) {
651  PX4_INFO("param_get for %s : %f", param_name(param), (double)((union param_value_u *)val)->f);
652  }
653 
654  else {
655  PX4_INFO("Unknown param type for %s", param_name(param));
656  }
657 
658 #endif
659 
660  perf_end(param_get_perf);
662 
663  return result;
664 }
665 
666 #ifndef PARAM_NO_AUTOSAVE
667 /**
668  * worker callback method to save the parameters
669  * @param arg unused
670  */
671 static void
672 autosave_worker(void *arg)
673 {
674  bool disabled = false;
675 
678  autosave_scheduled = false;
679  disabled = autosave_disabled;
681 
682  if (disabled) {
683  return;
684  }
685 
686  PX4_DEBUG("Autosaving params");
687  int ret = param_save_default();
688 
689  if (ret != 0) {
690  PX4_ERR("param save failed (%i)", ret);
691  }
692 }
693 #endif /* PARAM_NO_AUTOSAVE */
694 
695 /**
696  * Automatically save the parameters after a timeout and limited rate.
697  *
698  * This needs to be called with the writer lock held (it's not necessary that it's the writer lock, but it
699  * needs to be the same lock as autosave_worker() and param_control_autosave() use).
700  */
701 static void
703 {
704 #ifndef PARAM_NO_AUTOSAVE
705 
707  return;
708  }
709 
710  // wait at least 300ms before saving, because:
711  // - tasks often call param_set() for multiple params, so this avoids unnecessary save calls
712  // - the logger stores changed params. He gets notified on a param change via uORB and then
713  // looks at all unsaved params.
714  hrt_abstime delay = 300 * 1000;
715 
716  const hrt_abstime rate_limit = 2000 * 1000; // rate-limit saving to 2 seconds
718 
719  if (last_save_elapsed < rate_limit && rate_limit > last_save_elapsed + delay) {
720  delay = rate_limit - last_save_elapsed;
721  }
722 
723  autosave_scheduled = true;
724  work_queue(LPWORK, &autosave_work, (worker_t)&autosave_worker, nullptr, USEC2TICK(delay));
725 #endif /* PARAM_NO_AUTOSAVE */
726 }
727 
728 void
730 {
731 #ifndef PARAM_NO_AUTOSAVE
733 
734  if (!enable && autosave_scheduled) {
735  work_cancel(LPWORK, &autosave_work);
736  autosave_scheduled = false;
737  }
738 
739  autosave_disabled = !enable;
741 #endif /* PARAM_NO_AUTOSAVE */
742 }
743 
744 static int
745 param_set_internal(param_t param, const void *val, bool mark_saved, bool notify_changes)
746 {
747  int result = -1;
748  bool params_changed = false;
749 
751  perf_begin(param_set_perf);
752 
753  if (param_values == nullptr) {
754  utarray_new(param_values, &param_icd);
755  }
756 
757  if (param_values == nullptr) {
758  PX4_ERR("failed to allocate modified values array");
759  goto out;
760  }
761 
762  if (handle_in_range(param)) {
763 
764  param_wbuf_s *s = param_find_changed(param);
765 
766  if (s == nullptr) {
767 
768  /* construct a new parameter */
769  param_wbuf_s buf = {};
770  buf.param = param;
771 
772  params_changed = true;
773 
774  /* add it to the array and sort */
777 
778  /* find it after sorting */
779  s = param_find_changed(param);
780  }
781 
782  /* update the changed value */
783  switch (param_type(param)) {
784 
785  case PARAM_TYPE_INT32:
786  params_changed = params_changed || s->val.i != *(int32_t *)val;
787  s->val.i = *(int32_t *)val;
788  break;
789 
790  case PARAM_TYPE_FLOAT:
791  params_changed = params_changed || fabsf(s->val.f - * (float *)val) > FLT_EPSILON;
792  s->val.f = *(float *)val;
793  break;
794 
796  if (s->val.p == nullptr) {
797  size_t psize = param_size(param);
798 
799  if (psize > 0) {
800  s->val.p = malloc(psize);
801 
802  } else {
803  s->val.p = nullptr;
804  }
805 
806  if (s->val.p == nullptr) {
807  PX4_ERR("failed to allocate parameter storage");
808  goto out;
809  }
810  }
811 
812  memcpy(s->val.p, val, param_size(param));
813  params_changed = true;
814  break;
815 
816  default:
817  goto out;
818  }
819 
820  s->unsaved = !mark_saved;
821  result = 0;
822 
823  if (!mark_saved) { // this is false when importing parameters
824  param_autosave();
825  }
826  }
827 
828 out:
829  perf_end(param_set_perf);
831 
832  /*
833  * If we set something, now that we have unlocked, go ahead and advertise that
834  * a thing has been set.
835  */
836 
837  if (!param_import_done) { notify_changes = 0; }
838 
839  if (params_changed && notify_changes) {
841  }
842 
843  if (result == 0 && !set_called_from_get) {
844  update_to_shmem(param, *(union param_value_u *)val);
845  }
846 
847 #ifdef ENABLE_SHMEM_DEBUG
848 
849  if (param_type(param) == PARAM_TYPE_INT32) {
850  PX4_INFO("param_set for %s : %d", param_name(param), ((union param_value_u *)val)->i);
851  }
852 
853  else if (param_type(param) == PARAM_TYPE_FLOAT) {
854  PX4_INFO("param_set for %s : %f", param_name(param), (double)((union param_value_u *)val)->f);
855  }
856 
857  else {
858  PX4_INFO("Unknown param type for %s", param_name(param));
859  }
860 
861 #endif
862 
863  return result;
864 }
865 
866 #if defined(FLASH_BASED_PARAMS)
867 int param_set_external(param_t param, const void *val, bool mark_saved, bool notify_changes)
868 {
869  return param_set_internal(param, val, mark_saved, notify_changes);
870 }
871 
873 {
874  return param_get_value_ptr(param);
875 }
876 #endif
877 
878 int
879 param_set(param_t param, const void *val)
880 {
881  return param_set_internal(param, val, false, true);
882 }
883 
884 int
886 {
887  return param_set_internal(param, val, false, false);
888 }
889 
890 bool
892 {
893  // TODO FIXME: for now all params are used
894  return true;
895 
896  int param_index = param_get_index(param);
897 
898  if (param_index < 0) {
899  return false;
900  }
901 
902  return param_changed_storage[param_index / bits_per_allocation_unit] &
903  (1 << param_index % bits_per_allocation_unit);
904 }
905 
907 {
909 }
910 
912 {
913  int param_index = param_get_index(param);
914 
915  if (param_index < 0) {
916  return;
917  }
918 
919  // FIXME: this needs locking too
921  (1 << param_index % bits_per_allocation_unit);
922 }
923 
924 int
926 {
927  param_wbuf_s *s = nullptr;
928  bool param_found = false;
929 
931 
932  if (handle_in_range(param)) {
933 
934  /* look for a saved value */
935  s = param_find_changed(param);
936 
937  /* if we found one, erase it */
938  if (s != nullptr) {
939  int pos = utarray_eltidx(param_values, s);
940  utarray_erase(param_values, pos, 1);
941  }
942 
943  param_found = true;
944  }
945 
946  param_autosave();
947 
949 
950  if (s != nullptr) {
952  }
953 
954  return (!param_found);
955 }
956 static void
958 {
960 
961  if (param_values != nullptr) {
963  }
964 
965  /* mark as reset / deleted */
966  param_values = nullptr;
967 
968  if (auto_save) {
969  param_autosave();
970  }
971 
973 
975 }
976 
977 void
979 {
981 }
982 
983 void
984 param_reset_excludes(const char *excludes[], int num_excludes)
985 {
986  param_t param;
987 
988  for (param = 0; handle_in_range(param); param++) {
989  const char *name = param_name(param);
990  bool exclude = false;
991 
992  for (int index = 0; index < num_excludes; index ++) {
993  int len = strlen(excludes[index]);
994 
995  if ((excludes[index][len - 1] == '*'
996  && strncmp(name, excludes[index], len - 1) == 0)
997  || strcmp(name, excludes[index]) == 0) {
998 
999  exclude = true;
1000  break;
1001  }
1002  }
1003 
1004  if (!exclude) {
1005  param_reset(param);
1006  }
1007  }
1008 
1010 }
1011 
1012 int
1013 param_set_default_file(const char *filename)
1014 {
1015  if (param_user_file != nullptr) {
1016  // we assume this is not in use by some other thread
1017  free(param_user_file);
1018  param_user_file = nullptr;
1019  }
1020 
1021  if (filename) {
1022  param_user_file = strdup(filename);
1023  }
1024 
1025  return 0;
1026 }
1027 
1028 const char *
1030 {
1031  return (param_user_file != nullptr) ? param_user_file : param_default_file;
1032 }
1033 
1034 int
1036 {
1037  int res = OK;
1038  int fd = -1;
1039 
1040  const char *filename = param_get_default_file();
1041 
1042  fd = PARAM_OPEN(filename, O_WRONLY | O_CREAT, PX4_O_MODE_666);
1043 
1044  if (fd < 0) {
1045  PX4_ERR("failed to open param file: %s", filename);
1046  goto do_exit;
1047  }
1048 
1049  res = param_export(fd, false);
1050 
1051  if (res != OK) {
1052  PX4_ERR("failed to write parameters to file: %s", filename);
1053  goto do_exit;
1054  }
1055 
1056  PARAM_CLOSE(fd);
1057 
1058 
1059  fd = -1;
1060 
1061 do_exit:
1062 
1063  if (fd >= 0) {
1064  close(fd);
1065  }
1066 
1067  if (res == OK) {
1068  PX4_DEBUG("saving params completed successfully");
1069  }
1070 
1071  return res;
1072 }
1073 
1074 /**
1075  * @return 0 on success, 1 if all params have not yet been stored, -1 if device open failed, -2 if writing parameters failed
1076  */
1077 int
1079 {
1080  int res = 0;
1081 #if !defined(FLASH_BASED_PARAMS)
1082  int fd_load = PARAM_OPEN(param_get_default_file(), O_RDONLY);
1083 
1084  if (fd_load < 0) {
1085  /* no parameter file is OK, otherwise this is an error */
1086  if (errno != ENOENT) {
1087  PX4_ERR("open '%s' for reading failed", param_get_default_file());
1088  return -1;
1089  }
1090 
1091  return 1;
1092  }
1093 
1094  int result = param_load(fd_load);
1095  PARAM_CLOSE(fd_load);
1096 
1097  if (result != 0) {
1098  PX4_ERR("error reading parameters from '%s'", param_get_default_file());
1099  return -2;
1100  }
1101 
1102 #else
1103  // no need for locking
1104  res = flash_param_load();
1105 #endif
1106  return res;
1107 }
1108 
1109 /**
1110  * @return 0 on success, 1 if all params have not yet been stored, -1 if device open failed, -2 if writing parameters failed
1111  */
1112 static int
1114 {
1115  int fd_load = open(param_get_default_file(), O_RDONLY);
1116 
1117  if (fd_load < 0) {
1118 #ifdef __PX4_QURT
1119  release_shmem_lock(__FILE__, __LINE__);
1120 #endif
1121 
1122  /* no parameter file is OK, otherwise this is an error */
1123  if (errno != ENOENT) {
1124  PX4_DEBUG("open '%s' for reading failed", param_get_default_file());
1125  return -1;
1126  }
1127 
1128  return 1;
1129  }
1130 
1131  int result = param_import(fd_load);
1132 
1133  close(fd_load);
1134 
1135  PX4_DEBUG("param loading done");
1136 
1137  if (result != 0) {
1138  PX4_WARN("error reading parameters from '%s'", param_get_default_file());
1139  return -2;
1140  }
1141 
1142  return 0;
1143 }
1144 
1145 int
1146 param_export(int fd, bool only_unsaved)
1147 {
1148  perf_begin(param_export_perf);
1149 
1150  param_wbuf_s *s = nullptr;
1151  int result = -1;
1152 
1153  struct bson_encoder_s encoder;
1154 
1155  int shutdown_lock_ret = px4_shutdown_lock();
1156 
1157  if (shutdown_lock_ret) {
1158  PX4_ERR("px4_shutdown_lock() failed (%i)", shutdown_lock_ret);
1159  }
1160 
1161  // take the file lock
1162  //do {} while (px4_sem_wait(&param_sem_save) != 0);
1163 
1165 
1166  bson_encoder_init_file(&encoder, fd);
1167 
1168  /* no modified parameters -> we are done */
1169  if (param_values == nullptr) {
1170  result = 0;
1171  goto out;
1172  }
1173 
1174  /* First of all, update the index which will call param_get for params
1175  * that have recently been changed. */
1176  update_index_from_shmem();
1177 
1178  while ((s = (struct param_wbuf_s *)utarray_next(param_values, s)) != nullptr) {
1179  /*
1180  * If we are only saving values changed since last save, and this
1181  * one hasn't, then skip it
1182  */
1183  if (only_unsaved && !s->unsaved) {
1184  continue;
1185  }
1186 
1187  s->unsaved = false;
1188 
1189  /* Make sure to get latest from shmem before saving. */
1190  update_from_shmem(s->param, &s->val);
1191 
1192  const char *name = param_name(s->param);
1193  const size_t size = param_size(s->param);
1194 
1195  /* append the appropriate BSON type object */
1196  switch (param_type(s->param)) {
1197 
1198  case PARAM_TYPE_INT32: {
1199  const int32_t i = s->val.i;
1200 
1201  PX4_DEBUG("exporting: %s (%d) size: %d val: %d", name, s->param, size, i);
1202 
1203  if (bson_encoder_append_int(&encoder, name, i)) {
1204  PX4_ERR("BSON append failed for '%s'", name);
1205  goto out;
1206  }
1207  }
1208  break;
1209 
1210  case PARAM_TYPE_FLOAT: {
1211  const double f = (double)s->val.f;
1212 
1213  PX4_DEBUG("exporting: %s (%d) size: %d val: %.3f", name, s->param, size, (double)f);
1214 
1215  if (bson_encoder_append_double(&encoder, name, f)) {
1216  PX4_ERR("BSON append failed for '%s'", name);
1217  goto out;
1218  }
1219  }
1220  break;
1221 
1223  const void *value_ptr = param_get_value_ptr(s->param);
1224 
1225  /* lock as short as possible */
1226  if (bson_encoder_append_binary(&encoder,
1227  name,
1229  size,
1230  value_ptr)) {
1231 
1232  PX4_ERR("BSON append failed for '%s'", name);
1233  goto out;
1234  }
1235  }
1236  break;
1237 
1238  default:
1239  PX4_ERR("unrecognized parameter type");
1240  goto out;
1241  }
1242  }
1243 
1244  result = 0;
1245 
1246 out:
1248 
1249  //px4_sem_post(&param_sem_save);
1250 
1251  fsync(fd); // make sure the data is flushed before releasing the shutdown lock
1252 
1253  if (shutdown_lock_ret == 0) {
1254  px4_shutdown_unlock();
1255  }
1256 
1257  if (result == 0) {
1258  result = bson_encoder_fini(&encoder);
1259  }
1260 
1261  perf_end(param_export_perf);
1262 
1263  return result;
1264 }
1265 
1266 struct param_import_state {
1267  bool mark_saved;
1268 };
1269 
1270 static int
1272 {
1273  float f = 0.0f;
1274  int32_t i = 0;
1275  void *tmp = nullptr;
1276  void *v = nullptr;
1277  int result = -1;
1279 
1280  /*
1281  * EOO means the end of the parameter object. (Currently not supporting
1282  * nested BSON objects).
1283  */
1284  if (node->type == BSON_EOO) {
1285  PX4_DEBUG("end of parameters");
1286  return 0;
1287  }
1288 
1289  /*
1290  * Find the parameter this node represents. If we don't know it,
1291  * ignore the node.
1292  */
1294 
1295  if (param == PARAM_INVALID) {
1296  PX4_ERR("ignoring unrecognised parameter '%s'", node->name);
1297  return 1;
1298  }
1299 
1300  /*
1301  * Handle setting the parameter from the node
1302  */
1303 
1304  switch (node->type) {
1305  case BSON_INT32: {
1306  if (param_type(param) != PARAM_TYPE_INT32) {
1307  PX4_WARN("unexpected type for %s", node->name);
1308  result = 1; // just skip this entry
1309  goto out;
1310  }
1311 
1312  i = node->i;
1313  v = &i;
1314 
1315  PX4_DEBUG("Imported %s with value %d", param_name(param), i);
1316  }
1317  break;
1318 
1319  case BSON_DOUBLE: {
1320  if (param_type(param) != PARAM_TYPE_FLOAT) {
1321  PX4_WARN("unexpected type for %s", node->name);
1322  result = 1; // just skip this entry
1323  goto out;
1324  }
1325 
1326  f = node->d;
1327  v = &f;
1328 
1329  PX4_DEBUG("Imported %s with value %f", param_name(param), (double)f);
1330  }
1331  break;
1332 
1333  case BSON_BINDATA: {
1334  if (node->subtype != BSON_BIN_BINARY) {
1335  PX4_WARN("unexpected subtype for %s", node->name);
1336  result = 1; // just skip this entry
1337  goto out;
1338  }
1339 
1340  if (bson_decoder_data_pending(decoder) != param_size(param)) {
1341  PX4_WARN("bad size for '%s'", node->name);
1342  result = 1; // just skip this entry
1343  goto out;
1344  }
1345 
1346  /* XXX check actual file data size? */
1347  size_t psize = param_size(param);
1348 
1349  if (psize > 0) {
1350  tmp = malloc(psize);
1351 
1352  } else {
1353  tmp = nullptr;
1354  }
1355 
1356  if (tmp == nullptr) {
1357  PX4_ERR("failed allocating for '%s'", node->name);
1358  goto out;
1359  }
1360 
1361  if (bson_decoder_copy_data(decoder, tmp)) {
1362  PX4_ERR("failed copying data for '%s'", node->name);
1363  goto out;
1364  }
1365 
1366  v = tmp;
1367  }
1368  break;
1369 
1370  default:
1371  PX4_DEBUG("unrecognised node type");
1372  goto out;
1373  }
1374 
1375  if (param_set_internal(param, v, state->mark_saved, true)) {
1376  PX4_DEBUG("error setting value for '%s'", node->name);
1377  goto out;
1378  }
1379 
1380  if (tmp != nullptr) {
1381  free(tmp);
1382  tmp = nullptr;
1383  }
1384 
1385  /* don't return zero, that means EOF */
1386  result = 1;
1387 
1388 out:
1389 
1390  if (tmp != nullptr) {
1391  free(tmp);
1392  }
1393 
1394  return result;
1395 }
1396 
1397 static int
1398 param_import_internal(int fd, bool mark_saved)
1399 {
1400  bson_decoder_s decoder;
1402  int result = -1;
1403 
1404  if (bson_decoder_init_file(&decoder, fd, param_import_callback, &state)) {
1405  PX4_ERR("decoder init failed");
1406  return PX4_ERROR;
1407  }
1408 
1409  state.mark_saved = mark_saved;
1410 
1411  do {
1412  result = bson_decoder_next(&decoder);
1413  usleep(1);
1414 
1415  } while (result > 0);
1416 
1417  return result;
1418 }
1419 
1420 int
1422 {
1423 #if !defined(FLASH_BASED_PARAMS)
1424  return param_import_internal(fd, false);
1425 #else
1426  (void)fd; // unused
1427  // no need for locking here
1428  return flash_param_import();
1429 #endif
1430 }
1431 
1432 int
1434 {
1435  param_reset_all_internal(false);
1436  return param_import_internal(fd, true);
1437 }
1438 
1439 void
1440 param_foreach(void (*func)(void *arg, param_t param), void *arg, bool only_changed, bool only_used)
1441 {
1442  param_t param;
1443 
1444  for (param = 0; handle_in_range(param); param++) {
1445 
1446  /* if requested, skip unchanged values */
1447  if (only_changed && (param_find_changed(param) == nullptr)) {
1448  continue;
1449  }
1450 
1451  if (only_used && !param_used(param)) {
1452  continue;
1453  }
1454 
1455  func(arg, param);
1456  }
1457 }
1458 
1460 {
1461  uint32_t param_hash = 0;
1462 
1464 
1465  /* compute the CRC32 over all string param names and 4 byte values */
1466  for (param_t param = 0; handle_in_range(param); param++) {
1468  continue;
1469  }
1470 
1471  const char *name = param_name(param);
1472  const void *val = param_get_value_ptr(param);
1473  param_hash = crc32part((const uint8_t *)name, strlen(name), param_hash);
1474  param_hash = crc32part((const uint8_t *)val, param_size(param), param_hash);
1475  }
1476 
1478 
1479  return param_hash;
1480 }
1481 
1483 {
1484  PX4_INFO("summary: %d/%d (used/total)", param_count_used(), param_count());
1485 
1486 #ifndef FLASH_BASED_PARAMS
1487  const char *filename = param_get_default_file();
1488 
1489  if (filename != nullptr) {
1490  PX4_INFO("file: %s", param_get_default_file());
1491  }
1492 
1493 #endif /* FLASH_BASED_PARAMS */
1494 
1495  if (param_values != nullptr) {
1496  PX4_INFO("storage array: %d/%d elements (%zu bytes total)",
1498  }
1499 
1500 #ifndef PARAM_NO_AUTOSAVE
1501  PX4_INFO("auto save: %s", autosave_disabled ? "off" : "on");
1502 
1504  PX4_INFO("last auto save: %.3f seconds ago", hrt_elapsed_time(&last_autosave_timestamp) * 1e-6);
1505  }
1506 
1507 #endif /* PARAM_NO_AUTOSAVE */
1508 
1509  perf_print_counter(param_export_perf);
1510  perf_print_counter(param_find_perf);
1511  perf_print_counter(param_get_perf);
1512  perf_print_counter(param_set_perf);
1513 }
1514 
1516 {
1517 #ifdef __PX4_QURT
1518  //copy params to shared memory
1519  init_shared_memory();
1520 #endif
1521 
1522  /*load params automatically*/
1523 #ifdef __PX4_POSIX
1525 #endif
1526 
1527  param_import_done = 1;
1528 
1529 #ifdef __PX4_QURT
1530  copy_params_to_shmem(param_info_base);
1531 
1532 #ifdef ENABLE_SHMEM_DEBUG
1533  PX4_INFO("Offsets:");
1534  PX4_INFO("params_val %lu, krait_changed %lu, adsp_changed %lu",
1535  (unsigned char *)shmem_info_p->params_val - (unsigned char *)shmem_info_p,
1536  (unsigned char *)&shmem_info_p->krait_changed_index - (unsigned char *)shmem_info_p,
1537  (unsigned char *)&shmem_info_p->adsp_changed_index - (unsigned char *)shmem_info_p);
1538 #endif /* ENABLE_SHMEM_DEBUG */
1539 
1540 #endif /* __PX4_QURT */
1541 }
static void param_lock_writer()
lock the parameter store for write access
#define PARAM_CLOSE
#define PARAM_INVALID
Handle returned when a parameter cannot be found.
Definition: param.h:103
#define utarray_find(a, v, cmp)
Definition: utarray.h:212
static int param_import_callback(bson_decoder_t decoder, void *priv, bson_node_t node)
void param_set_used(param_t param)
Mark a parameter as used.
param_type_t type
Definition: param.h:446
void param_control_autosave(bool enable)
Enable/disable the param autosaving.
char name[BSON_MAXNAME]
Definition: tinybson.h:85
static int param_import_internal(int fd, bool mark_saved)
static unsigned int param_instance
const UT_icd param_icd
array info for the modified parameters array
static char * param_user_file
uint32_t param_hash_check()
Generate the hash of all parameters and their values.
int param_import(int fd)
Import parameters from a file, discarding any unrecognized parameters.
bool param_value_unsaved(param_t param)
Test whether a parameter&#39;s value has been changed but not saved.
int param_reset(param_t param)
Reset a parameter to its default value.
int bson_decoder_next(bson_decoder_t decoder)
Process the next node from the stream and invoke the callback.
Definition: tinybson.cpp:180
#define PARAM_TYPE_UNKNOWN
Definition: param.h:64
measure the time elapsed performing an event
Definition: perf_counter.h:56
uint16_t volatile_param
Definition: param.h:447
static enum @74 state
#define PARAM_TYPE_INT32
Parameter types.
Definition: param.h:60
int bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size, const void *data)
Append a binary blob to the encoded stream.
Definition: tinybson.cpp:614
static void param_lock_reader()
< we use a separate lock to allow concurrent param reads and saves.
const char * name
Definition: param.h:444
API for the uORB lightweight object broker.
int bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *priv)
Initialise the decoder to read from a file.
Definition: tinybson.cpp:114
const char * param_name(param_t param)
Obtain the name of a parameter.
param_t param_find_no_notification(const char *name)
Look up a parameter by name.
static const param_info_s * param_info_base
Array of static parameter info.
#define PARAM_TYPE_STRUCT
Definition: param.h:62
int param_export(int fd, bool only_unsaved)
Export changed parameters to a file.
uint16_t param_type_t
Definition: param.h:66
Storage for modified parameters.
Definition: flashparams.cpp:71
static void param_reset_all_internal(bool auto_save)
bson_binary_subtype_t subtype
Definition: tinybson.h:87
param_t param_for_used_index(unsigned index)
Look up an used parameter by index.
__EXPORT int param_set_external(param_t param, const void *val, bool mark_saved, bool notify_changes)
#define utarray_sort(a, cmp)
Definition: utarray.h:208
static unsigned get_param_info_count()
Encoder state structure.
Definition: tinybson.h:173
static const void * param_get_value_ptr(param_t param)
Obtain a pointer to the storage allocated for a parameter.
union param_value_u val
Definition: flashparams.cpp:72
orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
Definition: uORB.cpp:43
int param_set_default_file(const char *filename)
Set the default parameter file name.
param_type_t param_type(param_t param)
Obtain the type of a parameter.
#define utarray_free(a)
Definition: utarray.h:84
int param_load_default()
Load parameters from the default parameter file.
__EXPORT const void * param_get_value_ptr_external(param_t param)
int bson_decoder_copy_data(bson_decoder_t decoder, void *buf)
Copy node data.
Definition: tinybson.cpp:312
void param_init()
Initialize the param backend.
static void param_unlock_writer()
unlock the parameter store
#define FLT_EPSILON
High-resolution timer with callouts and timekeeping.
int32_t i
Definition: param.h:418
void param_notify_changes()
Notify the system about parameter changes.
int size_param_changed_storage_bytes
Node structure passed to the callback.
Definition: tinybson.h:84
param_t param_for_index(unsigned index)
Look up a parameter by index.
void * p
Definition: param.h:417
A simple subset SAX-style BSON parser and generator.
static void param_unlock_reader()
unlock the parameter store
Global flash based parameter store.
void param_reset_excludes(const char *excludes[], int num_excludes)
Reset all parameters to their default values except for excluded parameters.
int bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value)
Append a double to the encoded stream.
Definition: tinybson.cpp:580
Static parameter definition structure.
Definition: param.h:428
int flash_param_load()
static int param_import_done
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
param_wbuf_s * param_find_changed(param_t param)
Locate the modified parameter structure for a parameter, if it exists.
int param_set(param_t param, const void *val)
Set the value of a parameter.
int flash_param_import()
static void _param_notify_changes()
Parameter value union.
Definition: param.h:416
Header common to all counters.
UT_array * param_values
flexible array holding modified parameter values
static bool autosave_disabled
static int reader_lock_holders
Definition: parameters.cpp:163
#define perf_alloc(a, b)
Definition: px4io.h:59
static int param_set_internal(param_t param, const void *val, bool mark_saved, bool notify_changes)
#define utarray_erase(a, pos, len)
Definition: utarray.h:177
static perf_counter_t param_find_perf
static void init_params()
int param_set_no_notification(param_t param, const void *val)
Set the value of a parameter, but do not notify the system about the change.
#define utarray_new(a, _icd)
Definition: utarray.h:79
static px4_sem_t param_sem
this protects against concurrent access to param_values
Definition: parameters.cpp:162
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
size_t bson_decoder_data_pending(bson_decoder_t decoder)
Report copyable data size.
Definition: tinybson.cpp:331
#define PARAM_TYPE_STRUCT_MAX
Definition: param.h:63
bool param_value_is_default(param_t param)
Test whether a parameter&#39;s value has changed from the default.
#define utarray_next(a, e)
Definition: utarray.h:215
void param_print_status()
Print the status of the param system.
void perf_end(perf_counter_t handle)
End a performance event.
bool handle_in_range(param_t param)
Test whether a param_t is value.
unsigned n
Definition: utarray.h:56
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
int param_save_default()
Save parameters to the default file.
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
Definition: uORB.h:134
int fd
Definition: dataman.cpp:146
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
int bson_encoder_fini(bson_encoder_t encoder)
Finalise the encoded stream.
Definition: tinybson.cpp:484
static perf_counter_t param_get_perf
bool param_used(param_t param)
Wether a parameter is in use in the system.
bson_type_t type
Definition: tinybson.h:86
const char * name
Definition: tests_main.c:58
const char * param_get_default_file()
Get the default parameter file name.
#define PARAM_TYPE_FLOAT
Definition: param.h:61
static unsigned char set_called_from_get
int param_load(int fd)
Load parameters from a file.
int param_get(param_t param, void *val)
Copy the value of a parameter.
const int bits_per_allocation_unit
int param_get_index(param_t param)
Look up the index of a parameter.
static param_t param_find_internal(const char *name, bool notification)
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
size_t param_size(param_t param)
Determine the size of a parameter.
float f
Definition: param.h:419
unsigned param_count_used()
Return the actually used number of parameters.
union param_value_u val
Definition: param.h:448
static orb_advert_t param_topic
parameter update topic handle
int bson_encoder_init_file(bson_encoder_t encoder, int fd)
Initialze the encoder for writing to a file.
Definition: tinybson.cpp:429
param_t param
Definition: flashparams.cpp:73
#define utarray_len(a)
Definition: utarray.h:114
void param_reset_all()
Reset all parameters to their default values.
static perf_counter_t param_set_perf
void param_foreach(void(*func)(void *arg, param_t param), void *arg, bool only_changed, bool only_used)
Apply a function to each parameter.
static void param_assert_locked()
assert that the parameter store is locked
static hrt_abstime last_autosave_timestamp
Definition: utarray.h:48
static const char * param_default_file
#define OK
Definition: uavcan_main.cpp:71
static perf_counter_t param_export_perf
param_t param_find(const char *name)
Look up a parameter by name.
int64_t i
Definition: tinybson.h:89
int param_get_used_index(param_t param)
Look up the index of an used parameter.
static bool autosave_scheduled
#define param_info_count
static void param_autosave()
Automatically save the parameters after a timeout and limited rate.
uint8_t * param_changed_storage
static void param_set_used_internal(param_t param)
static px4_sem_t reader_lock_holders_lock
this protects against concurrent access to reader_lock_holders
Definition: parameters.cpp:164
static void autosave_worker(void *arg)
worker callback method to save the parameters
#define utarray_eltidx(a, e)
Definition: utarray.h:218
void perf_begin(perf_counter_t handle)
Begin a performance event.
unsigned param_count()
Return the total number of parameters.
double d
Definition: tinybson.h:90
int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value)
Append an integer to the encoded stream.
Definition: tinybson.cpp:552
static int param_compare_values(const void *a, const void *b)
Compare two modifid parameter structures to determine ordering.
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
static int param_load_default_no_notify()
uint32_t param_t
Parameter handle.
Definition: param.h:98
#define utarray_push_back(a, p)
Definition: utarray.h:96
#define PARAM_OPEN
bool param_is_volatile(param_t param)
Obtain the volatile state of a parameter.
Performance measuring tools.