aboutsummaryrefslogtreecommitdiff
path: root/apps/systemlib/param/param.c
diff options
context:
space:
mode:
authorpx4dev <px4@purgatory.org>2012-08-19 01:30:55 -0700
committerpx4dev <px4@purgatory.org>2012-08-19 01:31:27 -0700
commitd903311dce6a94f09e56bc557025d2d4d73120b8 (patch)
tree3711e1e506b5f47e00189210f35a1d6eb47f51e0 /apps/systemlib/param/param.c
parenta9dc84231e0e02abbbfd2f13e3500d193ebdb03b (diff)
downloadpx4-firmware-d903311dce6a94f09e56bc557025d2d4d73120b8.tar.gz
px4-firmware-d903311dce6a94f09e56bc557025d2d4d73120b8.tar.bz2
px4-firmware-d903311dce6a94f09e56bc557025d2d4d73120b8.zip
Add support for setting and exporting parameters.
Diffstat (limited to 'apps/systemlib/param/param.c')
-rw-r--r--apps/systemlib/param/param.c261
1 files changed, 246 insertions, 15 deletions
diff --git a/apps/systemlib/param/param.c b/apps/systemlib/param/param.c
index bb82941a0..315ba187b 100644
--- a/apps/systemlib/param/param.c
+++ b/apps/systemlib/param/param.c
@@ -6,10 +6,13 @@
#include <string.h>
#include <stdbool.h>
-
+#include <fcntl.h>
#include <unistd.h>
+#include <err.h>
-#include "param.h"
+#include "systemlib/param/param.h"
+#include "systemlib/uthash/utarray.h"
+#include "systemlib/bson/bson.h"
/**
* Array of static parameter info.
@@ -19,12 +22,78 @@ static const struct param_info_s *param_info_base = (struct param_info_s *)&__pa
static const struct param_info_s *param_info_limit = (struct param_info_s *)&__param_end;
#define param_info_count ((unsigned)(param_info_limit - param_info_base))
+/**
+ * Storage for modified parameters.
+ */
+struct param_wbuf_s
+{
+ param_t param;
+ union param_value_u val;
+ bool unsaved;
+};
+
+UT_icd param_icd = {sizeof(struct param_wbuf_s), NULL, NULL, NULL};
+UT_array *param_values;
+
+static void
+param_lock(void)
+{
+ /* XXX */
+}
+
+static void
+param_unlock(void)
+{
+ /* XXX */
+}
+
+static void
+param_assert_locked(void)
+{
+ /* XXX */
+}
+
static bool
handle_in_range(param_t handle)
{
return (handle < param_info_count);
}
+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;
+
+ if (pa->param < pb->param)
+ return -1;
+ if (pa->param > pb->param)
+ return 1;
+ return 0;
+}
+
+static struct param_wbuf_s *
+param_find_changed(param_t param)
+{
+ struct param_wbuf_s *s = NULL;
+
+ param_assert_locked();
+
+ if (param_values != NULL) {
+#if 0 /* utarray_find requires bsearch, not available */
+ struct param_wbuf_s key;
+ key.param = param;
+ s = utarray_find(param_values, &key, param_compare_values);
+#else
+ while ((s = (struct param_wbuf_s *)utarray_next(param_values, s)) != NULL) {
+ if (s->param == param)
+ break;
+ }
+#endif
+ }
+ return s;
+}
+
param_t
param_find(const char *name)
{
@@ -39,8 +108,17 @@ param_find(const char *name)
return PARAM_INVALID;
}
-enum
-param_type_e param_type(param_t param)
+const char *
+param_name(param_t param)
+{
+ if (handle_in_range(param))
+ return param_info_base[param].name;
+
+ return NULL;
+}
+
+enum param_type_e
+param_type(param_t param)
{
if (handle_in_range(param))
return param_info_base[param].type;
@@ -51,7 +129,6 @@ param_type_e param_type(param_t param)
size_t
param_size(param_t param)
{
-
if (handle_in_range(param)) {
switch (param_info_base[param].type) {
case PARAM_TYPE_INT32:
@@ -72,39 +149,193 @@ param_size(param_t param)
int
param_get(param_t param, void *val)
{
+ int result = -1;
+
+ param_lock();
+
if (handle_in_range(param)) {
+ struct param_wbuf_s *s = param_find_changed(param);
+ const union param_value_u *v;
+
+ /* work out whether we're fetching the default or a written value */
+ if (s != NULL) {
+ v = &s->val;
+ } else {
+ v = &param_info_base[param].val;
+ }
+
/* XXX look for updated value stored elsewhere */
switch (param_info_base[param].type) {
case PARAM_TYPE_INT32:
- *(int32_t *)val = param_info_base[param].i;
- return 0;
+ *(int32_t *)val = v->i;
+ result = 0;
+ break;
case PARAM_TYPE_FLOAT:
- *(float *)val = param_info_base[param].f;
- return 0;
+ *(float *)val = v->f;
+ result = 0;
+ break;
case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
- memcpy(val, param_info_base[param].p, param_size(param));
- return 0;
+ *(void **)val = v->p;
+ result = 0;
+ break;
default:
- return -1;
+ break;
}
+
}
- return -1;
+
+ param_unlock();
+
+ return result;
}
int
param_set(param_t param, void *val)
{
+ int result = -1;
+
+ param_lock();
+
+ if (param_values == NULL)
+ utarray_new(param_values, &param_icd);
+ if (param_values == NULL)
+ goto out;
+
if (handle_in_range(param)) {
- /* XXX maintain list of changed values */
+ struct param_wbuf_s *s = param_find_changed(param);
+
+ if (s == NULL) {
+ /* construct a new parameter */
+ struct param_wbuf_s buf = { .param = param };
+
+ /* 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 */
+ switch (param_info_base[param].type) {
+ case PARAM_TYPE_INT32:
+ s->val.i = *(int32_t *)val;
+ break;
+
+ case PARAM_TYPE_FLOAT:
+ s->val.f = *(float *)val;
+ break;
+
+ case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
+ s->val.p = *(void **)val;
+ break;
+
+ default:
+ goto out;
+ }
+ s->unsaved = true;
+
+ result = 0;
}
- return -1;
+out:
+ param_unlock();
+ return result;
+}
+
+int
+param_export(const char *filename, bool only_unsaved)
+{
+ struct param_wbuf_s *s;
+ bson b[1];
+ int result = -1;
+
+ param_lock();
+
+ bson_init(b);
+
+ while ((s = (struct param_wbuf_s *)utarray_next(param_values, s)) != NULL) {
+ const struct param_info_s *is = &param_info_base[s->param];
+
+ /*
+ * if we are only saving values changed since last save, and this
+ * one hasn't, then skip it
+ */
+ if (only_unsaved & !s->unsaved)
+ continue;
+ s->unsaved = false;
+
+ switch (is->type) {
+ case PARAM_TYPE_INT32:
+ if (bson_append_int(b, is->name, s->val.i) != BSON_OK)
+ goto out;
+ break;
+ case PARAM_TYPE_FLOAT:
+ if (bson_append_double(b, is->name, s->val.f) != BSON_OK)
+ goto out;
+ break;
+
+ case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
+ if (bson_append_binary(b,
+ is->name,
+ is->type,
+ is->val.p,
+ is->type - PARAM_TYPE_STRUCT) != BSON_OK)
+ goto out;
+ break;
+ default:
+ goto out;
+ }
+ }
+ result = 0;
+
+out:
+ param_unlock();
+
+ if (result == 0) {
+ bson_finish(b);
+ bson_print(b);
+
+ warnx("object is %d bytes", bson_buffer_size(b));
+
+ if (filename != NULL) {
+ int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ int siz = bson_buffer_size(b);
+ int len = write(fd, bson_data(b), siz);
+ close(fd);
+ if (len != siz)
+ result = -1;
+ }
+ }
+ bson_destroy(b);
+
+ return result;
+}
+
+int
+param_import(const char *filename)
+{
+ return -1;
}
+void
+param_foreach(void (*func)(void *arg, param_t param), void *arg, bool only_changed)
+{
+ param_t param;
+
+ for (param = 0; handle_in_range(param); param++) {
+
+ /* if requested, skip unchanged values */
+ if (only_changed && (param_find_changed(param) == NULL))
+ continue;
+
+ func(arg, param);
+ }
+} \ No newline at end of file