2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/types.h>
35 #include <murphy/common.h>
36 #include <murphy/core.h>
37 #include <murphy/common/dbus-libdbus.h>
38 #include <murphy/common/process.h>
40 #include <murphy-db/mdb.h>
41 #include <murphy-db/mqi.h>
42 #include <murphy-db/mql.h>
44 #include <murphy/core/lua-utils/object.h>
45 #include <murphy/core/lua-bindings/murphy.h>
46 #include <murphy/core/lua-utils/funcbridge.h>
47 #include <murphy/core/lua-decision/mdb.h>
48 #include <murphy/core/lua-decision/element.h>
55 ARG_AMB_TPORT_ADDRESS,
56 ARG_AMB_STARTUP_DELAY,
57 ARG_AMB_FORCE_SUBSCRIPTION,
71 #define AMB_NAME "name"
72 #define AMB_HANDLER "handler"
73 #define AMB_DBUS_DATA "dbus_data"
74 #define AMB_OBJECT "obj"
75 #define AMB_INTERFACE "interface"
76 #define AMB_MEMBER "property"
77 #define AMB_OBJECTNAME "objectname"
78 #define AMB_SIGNATURE "signature"
79 #define AMB_BASIC_TABLE_NAME "basic_table_name"
80 #define AMB_OUTPUTS "outputs"
84 signal sender=:1.35 -> dest=(null destination) serial=716 path=/c0ffee8ac6054a06903459c1deadbeef/0/Transmission; interface=org.automotive.Transmission; member=GearPositionChanged
87 signal sender=:1.35 -> dest=(null destination) serial=717 path=/c0ffee8ac6054a06903459c1deadbeef/0/Transmission; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
88 string "org.automotive.Transmission"
95 string "GearPositionSequence"
100 variant double 1.38978e+09
106 signal sender=:1.35 -> dest=(null destination) serial=718 path=/c0ffee8ac6054a06903459c1deadbeef/0/VehicleSpeed; interface=org.automotive.VehicleSpeed; member=VehicleSpeedChanged
109 signal sender=:1.35 -> dest=(null destination) serial=719 path=/c0ffee8ac6054a06903459c1deadbeef/0/VehicleSpeed; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
110 string "org.automotive.VehicleSpeed"
113 string "VehicleSpeed"
117 string "VehicleSpeedSequence"
122 variant double 1.38978e+09
131 mrp_dbus_type_t type;
139 } dbus_basic_property_t;
141 typedef void (*property_updated_cb_t)(dbus_basic_property_t *property,
148 char *name; /* property name ("GearPosition") */
149 char *objectname; /* amb object to query ("Transmission") */
151 bool undefined_object_path;
154 char *basic_table_name;
157 } lua_amb_property_t;
161 const char *amb_addr;
162 const char *config_file;
164 const char *tport_addr;
165 bool force_subscription;
167 mrp_list_hook_t lua_properties;
168 mrp_htbl_t *dbus_property_objects; /* path to dbus_property_object_t */
170 mrp_process_state_t amb_state;
171 uint32_t amb_startup_delay;
180 mqi_column_def_t defs[4];
182 mql_statement_t *update_operation;
183 mqi_data_type_t type;
185 } basic_table_data_t;
188 /* PropertiesChanged signals are received by the object and may contain
189 * several properties that are changed. Hence we'll need to represent that
190 * with a custom datatype. */
192 /* htbl backpointer for freeing */
195 /* list of properties that belong to this object */
196 mrp_htbl_t *dbus_properties; /* interface+property to dbus_property_watch_t */
198 mrp_list_hook_t hook;
199 } dbus_property_object_t;
202 dbus_basic_property_t prop;
203 dbus_property_object_t *o; /* top level */
205 property_updated_cb_t cb;
208 lua_amb_property_t *lua_prop;
210 /* for basic tables that we manage ourselves */
211 basic_table_data_t *tdata;
213 /* htbl backpointer for freeing */
216 mrp_list_hook_t hook;
218 } dbus_property_watch_t;
220 static data_t *global_ctx = NULL;
222 static basic_table_data_t *create_basic_property_table(const char *table_name,
223 const char *member, int type);
224 static void delete_basic_table_data(basic_table_data_t *tdata);
225 static int find_property_object(data_t *ctx, dbus_property_watch_t *w,
227 static int subscribe_property(data_t *ctx, dbus_property_watch_t *w);
228 static void basic_property_updated(dbus_basic_property_t *prop, void *userdata);
229 static int create_transport(mrp_mainloop_t *ml, data_t *ctx);
230 static int property_signal_handler(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg,
235 static int amb_constructor(lua_State *L);
236 static int amb_setfield(lua_State *L);
237 static int amb_getfield(lua_State *L);
238 static void lua_amb_destroy(void *data);
240 #define PROPERTY_CLASS MRP_LUA_CLASS(amb, property)
242 MRP_LUA_METHOD_LIST_TABLE (
243 amb_methods, /* methodlist name */
244 MRP_LUA_METHOD_CONSTRUCTOR (amb_constructor)
247 MRP_LUA_METHOD_LIST_TABLE (
248 amb_overrides, /* methodlist name */
249 MRP_LUA_OVERRIDE_CALL (amb_constructor)
250 MRP_LUA_OVERRIDE_GETFIELD (amb_getfield)
251 MRP_LUA_OVERRIDE_SETFIELD (amb_setfield)
255 amb, /* main class name */
256 property, /* constructor name */
257 lua_amb_property_t, /* userdata type */
258 lua_amb_destroy, /* userdata destructor */
259 amb_methods, /* class methods */
260 amb_overrides /* class overrides */
265 static void lua_amb_destroy(void *data)
267 lua_amb_property_t *prop = (lua_amb_property_t *)data;
271 mrp_log_info("AMB: lua_amb_destroy");
279 static int count_keys_cb(void *key, void *object, void *user_data)
281 int *count = user_data;
288 return MRP_HTBL_ITER_MORE;
292 static void destroy_prop(data_t *ctx, dbus_property_watch_t *w)
294 dbus_property_object_t *o = w->o;
297 /* remove property from the object */
299 mrp_htbl_remove(o->dbus_properties, w->key, FALSE);
301 /* check if no-one is interested in the signals o receives */
303 mrp_htbl_foreach(o->dbus_properties, count_keys_cb, &len);
306 mrp_dbus_unsubscribe_signal(ctx->dbus, property_signal_handler, o,
308 "org.freedesktop.DBus.Properties",
309 "PropertiesChanged", NULL);
310 mrp_htbl_remove(ctx->dbus_property_objects, o->path, TRUE);
315 /* delete the table data */
318 delete_basic_table_data(w->tdata);
322 char *name = w->lua_prop->name;
323 mrp_free(w->lua_prop->basic_table_name);
324 mrp_free(w->lua_prop->dbus_data.iface);
325 mrp_free(w->lua_prop->dbus_data.name);
326 mrp_free(w->lua_prop->dbus_data.obj);
327 mrp_free(w->lua_prop->dbus_data.objectname);
328 mrp_free(w->lua_prop->dbus_data.signature);
330 mrp_lua_destroy_object(ctx->L, name, 0, w->lua_prop);
339 static int amb_constructor(lua_State *L)
341 lua_amb_property_t *prop;
342 size_t field_name_len = 0;
343 const char *field_name;
344 data_t *ctx = global_ctx;
345 dbus_property_watch_t *w = NULL;
346 char *error = "unknown error";
350 mrp_debug("AMB: amb_constructor, stack size: %d", lua_gettop(L));
352 prop = (lua_amb_property_t *)
353 mrp_lua_create_object(L, PROPERTY_CLASS, NULL, 0);
358 prop->handler_ref = LUA_NOREF;
359 prop->outputs_ref = LUA_NOREF;
361 MRP_LUA_FOREACH_FIELD(L, 2, field_name, field_name_len) {
362 char buf[field_name_len+1];
364 strncpy(buf, field_name, field_name_len);
365 buf[field_name_len] = '\0';
367 /* mrp_log_info("field name: %s", buf); */
369 if (strncmp(field_name, "dbus_data", field_name_len) == 0) {
371 luaL_checktype(L, -1, LUA_TTABLE);
375 while (lua_next(L, -2)) {
380 luaL_checktype(L, -2, LUA_TSTRING);
381 luaL_checktype(L, -1, LUA_TSTRING);
383 key = lua_tostring(L, -2);
384 value = lua_tostring(L, -1);
386 mrp_log_info("%s -> %s", key, value);
388 if (!key || !value) {
389 error = "key or value undefined";
393 if (strcmp(key, AMB_SIGNATURE) == 0) {
394 prop->dbus_data.signature = mrp_strdup(value);
396 else if (strcmp(key, AMB_MEMBER) == 0) {
397 prop->dbus_data.name = mrp_strdup(value);
399 else if (strcmp(key, AMB_OBJECTNAME) == 0) {
400 prop->dbus_data.objectname = mrp_strdup(value);
402 else if (strcmp(key, AMB_OBJECT) == 0) {
403 if (strcmp(value, "undefined") == 0) {
404 /* need to query AMB for finding the object path */
405 mrp_log_info("querying AMB for correct path");
406 prop->dbus_data.undefined_object_path = TRUE;
407 prop->dbus_data.obj = NULL;
410 prop->dbus_data.undefined_object_path = FALSE;
411 prop->dbus_data.obj = mrp_strdup(value);
414 else if (strcmp(key, AMB_INTERFACE) == 0) {
415 prop->dbus_data.iface = mrp_strdup(value);
418 error = "unknown key";
425 if (prop->dbus_data.objectname == NULL)
426 prop->dbus_data.objectname = mrp_strdup(prop->dbus_data.name);
428 /* check that we have all necessary data */
429 if (prop->dbus_data.signature == NULL ||
430 prop->dbus_data.iface == NULL ||
431 prop->dbus_data.name == NULL ||
432 prop->dbus_data.objectname == NULL ||
433 (!prop->dbus_data.undefined_object_path &&
434 prop->dbus_data.obj == NULL)) {
435 error = "missing data";
439 else if (strncmp(field_name, "handler", field_name_len) == 0) {
440 luaL_checktype(L, -1, LUA_TFUNCTION);
441 prop->handler_ref = luaL_ref(L, LUA_REGISTRYINDEX);
442 lua_pushnil(L); /* need two items on the stack */
444 else if (strncmp(field_name, AMB_NAME, field_name_len) == 0) {
445 luaL_checktype(L, -1, LUA_TSTRING);
446 prop->name = mrp_strdup(lua_tostring(L, -1));
447 mrp_lua_set_object_name(L, PROPERTY_CLASS, prop->name);
449 else if (strncmp(field_name, "basic_table_name", field_name_len) == 0) {
450 luaL_checktype(L, -1, LUA_TSTRING);
451 prop->basic_table_name = mrp_strdup(lua_tostring(L, -1));
453 else if (strncmp(field_name, AMB_OUTPUTS, field_name_len) == 0) {
454 prop->outputs_ref = luaL_ref(L, LUA_REGISTRYINDEX);
455 lua_pushnil(L); /* need two items on the stack */
460 error = "missing property name";
464 if (prop->handler_ref == LUA_NOREF && !prop->basic_table_name) {
465 error = "missing table name";
469 w = (dbus_property_watch_t *) mrp_allocz(sizeof(dbus_property_watch_t));
472 error = "out of memory";
478 w->prop.initialized = FALSE;
479 w->prop.type = MRP_DBUS_TYPE_INVALID;
480 w->prop.name = mrp_strdup(w->lua_prop->dbus_data.name);
483 error = "missing watch property name";
487 if (prop->handler_ref == LUA_NOREF) {
488 basic_table_data_t *tdata;
490 w->prop.type = w->lua_prop->dbus_data.signature[0]; /* FIXME */
492 tdata = create_basic_property_table(prop->basic_table_name,
493 prop->dbus_data.name, w->prop.type);
496 error = "could not create table data";
502 w->cb = basic_property_updated;
506 mrp_list_init(&w->hook);
508 mrp_list_append(&ctx->lua_properties, &w->hook);
510 /* TODO: need some mapping? or custom property_watch? */
512 /* TODO: put the object to a global table or not? maybe better to just
513 * unload them when the plugin is unloaded. */
515 mrp_lua_push_object(L, prop);
520 destroy_prop(global_ctx, w);
522 mrp_log_error("AMB: amb_constructor error: %s", error);
526 static int amb_getfield(lua_State *L)
528 lua_amb_property_t *prop = (lua_amb_property_t *)
529 mrp_lua_check_object(L, PROPERTY_CLASS, 1);
530 size_t field_name_len;
531 const char *field_name = lua_tolstring(L, 2, &field_name_len);
538 mrp_debug("AMB: amb_getfield");
540 if (strncmp(field_name, AMB_NAME, field_name_len) == 0) {
542 lua_pushstring(L, prop->name);
546 else if (strncmp(field_name, AMB_HANDLER, field_name_len) == 0) {
547 if (prop->handler_ref != LUA_NOREF)
548 lua_rawgeti(L, LUA_REGISTRYINDEX, prop->handler_ref);
552 else if (strncmp(field_name, AMB_DBUS_DATA, field_name_len) == 0) {
555 lua_pushstring(L, AMB_OBJECT);
556 if (prop->dbus_data.obj)
557 lua_pushstring(L, prop->dbus_data.obj);
559 lua_pushstring(L, "undefined");
562 lua_pushstring(L, AMB_INTERFACE);
563 lua_pushstring(L, prop->dbus_data.iface);
566 lua_pushstring(L, AMB_MEMBER);
567 lua_pushstring(L, prop->dbus_data.name);
569 lua_pushstring(L, AMB_OBJECTNAME);
570 lua_pushstring(L, prop->dbus_data.objectname);
573 lua_pushstring(L, AMB_SIGNATURE);
574 lua_pushstring(L, prop->dbus_data.signature);
577 else if (strncmp(field_name, "basic_table_name", field_name_len) == 0) {
578 if (prop->basic_table_name)
579 lua_pushstring(L, prop->basic_table_name);
583 else if (strncmp(field_name, AMB_OUTPUTS, field_name_len) == 0) {
584 if (prop->outputs_ref != LUA_NOREF)
585 lua_rawgeti(L, LUA_REGISTRYINDEX, prop->outputs_ref);
600 static int amb_setfield(lua_State *L)
606 mrp_debug("AMB: amb_setfield");
613 static bool parse_elementary_value(lua_State *L,
614 mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
628 sig = mrp_dbus_msg_arg_type(msg, NULL);
631 case MRP_DBUS_TYPE_INT32:
632 mrp_dbus_msg_read_basic(msg, sig, &i32_val);
633 lua_pushinteger(L, i32_val);
635 case MRP_DBUS_TYPE_INT16:
636 mrp_dbus_msg_read_basic(msg, sig, &i16_val);
637 lua_pushinteger(L, i16_val);
639 case MRP_DBUS_TYPE_UINT32:
640 mrp_dbus_msg_read_basic(msg, sig, &u32_val);
641 lua_pushinteger(L, u32_val);
643 case MRP_DBUS_TYPE_UINT16:
644 mrp_dbus_msg_read_basic(msg, sig, &u16_val);
645 lua_pushinteger(L, u16_val);
647 case MRP_DBUS_TYPE_BOOLEAN:
648 mrp_dbus_msg_read_basic(msg, sig, &u32_val);
649 lua_pushboolean(L, u32_val == TRUE);
651 case MRP_DBUS_TYPE_BYTE:
652 mrp_dbus_msg_read_basic(msg, sig, &byte_val);
653 lua_pushinteger(L, byte_val);
655 case MRP_DBUS_TYPE_DOUBLE:
656 mrp_dbus_msg_read_basic(msg, sig, &d_val);
657 lua_pushnumber(L, d_val);
659 case MRP_DBUS_TYPE_STRING:
660 mrp_dbus_msg_read_basic(msg, sig, &s_val);
661 lua_pushstring(L, s_val);
664 mrp_log_error("AMB: parse_elementary_value: unknown type");
674 static bool parse_value(lua_State *L, mrp_dbus_msg_t *msg,
675 dbus_property_watch_t *w);
677 static bool parse_struct(lua_State *L,
678 mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
682 /* initialize the table */
685 mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
687 while (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_INVALID) {
690 lua_pushinteger(L, i++);
692 parse_value(L, msg, w);
694 /* put the values to the table */
698 mrp_dbus_msg_exit_container(msg);
704 static bool parse_dict_entry(lua_State *L,
705 mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
707 mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_DICT_ENTRY, NULL);
709 while (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_INVALID) {
711 /* key must be elementary, value can be anything */
712 parse_elementary_value(L, msg, w);
713 parse_value(L, msg, w);
715 /* put the values to the table */
719 mrp_dbus_msg_exit_container(msg); /* dict entry */
724 static bool parse_array(lua_State *L,
725 mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
730 mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_ARRAY, NULL);
732 /* the problem: if the value inside array is a dict entry, the
733 * indexing of elements need to be done with dict keys instead
736 if (mrp_dbus_msg_arg_type(msg, NULL) == MRP_DBUS_TYPE_DICT_ENTRY) {
737 while (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_INVALID) {
738 parse_dict_entry(L, msg, w);
744 while (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_INVALID) {
747 lua_pushinteger(L, i++);
749 parse_value(L, msg, w);
751 /* put the values to the table */
756 mrp_dbus_msg_exit_container(msg); /* array */
761 static bool parse_value(lua_State *L, mrp_dbus_msg_t *msg,
762 dbus_property_watch_t *w)
764 mrp_dbus_type_t curr;
766 curr = mrp_dbus_msg_arg_type(msg, NULL);
769 case MRP_DBUS_TYPE_BYTE:
770 case MRP_DBUS_TYPE_BOOLEAN:
771 case MRP_DBUS_TYPE_INT16:
772 case MRP_DBUS_TYPE_INT32:
773 case MRP_DBUS_TYPE_UINT16:
774 case MRP_DBUS_TYPE_UINT32:
775 case MRP_DBUS_TYPE_DOUBLE:
776 case MRP_DBUS_TYPE_STRING:
777 return parse_elementary_value(L, msg, w);
778 case MRP_DBUS_TYPE_ARRAY:
779 return parse_array(L, msg, w);
780 case MRP_DBUS_TYPE_STRUCT:
781 return parse_struct(L, msg, w);
782 case MRP_DBUS_TYPE_DICT_ENTRY:
783 goto error; /* these are handled from parse_array */
784 case MRP_DBUS_TYPE_INVALID:
791 mrp_log_error("AMB: failed to parse D-Bus property (sig[i] %c)", curr);
795 static void lua_property_handler(mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
798 char *variant_sig = NULL;
802 mrp_log_error("AMB: no dbus property watch set");
806 if (w->lua_prop->handler_ref == LUA_NOREF) {
807 mrp_log_error("AMB: no lua reference");
811 if (mrp_dbus_msg_type(msg) == MRP_DBUS_MESSAGE_TYPE_ERROR) {
812 mrp_log_error("AMB: error message from ambd");
816 if (!mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_VARIANT, NULL)) {
817 mrp_log_error("AMB: message parameter wasn't a variant");
822 mrp_log_info("iter sig: %s, expected: %s",
823 variant_sig, w->lua_prop->dbus_data.signature);
828 /* FIXME: check this when the D-Bus API has support */
829 variant_sig = dbus_message_iter_get_signature(&variant_iter);
832 mrp_log_error("amb: could not get variant signature");
836 /* check if we got what we were expecting */
837 if (strcmp(variant_sig, w->lua_prop->dbus_data.signature) != 0) {
838 mrp_log_error("amb: dbus data signature didn't match");
843 /* load the function pointer to the stack */
844 lua_rawgeti(w->ctx->L, LUA_REGISTRYINDEX, w->lua_prop->handler_ref);
846 /* "self" parameter */
847 mrp_lua_push_object(w->ctx->L, w->lua_prop);
849 /* parse values to the stack */
850 parse_value(w->ctx->L, msg, w);
852 /* call the handler function */
853 lua_pcall(w->ctx->L, 2, 0, 0);
855 mrp_dbus_msg_exit_container(msg);
858 /* TODO: clean up the variant sig string */
863 static void basic_property_handler(mrp_dbus_msg_t *msg, dbus_property_watch_t *w)
874 mrp_log_error("AMB: no dbus property watch set");
878 if (!mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_VARIANT, NULL)) {
879 mrp_log_error("AMB: message parameter wasn't a variant");
883 /* check that D-Bus type matches the expected type */
885 if (mrp_dbus_msg_arg_type(msg, NULL) != w->prop.type) {
886 mrp_log_error("AMB: argument type %c did not match expected type %c",
887 mrp_dbus_msg_arg_type(msg, NULL), w->prop.type);
891 switch (w->prop.type) {
892 case MRP_DBUS_TYPE_INT32:
893 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_INT32, &i32_val);
894 w->prop.value.i = i32_val;
896 case MRP_DBUS_TYPE_INT16:
897 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_INT16, &i16_val);
898 w->prop.value.i = i16_val;
900 case MRP_DBUS_TYPE_UINT32:
901 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT32, &u32_val);
902 w->prop.value.u = u32_val;
904 case MRP_DBUS_TYPE_UINT16:
905 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &u16_val);
906 w->prop.value.u = u16_val;
908 case MRP_DBUS_TYPE_BOOLEAN:
909 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &u32_val);
910 w->prop.value.u = u32_val;
912 case MRP_DBUS_TYPE_BYTE:
913 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_BYTE, &byte_val);
914 w->prop.value.u = byte_val;
916 case MRP_DBUS_TYPE_DOUBLE:
917 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_DOUBLE, &d_val);
918 w->prop.value.f = d_val;
920 case MRP_DBUS_TYPE_STRING:
921 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_STRING, &s_val);
922 w->prop.value.s = mrp_strdup(s_val);
925 mrp_dbus_msg_exit_container(msg);
929 mrp_dbus_msg_exit_container(msg);
932 w->cb(&w->prop, w->user_data);
937 mrp_log_error("AMB: failed to parse property value");
941 static int property_signal_handler(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg,
944 dbus_property_object_t *o = (dbus_property_object_t *) data;
945 dbus_property_watch_t *w;
951 mrp_log_error("AMB: message is NULL");
954 if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_STRING) {
955 mrp_log_error("AMB: argument type %c , expected interface string",
956 mrp_dbus_msg_arg_type(msg, NULL));
960 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_STRING, &interface);
962 /* loop for all the properties */
963 mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_ARRAY, NULL);
965 while (mrp_dbus_msg_arg_type(msg, NULL) == MRP_DBUS_TYPE_DICT_ENTRY) {
968 mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_DICT_ENTRY, NULL);
970 if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_STRING) {
971 mrp_log_error("AMB: argument type %c, expected property name",
972 mrp_dbus_msg_arg_type(msg, NULL));
976 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_STRING, &property_name);
978 /* the right handler for the property is now defined by
979 * property_name and interface */
981 if (interface && property_name) {
982 int interface_len = strlen(interface);
983 int property_name_len = strlen(property_name);
984 char key[interface_len + 1 + property_name_len + 1];
986 strncpy(key, interface, interface_len);
987 *(key+interface_len) = '-';
988 strncpy(key+interface_len+1, property_name, property_name_len);
989 key[interface_len + 1 + property_name_len] = '\0';
991 mrp_debug("AMB: looking up property watch from %p with key '%s'",
994 /* find the right dbus_property_watch */
995 w = mrp_htbl_lookup(o->dbus_properties, key);
998 /* we are interested in this property of this object */
999 mrp_debug("AMB: PropertiesChanged for %s; %s handling",
1000 property_name, w->tdata ? "basic" : "lua");
1002 /* process the variant from the dict */
1004 basic_property_handler(msg, w);
1007 lua_property_handler(msg, w);
1011 mrp_dbus_msg_exit_container(msg); /* dict entry */
1013 mrp_dbus_msg_exit_container(msg); /* array entry */
1018 static void property_reply_handler(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg,
1021 dbus_property_watch_t *w = (dbus_property_watch_t *) data;
1025 mrp_log_info("AMB: received property method reply, going for %s handling",
1026 w->tdata ? "basic" : "lua");
1029 basic_property_handler(msg, w);
1032 lua_property_handler(msg, w);
1037 static void find_property_reply_handler(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg,
1040 dbus_property_watch_t *w = (dbus_property_watch_t *) data;
1045 if (mrp_dbus_msg_type(msg) == MRP_DBUS_MESSAGE_TYPE_ERROR) {
1046 mrp_log_error("AMB: Error when trying to find an AMB object path");
1050 if(!mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_OBJECT_PATH, &obj)) {
1051 mrp_log_error("AMB: Error fetching the object path from the message");
1055 mrp_free((char *) w->lua_prop->dbus_data.obj);
1056 w->lua_prop->dbus_data.obj = mrp_strdup(obj);
1058 mrp_debug("AMB: path for property %s: %s", w->lua_prop->dbus_data.name,
1059 w->lua_prop->dbus_data.obj);
1061 subscribe_property(w->ctx, w);
1068 static int find_property_object(data_t *ctx, dbus_property_watch_t *w,
1071 if (!ctx || !w || !prop)
1074 mrp_log_info("AMB: finding object path of property '%s'", prop);
1076 mrp_dbus_call(ctx->dbus,
1078 "org.automotive.Manager",
1079 "findProperty", 3000, find_property_reply_handler, w,
1080 MRP_DBUS_TYPE_STRING, prop, MRP_DBUS_TYPE_INVALID);
1085 static void free_dbus_property_object(dbus_property_object_t *o)
1087 mrp_htbl_destroy(o->dbus_properties, FALSE);
1092 static void htbl_free_prop(void *key, void *object)
1098 static int subscribe_property(data_t *ctx, dbus_property_watch_t *w)
1100 const char *obj = w->lua_prop->dbus_data.obj;
1101 const char *iface = w->lua_prop->dbus_data.iface;
1102 const char *name = w->lua_prop->dbus_data.name;
1103 dbus_property_object_t *o;
1104 int interface_len = strlen(w->lua_prop->dbus_data.iface);
1105 int name_len = strlen(w->lua_prop->dbus_data.name);
1107 mrp_log_info("AMB: subscribing to PropertiesChanged signal at '%s'", obj);
1109 o = (dbus_property_object_t *) mrp_htbl_lookup(ctx->dbus_property_objects,
1113 mrp_htbl_config_t prop_conf;
1115 prop_conf.comp = mrp_string_comp;
1116 prop_conf.hash = mrp_string_hash;
1117 prop_conf.free = htbl_free_prop;
1118 prop_conf.nbucket = 0;
1119 prop_conf.nentry = 10;
1121 o = (dbus_property_object_t *) mrp_allocz(sizeof(dbus_property_object_t));
1122 o->path = strdup(obj);
1125 o->dbus_properties = mrp_htbl_create(&prop_conf);
1126 if (!o->dbus_properties) {
1131 mrp_htbl_insert(ctx->dbus_property_objects, o->path, o);
1134 /* generate the key and add the watch to the object */
1136 w->key = mrp_allocz(interface_len + 1 + name_len + 1);
1139 free_dbus_property_object(o);
1143 strncpy(w->key, iface, interface_len);
1144 *(w->key+interface_len) = '-';
1145 strncpy(w->key+interface_len+1, name, name_len);
1147 mrp_debug("AMB: inserting property watch to %p with key '%s'", o, w->key);
1149 mrp_htbl_insert(o->dbus_properties, w->key, w);
1152 mrp_dbus_subscribe_signal(ctx->dbus, property_signal_handler, o, NULL,
1153 obj, "org.freedesktop.DBus.Properties", "PropertiesChanged", NULL);
1155 /* Ok, now we are listening to property changes. Let's get the initial
1158 mrp_dbus_call(ctx->dbus,
1160 "org.freedesktop.DBus.Properties",
1161 "Get", 3000, property_reply_handler, w,
1162 MRP_DBUS_TYPE_STRING, iface,
1163 MRP_DBUS_TYPE_STRING, name,
1164 MRP_DBUS_TYPE_INVALID);
1170 static void print_basic_property(dbus_basic_property_t *prop)
1172 switch (prop->type) {
1173 case MRP_DBUS_TYPE_INT32:
1174 case MRP_DBUS_TYPE_INT16:
1175 mrp_debug("AMB: Property %s : %i", prop->name, prop->value.i);
1177 case MRP_DBUS_TYPE_UINT32:
1178 case MRP_DBUS_TYPE_UINT16:
1179 case MRP_DBUS_TYPE_BOOLEAN:
1180 case MRP_DBUS_TYPE_BYTE:
1181 mrp_debug("AMB: Property %s : %u", prop->name, prop->value.u);
1183 case MRP_DBUS_TYPE_DOUBLE:
1184 mrp_debug("AMB: Property %s : %f", prop->name, prop->value.f);
1186 case MRP_DBUS_TYPE_STRING:
1187 mrp_debug("AMB: Property %s : %s", prop->name, prop->value.s);
1190 mrp_log_error("AMB: Unknown value in property");
1194 static void basic_property_updated(dbus_basic_property_t *prop, void *userdata)
1199 dbus_property_watch_t *w = (dbus_property_watch_t *) userdata;
1200 basic_table_data_t *tdata = w->tdata;
1203 mrp_debug("AMB: basic_property_updated");
1205 print_basic_property(prop);
1207 tx = mqi_begin_transaction();
1209 if (!prop->initialized) {
1211 switch (tdata->type) {
1213 buflen = snprintf(buf, 512, "INSERT INTO %s VALUES (1, '%s', %s)",
1214 w->lua_prop->basic_table_name, prop->name, prop->value.s);
1217 buflen = snprintf(buf, 512, "INSERT INTO %s VALUES (1, '%s', %d)",
1218 w->lua_prop->basic_table_name, prop->name, (int) prop->value.i);
1221 buflen = snprintf(buf, 512, "INSERT INTO %s VALUES (1, '%s', %u)",
1222 w->lua_prop->basic_table_name, prop->name, prop->value.u);
1225 buflen = snprintf(buf, 512, "INSERT INTO %s VALUES (1, '%s', %f)",
1226 w->lua_prop->basic_table_name, prop->name, prop->value.f);
1232 if (buflen <= 0 || buflen == 512) {
1236 r = mql_exec_string(mql_result_string, buf);
1238 prop->initialized = TRUE;
1243 switch (tdata->type) {
1245 ret = mql_bind_value(tdata->update_operation, 1, tdata->type,
1249 ret = mql_bind_value(tdata->update_operation, 1, tdata->type,
1253 ret = mql_bind_value(tdata->update_operation, 1, tdata->type,
1257 ret = mql_bind_value(tdata->update_operation, 1, tdata->type,
1265 mrp_log_error("AMB: failed to bind value to update operation");
1269 r = mql_exec_statement(mql_result_string, tdata->update_operation);
1272 mrp_debug("amb: %s", mql_result_is_success(r) ? "updated database" :
1273 mql_result_error_get_message(r));
1278 mqi_commit_transaction(tx);
1281 static void delete_basic_table_data(basic_table_data_t *tdata)
1286 if (tdata->update_operation)
1287 mql_statement_free(tdata->update_operation);
1290 mqi_drop_table(tdata->table);
1295 static basic_table_data_t *create_basic_property_table(const char *table_name,
1296 const char *member, int type)
1299 char *update_format;
1300 /* char *insert_format; */
1301 basic_table_data_t *tdata = NULL;
1304 if (strlen(member) > 64)
1307 tdata = (basic_table_data_t *) mrp_allocz(sizeof(basic_table_data_t));
1313 case MRP_DBUS_TYPE_INT32:
1314 case MRP_DBUS_TYPE_INT16:
1315 tdata->type = mqi_integer;
1316 update_format = "%d";
1317 /* insert_format = "%d"; */
1319 case MRP_DBUS_TYPE_UINT32:
1320 case MRP_DBUS_TYPE_UINT16:
1321 case MRP_DBUS_TYPE_BOOLEAN:
1322 case MRP_DBUS_TYPE_BYTE:
1323 tdata->type = mqi_unsignd;
1324 update_format = "%u";
1325 /* insert_format = "%u"; */
1327 case MRP_DBUS_TYPE_DOUBLE:
1328 tdata->type = mqi_floating;
1329 update_format = "%f";
1330 /* insert_format = "%f"; */
1332 case MRP_DBUS_TYPE_STRING:
1333 tdata->type = mqi_varchar;
1334 update_format = "%s";
1335 /* insert_format = "'%s'"; */
1338 mrp_log_error("unknown type %d", type);
1342 tdata->defs[0].name = "id";
1343 tdata->defs[0].type = mqi_unsignd;
1344 tdata->defs[0].length = 0;
1345 tdata->defs[0].flags = 0;
1347 tdata->defs[1].name = "key";
1348 tdata->defs[1].type = mqi_varchar;
1349 tdata->defs[1].length = 64;
1350 tdata->defs[1].flags = 0;
1352 tdata->defs[2].name = "value";
1353 tdata->defs[2].type = tdata->type;
1354 tdata->defs[2].length = (tdata->type == mqi_varchar) ? 128 : 0;
1355 tdata->defs[2].flags = 0;
1357 memset(&tdata->defs[3], 0, sizeof(tdata->defs[3]));
1359 tdata->table = MQI_CREATE_TABLE((char *) table_name, MQI_TEMPORARY,
1362 if (!tdata->table) {
1363 mrp_log_error("AMB: creating table '%s' failed", table_name);
1367 ret = snprintf(buf, 512, "UPDATE %s SET value = %s where id = 1",
1368 table_name, update_format);
1370 if (ret <= 0 || ret == 512) {
1374 tdata->update_operation = mql_precompile(buf);
1376 if (!tdata->update_operation) {
1377 mrp_log_error("AMB: buggy buf: '%s'", buf);
1381 mrp_log_info("AMB: compiled update statement '%s'", buf);
1386 mrp_log_error("AMB: failed to create table %s", table_name);
1387 delete_basic_table_data(tdata);
1391 static int load_config(lua_State *L, const char *path)
1393 if (!luaL_loadfile(L, path) && !lua_pcall(L, 0, 0, 0))
1396 mrp_log_error("AMB: failed to load config file %s.", path);
1397 mrp_log_error("%s", lua_tostring(L, -1));
1404 static void amb_startup_timer(mrp_timer_t *t, void *data)
1406 data_t *ctx = (data_t *) data;
1407 mrp_list_hook_t *p, *n;
1411 /* check that ambd hasn't crashed meanwhile */
1413 if (!ctx->force_subscription && ctx->amb_state != MRP_PROCESS_STATE_READY)
1416 mrp_log_info("AMB: delayed querying of ambd properties\n");
1418 /* query the ambd property D-Bus paths again and start listening to
1421 mrp_list_foreach(&ctx->lua_properties, p, n) {
1422 dbus_property_watch_t *w =
1423 mrp_list_entry(p, dbus_property_watch_t, hook);
1425 if (w->lua_prop->dbus_data.undefined_object_path)
1426 find_property_object(ctx, w, w->lua_prop->dbus_data.objectname);
1428 subscribe_property(ctx, w);
1432 static int unsubscribe_signal_cb(void *key, void *object, void *user_data)
1434 dbus_property_object_t *o = (dbus_property_object_t *) object;
1435 data_t *ctx = (data_t *) user_data;
1439 mrp_dbus_unsubscribe_signal(ctx->dbus, property_signal_handler, o,
1441 "org.freedesktop.DBus.Properties",
1442 "PropertiesChanged", NULL);
1443 return MRP_HTBL_ITER_MORE;
1446 static void amb_watch(const char *id, mrp_process_state_t state, void *data)
1448 data_t *ctx = (data_t *) data;
1450 if (strcmp(id, ctx->amb_id) != 0)
1453 mrp_log_info("AMB: ambd state changed to %s",
1454 state == MRP_PROCESS_STATE_READY ? "ready" : "not ready");
1457 if (state == MRP_PROCESS_STATE_NOT_READY &&
1458 ctx->amb_state == MRP_PROCESS_STATE_READY) {
1460 mrp_log_error("AMB: lost connection to ambd");
1462 /* stop listening to the ambd signals */
1463 mrp_htbl_foreach(ctx->dbus_property_objects, unsubscribe_signal_cb, ctx);
1465 else if (state == MRP_PROCESS_STATE_READY &&
1466 ctx->amb_state != MRP_PROCESS_STATE_READY) {
1468 mrp_log_info("AMB: ambd was started up\n");
1470 /* give amb some time to get the D-Bus interface ready */
1472 mrp_add_timer(ctx->ml, ctx->amb_startup_delay, amb_startup_timer, ctx);
1475 ctx->amb_state = state;
1478 /* functions for handling updating the AMB properties */
1480 static int update_amb_property(char *name, enum amb_type type, void *value,
1484 mrp_msg_t *msg = mrp_msg_create(
1485 MRP_MSG_TAG_STRING(1, name),
1496 mrp_msg_append(msg, 2, MRP_MSG_FIELD_STRING, value);
1499 mrp_msg_append(msg, 2, MRP_MSG_FIELD_BOOL, *(bool *)value);
1502 mrp_msg_append(msg, 2, MRP_MSG_FIELD_INT32, *(int32_t *)value);
1505 mrp_msg_append(msg, 2, MRP_MSG_FIELD_INT16, *(int16_t *)value);
1508 mrp_msg_append(msg, 2, MRP_MSG_FIELD_UINT32, *(uint32_t *)value);
1511 mrp_msg_append(msg, 2, MRP_MSG_FIELD_UINT16, *(uint16_t *)value);
1514 mrp_msg_append(msg, 2, MRP_MSG_FIELD_UINT8, *(uint8_t *)value);
1517 mrp_msg_append(msg, 2, MRP_MSG_FIELD_DOUBLE, *(double *)value);
1521 if (!mrp_transport_send(ctx->t, msg))
1524 mrp_log_info("AMB: Sent message to ambd");
1536 static bool initiate_func(lua_State *L, void *data,
1537 const char *signature, mrp_funcbridge_value_t *args,
1538 char *ret_type, mrp_funcbridge_value_t *ret_val)
1544 if (!signature || signature[0] != 'o') {
1548 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1549 ret_val->boolean = true;
1555 static bool update_func(lua_State *L, void *data,
1556 const char *signature, mrp_funcbridge_value_t *args,
1557 char *ret_type, mrp_funcbridge_value_t *ret_val)
1559 mrp_lua_sink_t *sink;
1560 const char *type, *property;
1568 char *error = "unknown error";
1572 if (!signature || signature[0] != 'o') {
1573 mrp_log_error("AMB: invalid signature '%s'", signature ? signature : "NULL");
1577 sink = (mrp_lua_sink_t *) args[0].pointer;
1579 property = mrp_lua_sink_get_property(sink);
1581 if (!property || strlen(property) == 0) {
1582 error = "invalid property";
1586 /* ok, for now we only support updates of basic values */
1588 type = mrp_lua_sink_get_type(sink);
1590 if (!type || strlen(type) != 1) {
1591 error = "invalid type";
1597 d_val = mrp_lua_sink_get_floating(sink,0,0,0);
1598 ret = update_amb_property((char *) property,
1599 (enum amb_type) type[0], &d_val, (data_t *) data);
1603 i_val = mrp_lua_sink_get_integer(sink,0,0,0);
1604 ret = update_amb_property((char *) property,
1605 (enum amb_type) type[0], &i_val, (data_t *) data);
1611 u_val = mrp_lua_sink_get_unsigned(sink,0,0,0);
1612 ret = update_amb_property((char *) property,
1613 (enum amb_type) type[0], &u_val, (data_t *) data);
1616 s_val = mrp_lua_sink_get_string(sink,0,0,0,NULL,0);
1617 ret = update_amb_property((char *) property,
1618 (enum amb_type) type[0], (void *) s_val,
1624 error = "error updating property";
1628 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1629 ret_val->boolean = true;
1634 mrp_log_error("AMB: error processing the property change!");
1636 *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1637 ret_val->boolean = false;
1639 /* FIXME: this shouldn't be needed, but without this the element handler crashes */
1640 ret_val->string = mrp_strdup(error);
1646 static void recvdatafrom_evt(mrp_transport_t *t, void *data, uint16_t tag,
1647 mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
1649 /* At the moment we are not receiving anything from AMB through this
1650 * transport, however that might change */
1656 MRP_UNUSED(addrlen);
1657 MRP_UNUSED(user_data);
1661 static void recvdata_evt(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
1663 recvdatafrom_evt(t, data, tag, NULL, 0, user_data);
1667 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
1669 data_t *ctx = (data_t *) user_data;
1673 mrp_transport_destroy(t);
1676 /* open the listening socket again */
1679 create_transport(t->ml, ctx);
1683 static void connection_evt(mrp_transport_t *lt, void *user_data)
1685 data_t *ctx = (data_t *) user_data;
1687 mrp_log_info("AMB connection!");
1690 mrp_log_error("AMB: already connected");
1693 ctx->t = mrp_transport_accept(lt, ctx, 0);
1695 /* amb murphy plugin is now connected to us */
1698 /* close the listening socket, since we only have one client */
1700 mrp_transport_destroy(lt);
1705 static int create_transport(mrp_mainloop_t *ml, data_t *ctx)
1708 mrp_sockaddr_t addr;
1709 int flags = MRP_TRANSPORT_REUSEADDR | MRP_TRANSPORT_MODE_MSG;
1711 struct stat statbuf;
1713 static mrp_transport_evt_t evt; /* static members are initialized to zero */
1715 evt.closed = closed_evt;
1716 evt.connection = connection_evt;
1717 evt.recvdata = recvdata_evt;
1718 evt.recvdatafrom = recvdatafrom_evt;
1720 alen = mrp_transport_resolve(NULL, ctx->tport_addr, &addr, sizeof(addr),
1723 mrp_log_error("AMB: failed to resolve address");
1727 /* remove the old socket if present */
1729 if (strcmp(atype, "unxs") == 0) {
1730 char *path = addr.unx.sun_path;
1731 if (path[0] == '/') {
1732 /* if local socket and file exists, remove it */
1733 if (stat(path, &statbuf) == 0) {
1734 if (S_ISSOCK(statbuf.st_mode)) {
1735 if (unlink(path) < 0) {
1736 mrp_log_error("error removing the socket");
1741 mrp_log_error("AMB: a file where the socket should be");
1749 ctx->lt = mrp_transport_create(ml, atype, &evt, ctx, flags);
1750 if (ctx->lt == NULL) {
1751 mrp_log_error("AMB: failed to create transport");
1755 if (!mrp_transport_bind(ctx->lt, &addr, alen)) {
1756 mrp_log_error("AMB: failed to bind transport to address");
1760 if (!mrp_transport_listen(ctx->lt, 1)) {
1761 mrp_log_error("AMB: failed to listen on transport");
1769 mrp_transport_destroy(ctx->lt);
1775 static void htbl_free_obj(void *key, void *object)
1777 dbus_property_object_t *o = (dbus_property_object_t *) object;
1781 free_dbus_property_object(o);
1785 /* plugin init and deinit */
1787 static int amb_init(mrp_plugin_t *plugin)
1790 mrp_plugin_arg_t *args = plugin->args;
1791 mrp_htbl_config_t obj_conf;
1793 ctx = (data_t *) mrp_allocz(sizeof(data_t));
1798 mrp_list_init(&ctx->lua_properties);
1802 ctx->ml = plugin->ctx->ml;
1804 ctx->amb_addr = args[ARG_AMB_DBUS_ADDRESS].str;
1805 ctx->config_file = args[ARG_AMB_CONFIG_FILE].str;
1806 ctx->amb_id = args[ARG_AMB_ID].str;
1807 ctx->tport_addr = args[ARG_AMB_TPORT_ADDRESS].str;
1808 ctx->amb_startup_delay = args[ARG_AMB_STARTUP_DELAY].u32;
1809 ctx->force_subscription = args[ARG_AMB_FORCE_SUBSCRIPTION].bln;
1811 mrp_log_info("AMB: D-Bus address: %s", ctx->amb_addr);
1812 mrp_log_info("AMB: config file: %s", ctx->config_file);
1813 mrp_log_info("AMB: transport address: %s", ctx->tport_addr);
1814 mrp_log_info("AMB: %s D-Bus subscription",
1815 ctx->force_subscription ? "forced" : "didn't force");
1817 ctx->dbus = mrp_dbus_connect(plugin->ctx->ml, args[ARG_AMB_DBUS_BUS].str,
1823 /* initialize transport towards ambd */
1825 if (create_transport(plugin->ctx->ml, ctx) < 0)
1828 /* create hash table */
1830 obj_conf.comp = mrp_string_comp;
1831 obj_conf.hash = mrp_string_hash;
1832 obj_conf.free = htbl_free_obj;
1833 obj_conf.nbucket = 0;
1834 obj_conf.nentry = 10;
1836 ctx->dbus_property_objects = mrp_htbl_create(&obj_conf);
1838 if (!ctx->dbus_property_objects)
1841 /* initialize lua support */
1845 ctx->L = mrp_lua_get_lua_state();
1850 /* functions to handle the direct property updates */
1852 mrp_funcbridge_create_cfunc(ctx->L, "amb_initiate", "o",
1853 initiate_func, (void *)ctx);
1854 mrp_funcbridge_create_cfunc(ctx->L, "amb_update", "o",
1855 update_func, (void *)ctx);
1857 /* custom class for configuration */
1859 mrp_lua_create_object_class(ctx->L, MRP_LUA_CLASS(amb, property));
1861 /* TODO: create here a "manager" lua object and put that to the global
1862 * lua table? This one then has a pointer to the C context. */
1864 /* 1. read the configuration file. The configuration must tell
1865 - target object (/org/automotive/runningstatus/vehicleSpeed)
1866 - target interface (org.automotive.vehicleSpeed)
1867 - target member (VehicleSpeed)
1868 - target type (int32_t)
1872 if (!load_config(ctx->L, ctx->config_file))
1875 mrp_process_set_state("murphy-amb", MRP_PROCESS_STATE_READY);
1877 if (mrp_process_set_watch(ctx->amb_id, plugin->ctx->ml, amb_watch, ctx) < 0) {
1878 /* let's not quit yet? */
1879 mrp_log_error("AMB: setting the ambd status watch failed");
1882 ctx->amb_state = mrp_process_query_state(ctx->amb_id);
1884 /* query amb properties after amb has had time to ready the interface */
1886 if (ctx->force_subscription || ctx->amb_state == MRP_PROCESS_STATE_READY) {
1887 mrp_log_info("added the ambd timer after %u ms", ctx->amb_startup_delay);
1888 mrp_add_timer(ctx->ml, ctx->amb_startup_delay, amb_startup_timer, ctx);
1895 mrp_list_hook_t *p, *n;
1897 mrp_list_foreach(&ctx->lua_properties, p, n) {
1898 dbus_property_watch_t *w =
1899 mrp_list_entry(p, dbus_property_watch_t, hook);
1901 destroy_prop(ctx, w);
1906 mrp_dbus_unref(ctx->dbus);
1911 mrp_transport_destroy(ctx->t);
1915 if (ctx->dbus_property_objects) {
1916 mrp_htbl_destroy(ctx->dbus_property_objects, FALSE);
1919 mrp_process_remove_watch(ctx->amb_id);
1927 static void amb_exit(mrp_plugin_t *plugin)
1929 data_t *ctx = (data_t *) plugin->data;
1930 mrp_list_hook_t *p, *n;
1932 mrp_process_remove_watch(ctx->amb_id);
1934 mrp_process_set_state("murphy-amb", MRP_PROCESS_STATE_NOT_READY);
1936 /* for all subscribed properties, unsubscribe and free memory */
1938 mrp_list_foreach(&ctx->lua_properties, p, n) {
1939 dbus_property_watch_t *w =
1940 mrp_list_entry(p, dbus_property_watch_t, hook);
1942 destroy_prop(ctx, w);
1945 if (ctx->dbus_property_objects) {
1946 mrp_htbl_destroy(ctx->dbus_property_objects, FALSE);
1949 mrp_transport_destroy(ctx->t);
1957 #define AMB_DESCRIPTION "A plugin for Automotive Message Broker D-Bus API."
1958 #define AMB_HELP "Access Automotive Message Broker."
1959 #define AMB_VERSION MRP_VERSION_INT(0, 0, 2)
1960 #define AMB_AUTHORS "Ismo Puustinen <ismo.puustinen@intel.com>"
1962 static mrp_plugin_arg_t args[] = {
1963 MRP_PLUGIN_ARGIDX(ARG_AMB_DBUS_ADDRESS, STRING, "amb_address",
1964 "org.automotive.message.broker"),
1965 MRP_PLUGIN_ARGIDX(ARG_AMB_DBUS_BUS, STRING, "dbus_bus", "system"),
1966 MRP_PLUGIN_ARGIDX(ARG_AMB_CONFIG_FILE, STRING, "config_file",
1967 "/etc/murphy/plugins/amb/config.lua"),
1968 MRP_PLUGIN_ARGIDX(ARG_AMB_ID, STRING, "amb_id", "ambd"),
1969 MRP_PLUGIN_ARGIDX(ARG_AMB_TPORT_ADDRESS, STRING, "transport_address",
1970 "unxs:/tmp/murphy/amb"),
1971 MRP_PLUGIN_ARGIDX(ARG_AMB_STARTUP_DELAY, UINT32, "amb_startup_delay",
1973 MRP_PLUGIN_ARGIDX(ARG_AMB_FORCE_SUBSCRIPTION, BOOL,
1974 "force_subscription", false),
1977 MURPHY_REGISTER_PLUGIN("amb",
1978 AMB_VERSION, AMB_DESCRIPTION,
1979 AMB_AUTHORS, AMB_HELP,
1980 MRP_SINGLETON, amb_init, amb_exit,
1981 args, MRP_ARRAY_SIZE(args),
1982 NULL, 0, NULL, 0, NULL);