2012-08-19 22:15:29 -07:00
|
|
|
/****************************************************************************
|
|
|
|
|
*
|
2015-02-08 16:39:37 +01:00
|
|
|
* Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
|
2012-08-19 22:15:29 -07:00
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
|
* are met:
|
|
|
|
|
*
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
|
* distribution.
|
|
|
|
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
|
|
|
|
* used to endorse or promote products derived from this software
|
|
|
|
|
* without specific prior written permission.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
/**
|
|
|
|
|
* @file param.c
|
|
|
|
|
*
|
|
|
|
|
* Global parameter store.
|
2012-08-20 21:17:50 -07:00
|
|
|
*
|
|
|
|
|
* Note that it might make sense to convert this into a driver. That would
|
|
|
|
|
* offer some interesting options regarding state for e.g. ORB advertisements
|
|
|
|
|
* and background parameter saving.
|
2012-08-18 22:04:32 -07:00
|
|
|
*/
|
|
|
|
|
|
2015-03-11 16:45:19 -07:00
|
|
|
//#include <debug.h>
|
|
|
|
|
#include <px4_defines.h>
|
2015-05-06 22:12:45 -07:00
|
|
|
#include <px4_posix.h>
|
2016-01-23 13:23:53 +01:00
|
|
|
#include <px4_config.h>
|
2012-08-18 22:04:32 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdbool.h>
|
2016-09-26 23:16:46 +02:00
|
|
|
#include <float.h>
|
2015-05-14 16:44:55 -10:00
|
|
|
#include <stdlib.h>
|
2012-08-19 01:30:55 -07:00
|
|
|
#include <fcntl.h>
|
2012-08-18 22:04:32 -07:00
|
|
|
#include <unistd.h>
|
2013-04-28 09:54:11 +02:00
|
|
|
#include <systemlib/err.h>
|
2012-10-31 16:31:21 +01:00
|
|
|
#include <errno.h>
|
2017-02-16 17:51:29 +01:00
|
|
|
#include <px4_sem.h>
|
Clean up of px4_defines.h (remove math.h)
This patch reorders px4_defines.h to make it more readable (I think)
but more importantly, cleans up the #include <math.h>/<cmath>
and [std::]isfinite stuff.
My main goal was to completely get rid of including math.h/cmath,
because that doesn't really belong in a header that is supposed to
define macro's and is included in almost every source file (if not
all).
I'm not sure what it did before ;) (pun intended), but now it does
the following:
PX4_ISFINITE is only used in C++ code (that was already the case,
but hereby is official; for C code just use 'isfinite()') and is
defined to be std::isfinite, except on __PX4_QURT because that uses
the HEXAGON toolset which (erroneously) defines isfinite as macro.
I would have liked to remove PX4_ISFINITE completely from the code
and just use std::isfinite whereever that is needed, but that would
have required changing the libecl submodule, and at the moment I'm
getting tired of changing submodules... so maybe something for the
future.
Also, all includes of <math.h> or <cmath> have been removed except
for __PX4_NUTTX. Like the HEXAGON toolset NuttX currently defines
isfinite as macro for C++. So, we could have solved this in the
same was as __P4_QURT; but since we can fix NuttX ourselves I chose
to add a kludge to px4_defines.h instead that fixes this problem,
until the time that NuttX can be fixed (again postponing changing
a submodule). The kludge still demands including <cmath>, thus.
After removal of the math header file, it needed to be included
in source files that actually need it, of course.
Finally, I had a look at the math macro's (like M_PI, M_PI_F,
M_DEG_TO_RAD etc). These are sometimes (erroneously) defined in
certain math.h header files (like both, hexagon and nuttx).
This is incorrect: neither the C nor the C++ standard defines
math constants (neither as macro nor otherwise). The "problem"
here was that px4_defines.h defined some of the M_*_F float
constants in terms of the M_* double constant, which are
sometimes not defined either thus. So, I cleaned this up by
defining the M_*_F math constants as float literals in px4_defines.h,
except when they are defined in math.h for that platform.
This means that math.h has to be always included when using those
constants, but well; not much difference there as those files
usually also need/use the macro NAN (which *is* a standard macro
defined by math.h).
Finally finally, DEFAULT_PARAM_FILE was removed as it isn't
used anymore.
All in all I think the resulting px4_defines.h is nice, giving me
much less the feeling of a nearly unmaintainable and over time
slowly growing collection of kludges and hacks.
2016-10-24 18:05:04 +02:00
|
|
|
#include <math.h>
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2012-10-23 18:02:36 -07:00
|
|
|
#include <drivers/drv_hrt.h>
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
#include "systemlib/param/param.h"
|
|
|
|
|
#include "systemlib/uthash/utarray.h"
|
2012-08-20 01:52:39 -07:00
|
|
|
#include "systemlib/bson/tinybson.h"
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2016-07-11 10:51:42 -10:00
|
|
|
#if !defined(PARAM_NO_ORB)
|
|
|
|
|
# include "uORB/uORB.h"
|
|
|
|
|
# include "uORB/topics/parameter_update.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if !defined(FLASH_BASED_PARAMS)
|
|
|
|
|
# define FLASH_PARAMS_EXPOSE
|
|
|
|
|
#else
|
|
|
|
|
# include "systemlib/flashparams/flashparams.h"
|
|
|
|
|
#endif
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2016-07-11 10:51:42 -10:00
|
|
|
#include "px4_parameters.h"
|
2015-10-12 13:36:37 -04:00
|
|
|
#include <crc32.h>
|
|
|
|
|
|
2016-07-11 10:51:42 -10:00
|
|
|
|
2014-01-12 18:52:10 +01:00
|
|
|
#if 0
|
2012-08-19 22:15:29 -07:00
|
|
|
# define debug(fmt, args...) do { warnx(fmt, ##args); } while(0)
|
|
|
|
|
#else
|
|
|
|
|
# define debug(fmt, args...) do { } while(0)
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-05-19 13:36:13 -07:00
|
|
|
#ifdef __PX4_QURT
|
|
|
|
|
#define PARAM_OPEN px4_open
|
|
|
|
|
#define PARAM_CLOSE px4_close
|
|
|
|
|
#else
|
|
|
|
|
#define PARAM_OPEN open
|
|
|
|
|
#define PARAM_CLOSE close
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
#include <px4_workqueue.h>
|
|
|
|
|
/* autosaving variables */
|
|
|
|
|
static hrt_abstime last_autosave_timestamp = 0;
|
|
|
|
|
struct work_s autosave_work;
|
|
|
|
|
static bool autosave_scheduled = false;
|
|
|
|
|
static bool autosave_disabled = false;
|
|
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
/**
|
|
|
|
|
* Array of static parameter info.
|
|
|
|
|
*/
|
2015-02-03 10:35:20 +01:00
|
|
|
#ifdef _UNIT_TEST
|
2015-05-15 03:58:04 -10:00
|
|
|
extern struct param_info_s param_array[];
|
|
|
|
|
extern struct param_info_s *param_info_base;
|
|
|
|
|
extern struct param_info_s *param_info_limit;
|
2016-04-24 18:18:32 -04:00
|
|
|
#define param_info_count (param_info_limit - param_info_base)
|
2015-02-03 10:35:20 +01:00
|
|
|
#else
|
2015-10-06 15:26:19 -04:00
|
|
|
static const struct param_info_s *param_info_base = (const struct param_info_s *) &px4_parameters;
|
2015-09-11 12:41:00 -07:00
|
|
|
#define param_info_count px4_parameters.param_count
|
2016-04-24 18:18:32 -04:00
|
|
|
#endif /* _UNIT_TEST */
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
/**
|
|
|
|
|
* Storage for modified parameters.
|
|
|
|
|
*/
|
2012-08-19 22:15:29 -07:00
|
|
|
struct param_wbuf_s {
|
2012-08-19 01:30:55 -07:00
|
|
|
union param_value_u val;
|
2017-03-13 11:06:40 +01:00
|
|
|
param_t param;
|
2012-08-19 01:30:55 -07:00
|
|
|
bool unsaved;
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-14 12:36:40 -10:00
|
|
|
|
2017-02-16 17:51:29 +01:00
|
|
|
uint8_t *param_changed_storage = NULL;
|
2015-05-14 12:36:40 -10:00
|
|
|
int size_param_changed_storage_bytes = 0;
|
|
|
|
|
const int bits_per_allocation_unit = (sizeof(*param_changed_storage) * 8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
get_param_info_count(void)
|
|
|
|
|
{
|
2015-05-15 03:58:04 -10:00
|
|
|
/* Singleton creation of and array of bits to track changed values */
|
|
|
|
|
if (!param_changed_storage) {
|
2017-02-16 17:51:29 +01:00
|
|
|
/* Note that we have a (highly unlikely) race condition here: in the worst case the allocation is done twice */
|
2015-05-15 03:58:04 -10:00
|
|
|
size_param_changed_storage_bytes = (param_info_count / bits_per_allocation_unit) + 1;
|
|
|
|
|
param_changed_storage = calloc(size_param_changed_storage_bytes, 1);
|
2015-06-01 15:06:44 -10:00
|
|
|
|
|
|
|
|
/* If the allocation fails we need to indicate failure in the
|
|
|
|
|
* API by returning PARAM_INVALID
|
|
|
|
|
*/
|
|
|
|
|
if (param_changed_storage == NULL) {
|
2015-06-03 22:51:02 +02:00
|
|
|
return 0;
|
2015-06-01 15:06:44 -10:00
|
|
|
}
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return param_info_count;
|
2015-05-14 12:36:40 -10:00
|
|
|
}
|
2015-03-21 22:01:28 +01:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/** flexible array holding modified parameter values */
|
2016-07-11 10:51:42 -10:00
|
|
|
FLASH_PARAMS_EXPOSE UT_array *param_values;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/** array info for the modified parameters array */
|
2016-07-11 10:51:42 -10:00
|
|
|
FLASH_PARAMS_EXPOSE const UT_icd param_icd = {sizeof(struct param_wbuf_s), NULL, NULL, NULL};
|
|
|
|
|
|
|
|
|
|
#if !defined(PARAM_NO_ORB)
|
2012-08-22 01:09:06 -07:00
|
|
|
/** parameter update topic handle */
|
2015-05-25 22:21:23 -07:00
|
|
|
static orb_advert_t param_topic = NULL;
|
2016-07-11 10:51:42 -10:00
|
|
|
#endif
|
2012-08-22 01:09:06 -07:00
|
|
|
|
2015-03-21 22:01:28 +01:00
|
|
|
static void param_set_used_internal(param_t param);
|
|
|
|
|
|
|
|
|
|
static param_t param_find_internal(const char *name, bool notification);
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
// the following implements an RW-lock using 2 semaphores (used as mutexes). It gives
|
|
|
|
|
// priority to readers, meaning a writer could suffer from starvation, but in our use-case
|
|
|
|
|
// we only have short periods of reads and writes are rare.
|
2017-02-17 10:39:52 +01:00
|
|
|
static px4_sem_t param_sem; ///< this protects against concurrent access to param_values and param save
|
2017-03-13 11:05:18 +01:00
|
|
|
static int reader_lock_holders = 0;
|
|
|
|
|
static px4_sem_t reader_lock_holders_lock; ///< this protects against concurrent access to reader_lock_holders
|
2017-02-16 17:51:29 +01:00
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
/** lock the parameter store for read access */
|
2012-08-19 01:30:55 -07:00
|
|
|
static void
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader(void)
|
|
|
|
|
{
|
|
|
|
|
do {} while (px4_sem_wait(&reader_lock_holders_lock) != 0);
|
|
|
|
|
|
|
|
|
|
++reader_lock_holders;
|
|
|
|
|
|
|
|
|
|
if (reader_lock_holders == 1) {
|
|
|
|
|
// the first reader takes the lock, the next ones are allowed to just continue
|
|
|
|
|
do {} while (px4_sem_wait(¶m_sem) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
px4_sem_post(&reader_lock_holders_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** lock the parameter store for write access */
|
|
|
|
|
static void
|
|
|
|
|
param_lock_writer(void)
|
2012-08-19 01:30:55 -07:00
|
|
|
{
|
2017-02-16 17:51:29 +01:00
|
|
|
do {} while (px4_sem_wait(¶m_sem) != 0);
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/** unlock the parameter store */
|
2012-08-19 01:30:55 -07:00
|
|
|
static void
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader(void)
|
|
|
|
|
{
|
|
|
|
|
do {} while (px4_sem_wait(&reader_lock_holders_lock) != 0);
|
|
|
|
|
|
|
|
|
|
--reader_lock_holders;
|
|
|
|
|
|
|
|
|
|
if (reader_lock_holders == 0) {
|
|
|
|
|
// the last reader releases the lock
|
|
|
|
|
px4_sem_post(¶m_sem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
px4_sem_post(&reader_lock_holders_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** unlock the parameter store */
|
|
|
|
|
static void
|
|
|
|
|
param_unlock_writer(void)
|
2012-08-19 01:30:55 -07:00
|
|
|
{
|
2017-02-16 17:51:29 +01:00
|
|
|
px4_sem_post(¶m_sem);
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/** assert that the parameter store is locked */
|
2012-08-19 01:30:55 -07:00
|
|
|
static void
|
|
|
|
|
param_assert_locked(void)
|
|
|
|
|
{
|
|
|
|
|
/* XXX */
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-16 17:51:29 +01:00
|
|
|
void
|
|
|
|
|
param_init(void)
|
|
|
|
|
{
|
|
|
|
|
px4_sem_init(¶m_sem, 0, 1);
|
2017-03-13 11:05:18 +01:00
|
|
|
px4_sem_init(&reader_lock_holders_lock, 0, 1);
|
2017-02-16 17:51:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/**
|
|
|
|
|
* Test whether a param_t is value.
|
|
|
|
|
*
|
|
|
|
|
* @param param The parameter handle to test.
|
|
|
|
|
* @return True if the handle is valid.
|
|
|
|
|
*/
|
2012-08-18 22:04:32 -07:00
|
|
|
static bool
|
2012-08-19 22:15:29 -07:00
|
|
|
handle_in_range(param_t param)
|
2012-08-18 22:04:32 -07:00
|
|
|
{
|
2016-05-19 00:19:09 -04:00
|
|
|
unsigned count = get_param_info_count();
|
2015-06-01 15:06:44 -10:00
|
|
|
return (count && param < count);
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/**
|
|
|
|
|
* Compare two modifid parameter structures to determine ordering.
|
|
|
|
|
*
|
|
|
|
|
* This function is suitable for passing to qsort or bsearch.
|
|
|
|
|
*/
|
2012-08-19 01:30:55 -07:00
|
|
|
static int
|
|
|
|
|
param_compare_values(const void *a, const void *b)
|
|
|
|
|
{
|
|
|
|
|
struct param_wbuf_s *pa = (struct param_wbuf_s *)a;
|
|
|
|
|
struct param_wbuf_s *pb = (struct param_wbuf_s *)b;
|
|
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (pa->param < pb->param) {
|
2012-08-19 01:30:55 -07:00
|
|
|
return -1;
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (pa->param > pb->param) {
|
2012-08-19 01:30:55 -07:00
|
|
|
return 1;
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/**
|
|
|
|
|
* Locate the modified parameter structure for a parameter, if it exists.
|
|
|
|
|
*
|
|
|
|
|
* @param param The parameter being searched.
|
|
|
|
|
* @return The structure holding the modified value, or
|
|
|
|
|
* NULL if the parameter has not been modified.
|
|
|
|
|
*/
|
2012-08-19 01:30:55 -07:00
|
|
|
static struct param_wbuf_s *
|
2015-05-15 03:58:04 -10:00
|
|
|
param_find_changed(param_t param)
|
|
|
|
|
{
|
2012-08-19 01:30:55 -07:00
|
|
|
struct param_wbuf_s *s = NULL;
|
|
|
|
|
|
|
|
|
|
param_assert_locked();
|
|
|
|
|
|
|
|
|
|
if (param_values != NULL) {
|
|
|
|
|
struct param_wbuf_s key;
|
|
|
|
|
key.param = param;
|
|
|
|
|
s = utarray_find(param_values, &key, param_compare_values);
|
|
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-28 22:15:25 -07:00
|
|
|
static void
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes(void)
|
2012-08-28 22:15:25 -07:00
|
|
|
{
|
2016-07-11 10:51:42 -10:00
|
|
|
#if !defined(PARAM_NO_ORB)
|
|
|
|
|
struct parameter_update_s pup = {
|
|
|
|
|
.timestamp = hrt_absolute_time(),
|
2017-03-24 16:59:51 +01:00
|
|
|
.dummy = 0
|
2016-07-11 10:51:42 -10:00
|
|
|
};
|
2012-08-28 22:15:25 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we don't have a handle to our topic, create one now; otherwise
|
|
|
|
|
* just publish.
|
|
|
|
|
*/
|
2015-05-25 22:21:23 -07:00
|
|
|
if (param_topic == NULL) {
|
2012-08-28 22:15:25 -07:00
|
|
|
param_topic = orb_advertise(ORB_ID(parameter_update), &pup);
|
2012-10-23 23:38:45 -07:00
|
|
|
|
2012-08-28 22:15:25 -07:00
|
|
|
} else {
|
|
|
|
|
orb_publish(ORB_ID(parameter_update), param_topic, &pup);
|
|
|
|
|
}
|
2016-07-11 10:51:42 -10:00
|
|
|
|
|
|
|
|
#endif
|
2012-08-28 22:15:25 -07:00
|
|
|
}
|
|
|
|
|
|
2017-02-03 10:31:31 +01:00
|
|
|
void
|
|
|
|
|
param_notify_changes(void)
|
|
|
|
|
{
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes();
|
2017-02-03 10:31:31 +01:00
|
|
|
}
|
|
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
param_t
|
2015-03-21 22:01:28 +01:00
|
|
|
param_find_internal(const char *name, bool notification)
|
2012-08-18 22:04:32 -07:00
|
|
|
{
|
2017-01-04 13:22:56 -08:00
|
|
|
param_t middle;
|
|
|
|
|
param_t front = 0;
|
2017-01-05 12:02:39 -08:00
|
|
|
param_t last = get_param_info_count();
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
/* perform a binary search of the known parameters */
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
while (front <= last) {
|
2017-01-04 14:45:39 -08:00
|
|
|
middle = front + (last - front) / 2;
|
2017-01-04 13:22:56 -08:00
|
|
|
int ret = strcmp(name, param_info_base[middle].name);
|
2017-01-04 14:45:39 -08:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
if (ret == 0) {
|
2015-06-03 22:51:02 +02:00
|
|
|
if (notification) {
|
2017-01-04 13:22:56 -08:00
|
|
|
param_set_used_internal(middle);
|
2015-06-03 22:51:02 +02:00
|
|
|
}
|
2017-01-04 14:45:39 -08:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
return middle;
|
2017-01-04 14:45:39 -08:00
|
|
|
|
2017-01-05 12:02:39 -08:00
|
|
|
} else if (middle == front) {
|
2017-01-04 13:22:56 -08:00
|
|
|
/* An end point has been hit, but there has been no match */
|
|
|
|
|
break;
|
2017-01-04 14:45:39 -08:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
} else if (ret < 0) {
|
2017-01-04 15:45:02 -08:00
|
|
|
last = middle;
|
2017-01-04 14:45:39 -08:00
|
|
|
|
2017-01-04 13:22:56 -08:00
|
|
|
} else {
|
2017-01-04 14:45:39 -08:00
|
|
|
front = middle;
|
2015-06-03 22:51:02 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2015-06-03 22:51:02 +02:00
|
|
|
/* not found */
|
2012-08-18 22:04:32 -07:00
|
|
|
return PARAM_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-21 22:01:28 +01:00
|
|
|
param_t
|
|
|
|
|
param_find(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return param_find_internal(name, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_t
|
|
|
|
|
param_find_no_notification(const char *name)
|
|
|
|
|
{
|
|
|
|
|
return param_find_internal(name, false);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
unsigned
|
|
|
|
|
param_count(void)
|
|
|
|
|
{
|
2015-05-14 12:36:40 -10:00
|
|
|
return get_param_info_count();
|
2012-08-19 22:15:29 -07:00
|
|
|
}
|
|
|
|
|
|
2015-03-22 23:15:59 -07:00
|
|
|
unsigned
|
|
|
|
|
param_count_used(void)
|
|
|
|
|
{
|
2015-06-03 22:51:02 +02:00
|
|
|
unsigned count = 0;
|
|
|
|
|
|
|
|
|
|
// ensure the allocation has been done
|
|
|
|
|
if (get_param_info_count()) {
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < size_param_changed_storage_bytes; i++) {
|
|
|
|
|
for (unsigned j = 0; j < bits_per_allocation_unit; j++) {
|
|
|
|
|
if (param_changed_storage[i] & (1 << j)) {
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
2015-03-22 23:15:59 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
param_t
|
|
|
|
|
param_for_index(unsigned index)
|
|
|
|
|
{
|
2015-06-03 22:51:02 +02:00
|
|
|
unsigned count = get_param_info_count();
|
|
|
|
|
|
2015-06-01 15:06:44 -10:00
|
|
|
if (count && index < count) {
|
2012-08-19 22:15:29 -07:00
|
|
|
return (param_t)index;
|
2015-04-26 14:01:42 +02:00
|
|
|
}
|
2015-06-03 22:51:02 +02:00
|
|
|
|
2015-04-26 14:01:42 +02:00
|
|
|
return PARAM_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_t
|
|
|
|
|
param_for_used_index(unsigned index)
|
|
|
|
|
{
|
2015-06-03 22:51:02 +02:00
|
|
|
int count = get_param_info_count();
|
|
|
|
|
|
|
|
|
|
if (count && index < count) {
|
2015-06-25 09:28:04 +02:00
|
|
|
/* walk all params and count used params */
|
|
|
|
|
unsigned used_count = 0;
|
2015-04-26 14:01:42 +02:00
|
|
|
|
2015-05-15 09:11:28 +02:00
|
|
|
for (unsigned i = 0; i < (unsigned)size_param_changed_storage_bytes; i++) {
|
2015-05-18 13:51:21 -10:00
|
|
|
for (unsigned j = 0; j < bits_per_allocation_unit; j++) {
|
2015-04-26 14:01:42 +02:00
|
|
|
if (param_changed_storage[i] & (1 << j)) {
|
|
|
|
|
|
|
|
|
|
/* we found the right used count,
|
|
|
|
|
* return the param value
|
|
|
|
|
*/
|
2015-06-25 09:28:04 +02:00
|
|
|
if (index == used_count) {
|
2015-05-18 13:51:21 -10:00
|
|
|
return (param_t)(i * bits_per_allocation_unit + j);
|
2015-04-26 14:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 09:28:04 +02:00
|
|
|
used_count++;
|
2015-04-26 14:01:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
|
|
|
|
return PARAM_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-20 09:07:33 +02:00
|
|
|
int
|
|
|
|
|
param_get_index(param_t param)
|
|
|
|
|
{
|
2015-04-27 09:03:35 +02:00
|
|
|
if (handle_in_range(param)) {
|
2012-08-20 09:07:33 +02:00
|
|
|
return (unsigned)param;
|
2015-04-27 09:03:35 +02:00
|
|
|
}
|
2012-08-20 09:07:33 +02:00
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-22 23:15:59 -07:00
|
|
|
int
|
|
|
|
|
param_get_used_index(param_t param)
|
|
|
|
|
{
|
2015-05-17 22:58:52 +02:00
|
|
|
/* this tests for out of bounds and does a constant time lookup */
|
|
|
|
|
if (!param_used(param)) {
|
2015-03-22 23:15:59 -07:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-17 22:58:52 +02:00
|
|
|
/* walk all params and count, now knowing that it has a valid index */
|
2015-06-25 09:28:04 +02:00
|
|
|
int used_count = 0;
|
2015-03-22 23:15:59 -07:00
|
|
|
|
2015-05-17 22:58:52 +02:00
|
|
|
for (unsigned i = 0; i < (unsigned)size_param_changed_storage_bytes; i++) {
|
2015-05-18 13:51:21 -10:00
|
|
|
for (unsigned j = 0; j < bits_per_allocation_unit; j++) {
|
2015-03-22 23:15:59 -07:00
|
|
|
if (param_changed_storage[i] & (1 << j)) {
|
2015-04-27 09:03:35 +02:00
|
|
|
|
2015-05-18 13:51:21 -10:00
|
|
|
if ((unsigned)param == i * bits_per_allocation_unit + j) {
|
2015-06-25 09:28:04 +02:00
|
|
|
return used_count;
|
2015-04-27 09:03:35 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 09:28:04 +02:00
|
|
|
used_count++;
|
2015-03-22 23:15:59 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-27 09:03:35 +02:00
|
|
|
return -1;
|
2015-03-22 23:15:59 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
const char *
|
|
|
|
|
param_name(param_t param)
|
|
|
|
|
{
|
2015-05-17 23:08:10 +02:00
|
|
|
return handle_in_range(param) ? param_info_base[param].name : NULL;
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
|
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
bool
|
|
|
|
|
param_value_is_default(param_t param)
|
|
|
|
|
{
|
2017-02-16 17:51:29 +01:00
|
|
|
struct param_wbuf_s *s;
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader();
|
2017-02-16 17:51:29 +01:00
|
|
|
s = param_find_changed(param);
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader();
|
2017-02-16 17:51:29 +01:00
|
|
|
return s ? false : true;
|
2012-10-09 22:45:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
param_value_unsaved(param_t param)
|
|
|
|
|
{
|
2017-02-16 17:51:29 +01:00
|
|
|
struct param_wbuf_s *s;
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader();
|
2012-10-09 22:45:36 -07:00
|
|
|
s = param_find_changed(param);
|
2017-02-16 17:51:29 +01:00
|
|
|
bool ret = s && s->unsaved;
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader();
|
2017-02-16 17:51:29 +01:00
|
|
|
return ret;
|
2012-10-09 22:45:36 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
enum param_type_e
|
2015-05-15 03:58:04 -10:00
|
|
|
param_type(param_t param) {
|
|
|
|
|
return handle_in_range(param) ? param_info_base[param].type : PARAM_TYPE_UNKNOWN;
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
param_size(param_t param)
|
|
|
|
|
{
|
|
|
|
|
if (handle_in_range(param)) {
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
switch (param_type(param)) {
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
case PARAM_TYPE_INT32:
|
|
|
|
|
case PARAM_TYPE_FLOAT:
|
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
|
|
case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
|
2012-08-19 22:15:29 -07:00
|
|
|
/* decode structure size from type value */
|
|
|
|
|
return param_type(param) - PARAM_TYPE_STRUCT;
|
2012-08-18 22:04:32 -07:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-11 10:51:42 -10:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/**
|
|
|
|
|
* Obtain a pointer to the storage allocated for a parameter.
|
|
|
|
|
*
|
|
|
|
|
* @param param The parameter whose storage is sought.
|
|
|
|
|
* @return A pointer to the parameter value, or NULL
|
|
|
|
|
* if the parameter does not exist.
|
|
|
|
|
*/
|
|
|
|
|
static const void *
|
|
|
|
|
param_get_value_ptr(param_t param)
|
2012-08-18 22:04:32 -07:00
|
|
|
{
|
2012-08-19 22:15:29 -07:00
|
|
|
const void *result = NULL;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
param_assert_locked();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
if (handle_in_range(param)) {
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
const union param_value_u *v;
|
|
|
|
|
|
|
|
|
|
/* work out whether we're fetching the default or a written value */
|
2012-08-19 22:15:29 -07:00
|
|
|
struct param_wbuf_s *s = param_find_changed(param);
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
if (s != NULL) {
|
|
|
|
|
v = &s->val;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
} else {
|
|
|
|
|
v = ¶m_info_base[param].val;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (param_type(param) >= PARAM_TYPE_STRUCT &&
|
|
|
|
|
param_type(param) <= PARAM_TYPE_STRUCT_MAX) {
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
result = v->p;
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
} else {
|
|
|
|
|
result = v;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
int
|
|
|
|
|
param_get(param_t param, void *val)
|
|
|
|
|
{
|
|
|
|
|
int result = -1;
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
const void *v = param_get_value_ptr(param);
|
|
|
|
|
|
2017-02-25 07:05:04 +01:00
|
|
|
if (val && v) {
|
2012-08-19 22:15:29 -07:00
|
|
|
memcpy(val, v, param_size(param));
|
|
|
|
|
result = 0;
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
|
|
|
|
return result;
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
/**
|
|
|
|
|
* worker callback method to save the parameters
|
|
|
|
|
* @param arg unused
|
|
|
|
|
*/
|
|
|
|
|
static void autosave_worker(void *arg)
|
|
|
|
|
{
|
|
|
|
|
bool disabled = false;
|
|
|
|
|
|
|
|
|
|
param_lock_writer();
|
|
|
|
|
last_autosave_timestamp = hrt_absolute_time();
|
|
|
|
|
autosave_scheduled = false;
|
|
|
|
|
disabled = autosave_disabled;
|
|
|
|
|
param_unlock_writer();
|
|
|
|
|
|
|
|
|
|
if (disabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PX4_DEBUG("Autosaving params");
|
|
|
|
|
int ret = param_save_default();
|
|
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
PX4_ERR("param save failed (%i)", ret);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Automatically save the parameters after a timeout and limited rate.
|
|
|
|
|
*
|
|
|
|
|
* This needs to be called with the writer lock held (it's not necessary that it's the writer lock, but it
|
|
|
|
|
* needs to be the same lock as autosave_worker() and param_control_autosave() use).
|
|
|
|
|
*/
|
|
|
|
|
static void param_autosave(void)
|
|
|
|
|
{
|
|
|
|
|
if (autosave_scheduled || autosave_disabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wait at least 300ms before saving, because:
|
|
|
|
|
// - tasks often call param_set() for multiple params, so this avoids unnecessary save calls
|
|
|
|
|
// - the logger stores changed params. He gets notified on a param change via uORB and then
|
|
|
|
|
// looks at all unsaved params.
|
|
|
|
|
hrt_abstime delay = 300 * 1000;
|
|
|
|
|
|
|
|
|
|
const hrt_abstime rate_limit = 2000 * 1000; // rate-limit saving to 2 seconds
|
|
|
|
|
hrt_abstime last_save_elapsed = hrt_elapsed_time(&last_autosave_timestamp);
|
|
|
|
|
|
|
|
|
|
if (last_save_elapsed < rate_limit && rate_limit > last_save_elapsed + delay) {
|
|
|
|
|
delay = rate_limit - last_save_elapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
autosave_scheduled = true;
|
|
|
|
|
work_queue(LPWORK, &autosave_work, (worker_t)&autosave_worker, NULL, USEC2TICK(delay));
|
|
|
|
|
}
|
2012-10-09 22:45:36 -07:00
|
|
|
static int
|
2017-03-24 16:59:51 +01:00
|
|
|
param_set_internal(param_t param, const void *val, bool mark_saved, bool notify_changes)
|
2012-08-18 22:04:32 -07:00
|
|
|
{
|
2012-08-19 01:30:55 -07:00
|
|
|
int result = -1;
|
2012-08-27 22:57:20 +02:00
|
|
|
bool params_changed = false;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_writer();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (param_values == NULL) {
|
2012-08-19 01:30:55 -07:00
|
|
|
utarray_new(param_values, ¶m_icd);
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
|
|
|
|
if (param_values == NULL) {
|
|
|
|
|
debug("failed to allocate modified values array");
|
2012-08-19 01:30:55 -07:00
|
|
|
goto out;
|
2012-08-19 22:15:29 -07:00
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-18 22:04:32 -07:00
|
|
|
if (handle_in_range(param)) {
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
struct param_wbuf_s *s = param_find_changed(param);
|
|
|
|
|
|
|
|
|
|
if (s == NULL) {
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
/* construct a new parameter */
|
2012-08-19 22:15:29 -07:00
|
|
|
struct param_wbuf_s buf = {
|
|
|
|
|
.param = param,
|
|
|
|
|
.val.p = NULL,
|
|
|
|
|
.unsaved = false
|
|
|
|
|
};
|
2016-11-06 21:45:17 +08:00
|
|
|
params_changed = true;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
|
|
|
|
/* add it to the array and sort */
|
|
|
|
|
utarray_push_back(param_values, &buf);
|
|
|
|
|
utarray_sort(param_values, param_compare_values);
|
|
|
|
|
|
|
|
|
|
/* find it after sorting */
|
|
|
|
|
s = param_find_changed(param);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* update the changed value */
|
2012-08-19 22:15:29 -07:00
|
|
|
switch (param_type(param)) {
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
case PARAM_TYPE_INT32:
|
2016-11-06 21:45:17 +08:00
|
|
|
params_changed = params_changed || s->val.i != *(int32_t *)val;
|
2012-08-19 01:30:55 -07:00
|
|
|
s->val.i = *(int32_t *)val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PARAM_TYPE_FLOAT:
|
2016-11-06 21:45:17 +08:00
|
|
|
params_changed = params_changed || fabsf(s->val.f - * (float *)val) > FLT_EPSILON;
|
2012-08-19 01:30:55 -07:00
|
|
|
s->val.f = *(float *)val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
|
2012-08-19 22:15:29 -07:00
|
|
|
if (s->val.p == NULL) {
|
|
|
|
|
s->val.p = malloc(param_size(param));
|
|
|
|
|
|
|
|
|
|
if (s->val.p == NULL) {
|
|
|
|
|
debug("failed to allocate parameter storage");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(s->val.p, val, param_size(param));
|
2016-06-26 22:29:14 +02:00
|
|
|
params_changed = true;
|
2012-08-19 01:30:55 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
s->unsaved = !mark_saved;
|
2012-08-19 01:30:55 -07:00
|
|
|
result = 0;
|
2017-03-24 16:59:51 +01:00
|
|
|
|
|
|
|
|
if (!mark_saved) { // this is false when importing parameters
|
|
|
|
|
param_autosave();
|
|
|
|
|
}
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
out:
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_writer();
|
2012-08-20 21:17:50 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we set something, now that we have unlocked, go ahead and advertise that
|
|
|
|
|
* a thing has been set.
|
|
|
|
|
*/
|
2015-05-15 03:58:04 -10:00
|
|
|
if (params_changed && notify_changes) {
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes();
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-28 22:15:25 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-11 10:51:42 -10:00
|
|
|
#if defined(FLASH_BASED_PARAMS)
|
2017-03-24 16:59:51 +01:00
|
|
|
int param_set_external(param_t param, const void *val, bool mark_saved, bool notify_changes)
|
2016-07-11 10:51:42 -10:00
|
|
|
{
|
2017-03-24 16:59:51 +01:00
|
|
|
return param_set_internal(param, val, mark_saved, notify_changes);
|
2016-07-11 10:51:42 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const void *param_get_value_ptr_external(param_t param)
|
|
|
|
|
{
|
|
|
|
|
return param_get_value_ptr(param);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
int
|
|
|
|
|
param_set(param_t param, const void *val)
|
|
|
|
|
{
|
2017-03-24 16:59:51 +01:00
|
|
|
return param_set_internal(param, val, false, true);
|
2015-02-14 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
param_set_no_notification(param_t param, const void *val)
|
|
|
|
|
{
|
2017-03-24 16:59:51 +01:00
|
|
|
return param_set_internal(param, val, false, false);
|
2012-10-09 22:45:36 -07:00
|
|
|
}
|
|
|
|
|
|
2015-03-22 23:15:59 -07:00
|
|
|
bool
|
|
|
|
|
param_used(param_t param)
|
2015-03-21 22:01:28 +01:00
|
|
|
{
|
|
|
|
|
int param_index = param_get_index(param);
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2015-03-21 22:01:28 +01:00
|
|
|
if (param_index < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
return param_changed_storage[param_index / bits_per_allocation_unit] &
|
|
|
|
|
(1 << param_index % bits_per_allocation_unit);
|
2015-03-21 22:01:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void param_set_used_internal(param_t param)
|
|
|
|
|
{
|
|
|
|
|
int param_index = param_get_index(param);
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2015-03-21 22:01:28 +01:00
|
|
|
if (param_index < 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
// FIXME: this needs locking too
|
2015-05-15 03:58:04 -10:00
|
|
|
param_changed_storage[param_index / bits_per_allocation_unit] |=
|
|
|
|
|
(1 << param_index % bits_per_allocation_unit);
|
2015-03-21 22:01:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-08 16:39:37 +01:00
|
|
|
int
|
2012-08-28 22:15:25 -07:00
|
|
|
param_reset(param_t param)
|
|
|
|
|
{
|
|
|
|
|
struct param_wbuf_s *s = NULL;
|
2015-02-08 16:39:37 +01:00
|
|
|
bool param_found = false;
|
2012-08-28 22:15:25 -07:00
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_writer();
|
2012-08-28 22:15:25 -07:00
|
|
|
|
|
|
|
|
if (handle_in_range(param)) {
|
|
|
|
|
|
|
|
|
|
/* look for a saved value */
|
|
|
|
|
s = param_find_changed(param);
|
|
|
|
|
|
|
|
|
|
/* if we found one, erase it */
|
|
|
|
|
if (s != NULL) {
|
2012-10-28 15:42:27 -07:00
|
|
|
int pos = utarray_eltidx(param_values, s);
|
2012-08-28 22:15:25 -07:00
|
|
|
utarray_erase(param_values, pos, 1);
|
2012-08-22 01:09:06 -07:00
|
|
|
}
|
2015-02-08 16:39:37 +01:00
|
|
|
|
|
|
|
|
param_found = true;
|
2012-08-28 22:15:25 -07:00
|
|
|
}
|
2012-10-23 23:38:45 -07:00
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
param_autosave();
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_writer();
|
2012-08-28 22:15:25 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (s != NULL) {
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes();
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2015-02-08 16:39:37 +01:00
|
|
|
|
|
|
|
|
return (!param_found);
|
2012-08-28 22:15:25 -07:00
|
|
|
}
|
2017-03-24 16:59:51 +01:00
|
|
|
static void
|
|
|
|
|
param_reset_all_internal(bool auto_save)
|
2012-08-28 22:15:25 -07:00
|
|
|
{
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_writer();
|
2012-08-22 01:09:06 -07:00
|
|
|
|
2012-08-28 22:15:25 -07:00
|
|
|
if (param_values != NULL) {
|
|
|
|
|
utarray_free(param_values);
|
2012-08-20 21:17:50 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-29 22:56:29 +02:00
|
|
|
/* mark as reset / deleted */
|
|
|
|
|
param_values = NULL;
|
|
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
if (auto_save) {
|
|
|
|
|
param_autosave();
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_writer();
|
2012-08-28 22:15:25 -07:00
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
param_reset_all(void)
|
|
|
|
|
{
|
|
|
|
|
param_reset_all_internal(true);
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 11:21:05 +01:00
|
|
|
void
|
2015-05-15 03:58:04 -10:00
|
|
|
param_reset_excludes(const char *excludes[], int num_excludes)
|
2015-01-30 11:21:05 +01:00
|
|
|
{
|
|
|
|
|
param_t param;
|
|
|
|
|
|
|
|
|
|
for (param = 0; handle_in_range(param); param++) {
|
2015-05-15 03:58:04 -10:00
|
|
|
const char *name = param_name(param);
|
2015-02-04 09:33:14 +01:00
|
|
|
bool exclude = false;
|
|
|
|
|
|
|
|
|
|
for (int index = 0; index < num_excludes; index ++) {
|
|
|
|
|
int len = strlen(excludes[index]);
|
2015-01-30 11:21:05 +01:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if ((excludes[index][len - 1] == '*'
|
|
|
|
|
&& strncmp(name, excludes[index], len - 1) == 0)
|
|
|
|
|
|| strcmp(name, excludes[index]) == 0) {
|
2015-02-04 09:33:14 +01:00
|
|
|
exclude = true;
|
|
|
|
|
break;
|
2015-01-30 11:21:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-04 09:33:14 +01:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (!exclude) {
|
2015-02-04 09:33:14 +01:00
|
|
|
param_reset(param);
|
|
|
|
|
}
|
2015-01-30 11:21:05 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
_param_notify_changes();
|
2015-01-30 11:21:05 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-11 21:36:13 -07:00
|
|
|
static const char *param_default_file = PX4_ROOTFSDIR"/eeprom/parameters";
|
2012-11-02 15:21:37 +01:00
|
|
|
static char *param_user_file = NULL;
|
2012-10-31 16:31:21 +01:00
|
|
|
|
|
|
|
|
int
|
2015-05-15 03:58:04 -10:00
|
|
|
param_set_default_file(const char *filename)
|
2012-10-31 16:31:21 +01:00
|
|
|
{
|
2012-10-31 12:59:24 -07:00
|
|
|
if (param_user_file != NULL) {
|
2017-02-16 17:51:29 +01:00
|
|
|
// we assume this is not in use by some other thread
|
2012-10-31 12:59:24 -07:00
|
|
|
free(param_user_file);
|
|
|
|
|
param_user_file = NULL;
|
2012-10-31 16:31:21 +01:00
|
|
|
}
|
2015-05-15 03:58:04 -10:00
|
|
|
|
|
|
|
|
if (filename) {
|
2012-10-31 12:59:24 -07:00
|
|
|
param_user_file = strdup(filename);
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
|
|
|
|
|
2012-10-31 16:31:21 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-31 12:59:24 -07:00
|
|
|
const char *
|
|
|
|
|
param_get_default_file(void)
|
|
|
|
|
{
|
|
|
|
|
return (param_user_file != NULL) ? param_user_file : param_default_file;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-31 16:31:21 +01:00
|
|
|
int
|
|
|
|
|
param_save_default(void)
|
|
|
|
|
{
|
2013-10-22 21:02:29 +02:00
|
|
|
int res;
|
2016-07-11 10:51:42 -10:00
|
|
|
#if !defined(FLASH_BASED_PARAMS)
|
2013-10-22 21:02:29 +02:00
|
|
|
int fd;
|
2013-09-20 19:59:48 +02:00
|
|
|
|
2013-10-22 21:02:29 +02:00
|
|
|
const char *filename = param_get_default_file();
|
2014-01-12 16:33:23 +01:00
|
|
|
|
|
|
|
|
/* write parameters to temp file */
|
2015-06-13 22:06:38 -07:00
|
|
|
fd = PARAM_OPEN(filename, O_WRONLY | O_CREAT, PX4_O_MODE_666);
|
2014-01-12 16:33:23 +01:00
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
warn("failed to open param file: %s", filename);
|
2014-01-12 18:52:10 +01:00
|
|
|
return ERROR;
|
2014-01-12 16:33:23 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-22 14:21:09 +01:00
|
|
|
res = 1;
|
|
|
|
|
int attempts = 5;
|
|
|
|
|
|
|
|
|
|
while (res != OK && attempts > 0) {
|
|
|
|
|
res = param_export(fd, false);
|
|
|
|
|
attempts--;
|
|
|
|
|
}
|
2014-01-12 18:52:10 +01:00
|
|
|
|
2014-05-08 20:20:29 +02:00
|
|
|
if (res != OK) {
|
|
|
|
|
warnx("failed to write parameters to file: %s", filename);
|
2014-01-12 16:33:23 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-19 13:36:13 -07:00
|
|
|
PARAM_CLOSE(fd);
|
2016-07-11 10:51:42 -10:00
|
|
|
#else
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_writer();
|
2016-07-11 10:51:42 -10:00
|
|
|
res = flash_param_save();
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_writer();
|
2016-07-11 10:51:42 -10:00
|
|
|
#endif
|
2014-01-12 18:52:10 +01:00
|
|
|
return res;
|
2012-10-31 16:31:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return 0 on success, 1 if all params have not yet been stored, -1 if device open failed, -2 if writing parameters failed
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
param_load_default(void)
|
|
|
|
|
{
|
2017-02-16 17:40:16 +01:00
|
|
|
int res = 0;
|
|
|
|
|
#if !defined(FLASH_BASED_PARAMS)
|
2015-05-19 13:36:13 -07:00
|
|
|
int fd_load = PARAM_OPEN(param_get_default_file(), O_RDONLY);
|
2012-10-31 16:31:21 +01:00
|
|
|
|
2014-01-12 16:33:23 +01:00
|
|
|
if (fd_load < 0) {
|
2012-10-31 16:31:21 +01:00
|
|
|
/* no parameter file is OK, otherwise this is an error */
|
|
|
|
|
if (errno != ENOENT) {
|
2012-10-31 12:59:24 -07:00
|
|
|
warn("open '%s' for reading failed", param_get_default_file());
|
2012-10-31 16:31:21 +01:00
|
|
|
return -1;
|
|
|
|
|
}
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2012-10-31 16:31:21 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-12 16:33:23 +01:00
|
|
|
int result = param_load(fd_load);
|
2015-05-19 13:36:13 -07:00
|
|
|
PARAM_CLOSE(fd_load);
|
2012-10-31 16:31:21 +01:00
|
|
|
|
|
|
|
|
if (result != 0) {
|
2012-10-31 12:59:24 -07:00
|
|
|
warn("error reading parameters from '%s'", param_get_default_file());
|
2012-10-31 16:31:21 +01:00
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-16 17:40:16 +01:00
|
|
|
#else
|
|
|
|
|
// no need for locking
|
|
|
|
|
res = flash_param_load();
|
|
|
|
|
#endif
|
|
|
|
|
return res;
|
2012-10-31 16:31:21 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
static void
|
|
|
|
|
param_bus_lock(bool lock)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
|
2016-12-12 15:27:47 -10:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
// FMUv4 has baro and FRAM on the same bus,
|
|
|
|
|
// as this offers on average a 100% silent
|
|
|
|
|
// bus for the baro operation
|
|
|
|
|
|
|
|
|
|
// XXX this would be the preferred locking method
|
|
|
|
|
// if (dev == nullptr) {
|
2016-05-28 14:56:17 +02:00
|
|
|
// dev = px4_spibus_initialize(PX4_SPI_BUS_BARO);
|
2016-01-23 13:23:53 +01:00
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// SPI_LOCK(dev, lock);
|
|
|
|
|
|
|
|
|
|
// we lock like this for Pixracer for now
|
2016-12-12 15:27:47 -10:00
|
|
|
|
|
|
|
|
static irqstate_t irq_state = 0;
|
|
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
if (lock) {
|
2016-05-28 14:56:17 +02:00
|
|
|
irq_state = px4_enter_critical_section();
|
2016-01-23 14:29:15 +01:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
} else {
|
2016-05-28 14:56:17 +02:00
|
|
|
px4_leave_critical_section(irq_state);
|
2016-01-23 13:23:53 +01:00
|
|
|
}
|
2016-01-23 14:29:15 +01:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
int
|
2012-08-19 22:15:29 -07:00
|
|
|
param_export(int fd, bool only_unsaved)
|
2012-08-19 01:30:55 -07:00
|
|
|
{
|
2012-08-19 22:15:29 -07:00
|
|
|
struct param_wbuf_s *s = NULL;
|
2012-08-20 01:52:39 -07:00
|
|
|
struct bson_encoder_s encoder;
|
2012-08-19 01:30:55 -07:00
|
|
|
int result = -1;
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
param_bus_lock(true);
|
2012-10-28 15:42:27 -07:00
|
|
|
bson_encoder_init_file(&encoder, fd);
|
2016-01-23 13:23:53 +01:00
|
|
|
param_bus_lock(false);
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
/* no modified parameters -> we are done */
|
|
|
|
|
if (param_values == NULL) {
|
|
|
|
|
result = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
while ((s = (struct param_wbuf_s *)utarray_next(param_values, s)) != NULL) {
|
|
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
int32_t i;
|
|
|
|
|
float f;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we are only saving values changed since last save, and this
|
2012-08-19 01:30:55 -07:00
|
|
|
* one hasn't, then skip it
|
|
|
|
|
*/
|
2015-05-15 03:58:04 -10:00
|
|
|
if (only_unsaved && !s->unsaved) {
|
2012-08-19 01:30:55 -07:00
|
|
|
continue;
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
s->unsaved = false;
|
|
|
|
|
|
2012-09-25 16:36:33 +02:00
|
|
|
/* append the appropriate BSON type object */
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
switch (param_type(s->param)) {
|
2015-05-15 03:58:04 -10:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
case PARAM_TYPE_INT32: {
|
2017-02-16 17:43:30 +01:00
|
|
|
i = s->val.i;
|
2016-08-01 11:15:21 +02:00
|
|
|
const char *name = param_name(s->param);
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
/* lock as short as possible */
|
|
|
|
|
param_bus_lock(true);
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
if (bson_encoder_append_int(&encoder, name, i)) {
|
|
|
|
|
param_bus_lock(false);
|
|
|
|
|
debug("BSON append failed for '%s'", name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
break;
|
2012-08-18 22:04:32 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
case PARAM_TYPE_FLOAT: {
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2017-02-16 17:43:30 +01:00
|
|
|
f = s->val.f;
|
2016-08-01 11:15:21 +02:00
|
|
|
const char *name = param_name(s->param);
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
/* lock as short as possible */
|
|
|
|
|
param_bus_lock(true);
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
if (bson_encoder_append_double(&encoder, name, f)) {
|
|
|
|
|
param_bus_lock(false);
|
|
|
|
|
debug("BSON append failed for '%s'", name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
}
|
2016-08-01 11:15:21 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX: {
|
|
|
|
|
|
|
|
|
|
const char *name = param_name(s->param);
|
|
|
|
|
const size_t size = param_size(s->param);
|
|
|
|
|
const void *value_ptr = param_get_value_ptr(s->param);
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2016-08-01 11:15:21 +02:00
|
|
|
/* lock as short as possible */
|
|
|
|
|
param_bus_lock(true);
|
|
|
|
|
|
|
|
|
|
if (bson_encoder_append_binary(&encoder,
|
|
|
|
|
name,
|
|
|
|
|
BSON_BIN_BINARY,
|
|
|
|
|
size,
|
|
|
|
|
value_ptr)) {
|
|
|
|
|
param_bus_lock(false);
|
|
|
|
|
debug("BSON append failed for '%s'", name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
break;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
default:
|
2012-09-07 14:54:31 +02:00
|
|
|
debug("unrecognized parameter type");
|
2012-08-19 01:30:55 -07:00
|
|
|
goto out;
|
|
|
|
|
}
|
2016-01-22 11:35:56 +01:00
|
|
|
|
2016-01-23 13:23:53 +01:00
|
|
|
param_bus_lock(false);
|
|
|
|
|
|
2016-01-22 11:35:56 +01:00
|
|
|
/* allow this process to be interrupted by another process / thread */
|
|
|
|
|
usleep(5);
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
result = 0;
|
|
|
|
|
|
|
|
|
|
out:
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader();
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (result == 0) {
|
2012-08-28 21:52:26 -07:00
|
|
|
result = bson_encoder_fini(&encoder);
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-28 21:52:26 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-23 23:38:45 -07:00
|
|
|
struct param_import_state {
|
2012-10-09 22:45:36 -07:00
|
|
|
bool mark_saved;
|
|
|
|
|
};
|
|
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
static int
|
|
|
|
|
param_import_callback(bson_decoder_t decoder, void *private, bson_node_t node)
|
|
|
|
|
{
|
|
|
|
|
float f;
|
|
|
|
|
int32_t i;
|
|
|
|
|
void *v, *tmp = NULL;
|
|
|
|
|
int result = -1;
|
2012-10-09 22:45:36 -07:00
|
|
|
struct param_import_state *state = (struct param_import_state *)private;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
/*
|
2012-08-28 21:52:26 -07:00
|
|
|
* EOO means the end of the parameter object. (Currently not supporting
|
|
|
|
|
* nested BSON objects).
|
2012-08-20 01:52:39 -07:00
|
|
|
*/
|
|
|
|
|
if (node->type == BSON_EOO) {
|
|
|
|
|
debug("end of parameters");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
/*
|
|
|
|
|
* Find the parameter this node represents. If we don't know it,
|
|
|
|
|
* ignore the node.
|
|
|
|
|
*/
|
2015-03-21 22:01:28 +01:00
|
|
|
param_t param = param_find_no_notification(node->name);
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-28 21:52:26 -07:00
|
|
|
if (param == PARAM_INVALID) {
|
|
|
|
|
debug("ignoring unrecognised parameter '%s'", node->name);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2012-08-20 01:52:39 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle setting the parameter from the node
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch (node->type) {
|
2012-10-28 16:04:25 -07:00
|
|
|
case BSON_INT32:
|
2012-08-20 01:52:39 -07:00
|
|
|
if (param_type(param) != PARAM_TYPE_INT32) {
|
|
|
|
|
debug("unexpected type for '%s", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
i = node->i;
|
|
|
|
|
v = &i;
|
|
|
|
|
break;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
case BSON_DOUBLE:
|
|
|
|
|
if (param_type(param) != PARAM_TYPE_FLOAT) {
|
|
|
|
|
debug("unexpected type for '%s", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
f = node->d;
|
|
|
|
|
v = &f;
|
|
|
|
|
break;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
case BSON_BINDATA:
|
|
|
|
|
if (node->subtype != BSON_BIN_BINARY) {
|
|
|
|
|
debug("unexpected subtype for '%s", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
if (bson_decoder_data_pending(decoder) != param_size(param)) {
|
|
|
|
|
debug("bad size for '%s'", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
/* XXX check actual file data size? */
|
|
|
|
|
tmp = malloc(param_size(param));
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
if (tmp == NULL) {
|
|
|
|
|
debug("failed allocating for '%s'", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
if (bson_decoder_copy_data(decoder, tmp)) {
|
|
|
|
|
debug("failed copying data for '%s'", node->name);
|
|
|
|
|
goto out;
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
v = tmp;
|
|
|
|
|
break;
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
default:
|
|
|
|
|
debug("unrecognised node type");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 16:59:51 +01:00
|
|
|
if (param_set_internal(param, v, state->mark_saved, true)) {
|
2012-08-20 01:52:39 -07:00
|
|
|
debug("error setting value for '%s'", node->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
if (tmp != NULL) {
|
|
|
|
|
free(tmp);
|
|
|
|
|
tmp = NULL;
|
2012-08-19 01:30:55 -07:00
|
|
|
}
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-28 21:52:26 -07:00
|
|
|
/* don't return zero, that means EOF */
|
|
|
|
|
result = 1;
|
2012-08-19 01:30:55 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
out:
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (tmp != NULL) {
|
2012-08-20 01:52:39 -07:00
|
|
|
free(tmp);
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
static int
|
|
|
|
|
param_import_internal(int fd, bool mark_saved)
|
2012-08-19 01:30:55 -07:00
|
|
|
{
|
2012-08-20 01:52:39 -07:00
|
|
|
struct bson_decoder_s decoder;
|
|
|
|
|
int result = -1;
|
2012-10-09 22:45:36 -07:00
|
|
|
struct param_import_state state;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2016-01-23 13:32:52 +01:00
|
|
|
param_bus_lock(true);
|
2016-01-23 14:29:15 +01:00
|
|
|
|
2012-10-28 15:42:27 -07:00
|
|
|
if (bson_decoder_init_file(&decoder, fd, param_import_callback, &state)) {
|
2012-08-20 01:52:39 -07:00
|
|
|
debug("decoder init failed");
|
2016-01-23 13:32:52 +01:00
|
|
|
param_bus_lock(false);
|
2012-08-19 22:15:29 -07:00
|
|
|
goto out;
|
|
|
|
|
}
|
2016-01-23 14:29:15 +01:00
|
|
|
|
2016-01-23 13:32:52 +01:00
|
|
|
param_bus_lock(false);
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
state.mark_saved = mark_saved;
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-28 21:52:26 -07:00
|
|
|
do {
|
2016-01-23 13:32:52 +01:00
|
|
|
param_bus_lock(true);
|
2012-08-20 01:52:39 -07:00
|
|
|
result = bson_decoder_next(&decoder);
|
2016-01-23 13:32:52 +01:00
|
|
|
usleep(1);
|
|
|
|
|
param_bus_lock(false);
|
2012-08-20 21:17:50 -07:00
|
|
|
|
2012-10-23 23:38:45 -07:00
|
|
|
} while (result > 0);
|
2012-08-19 22:15:29 -07:00
|
|
|
|
2012-08-20 01:52:39 -07:00
|
|
|
out:
|
2012-10-23 23:38:45 -07:00
|
|
|
|
2015-05-15 03:58:04 -10:00
|
|
|
if (result < 0) {
|
2012-08-28 21:52:26 -07:00
|
|
|
debug("BSON error decoding parameters");
|
2015-05-15 03:58:04 -10:00
|
|
|
}
|
2012-08-28 22:15:25 -07:00
|
|
|
|
2012-08-19 22:15:29 -07:00
|
|
|
return result;
|
2012-08-18 22:04:32 -07:00
|
|
|
}
|
|
|
|
|
|
2012-10-09 22:45:36 -07:00
|
|
|
int
|
|
|
|
|
param_import(int fd)
|
|
|
|
|
{
|
2017-02-16 17:40:16 +01:00
|
|
|
#if !defined(FLASH_BASED_PARAMS)
|
2012-10-09 22:45:36 -07:00
|
|
|
return param_import_internal(fd, false);
|
2017-02-16 17:40:16 +01:00
|
|
|
#else
|
|
|
|
|
(void)fd; // unused
|
|
|
|
|
// no need for locking here
|
|
|
|
|
return flash_param_import();
|
|
|
|
|
#endif
|
2012-10-09 22:45:36 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-28 22:15:25 -07:00
|
|
|
int
|
|
|
|
|
param_load(int fd)
|
|
|
|
|
{
|
2017-03-24 16:59:51 +01:00
|
|
|
param_reset_all_internal(false);
|
2012-10-09 22:45:36 -07:00
|
|
|
return param_import_internal(fd, true);
|
2012-08-28 22:15:25 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-19 01:30:55 -07:00
|
|
|
void
|
2015-03-21 22:01:28 +01:00
|
|
|
param_foreach(void (*func)(void *arg, param_t param), void *arg, bool only_changed, bool only_used)
|
2012-08-19 01:30:55 -07:00
|
|
|
{
|
|
|
|
|
param_t param;
|
|
|
|
|
|
|
|
|
|
for (param = 0; handle_in_range(param); param++) {
|
|
|
|
|
|
|
|
|
|
/* if requested, skip unchanged values */
|
2015-03-21 22:01:28 +01:00
|
|
|
if (only_changed && (param_find_changed(param) == NULL)) {
|
2012-08-19 01:30:55 -07:00
|
|
|
continue;
|
2015-03-21 22:01:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-22 23:15:59 -07:00
|
|
|
if (only_used && !param_used(param)) {
|
2015-03-21 22:01:28 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2012-08-19 01:30:55 -07:00
|
|
|
|
|
|
|
|
func(arg, param);
|
|
|
|
|
}
|
2012-09-25 16:36:33 +02:00
|
|
|
}
|
2015-10-12 13:36:37 -04:00
|
|
|
|
|
|
|
|
uint32_t param_hash_check(void)
|
|
|
|
|
{
|
|
|
|
|
uint32_t param_hash = 0;
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_lock_reader();
|
2015-10-12 13:36:37 -04:00
|
|
|
|
|
|
|
|
/* compute the CRC32 over all string param names and 4 byte values */
|
|
|
|
|
for (param_t param = 0; handle_in_range(param); param++) {
|
|
|
|
|
if (!param_used(param)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-10-12 15:26:11 -04:00
|
|
|
|
2015-10-12 13:36:37 -04:00
|
|
|
const char *name = param_name(param);
|
|
|
|
|
const void *val = param_get_value_ptr(param);
|
2015-10-12 15:26:11 -04:00
|
|
|
param_hash = crc32part((const uint8_t *)name, strlen(name), param_hash);
|
2016-02-15 18:07:37 -05:00
|
|
|
param_hash = crc32part(val, param_size(param), param_hash);
|
2015-10-12 13:36:37 -04:00
|
|
|
}
|
|
|
|
|
|
2017-03-13 11:05:18 +01:00
|
|
|
param_unlock_reader();
|
2015-10-12 13:36:37 -04:00
|
|
|
|
|
|
|
|
return param_hash;
|
|
|
|
|
}
|