aml-dbus: add aml-dbus source [1/1]
PD#SWPL-155651
Problem:
add aml-dbus source
Solution:
add aml-dbus source
Verify:
local
Change-Id: I02132b92e0841b577ecb9467f9b73e6b159dec1a
Signed-off-by: Daogao Xu <daogao.xu@amlogic.com>
diff --git a/aml_dbus/Makefile b/aml_dbus/Makefile
new file mode 100644
index 0000000..4ebaae5
--- /dev/null
+++ b/aml_dbus/Makefile
@@ -0,0 +1,66 @@
+LDLIBS += -lsystemd -lpthread
+LINK:=$(CC)
+
+LIB_VER=0
+
+# BUILDDIR used for out-of-source compile
+BUILDDIR?=./
+
+all:
+
+.PHONY: clean
+
+define build_project
+OBJ_C := $(patsubst %.c,$(TARGET)_o/%.o,$(filter %.c,$2))
+OBJ_CXX := $(patsubst %.cpp,$(TARGET)_o/%.o,$(filter %.cpp,$2))
+OBJ_PATH := $(addprefix $(TARGET)_o/, $(sort $(dir $2)))
+_dummy := $$(shell mkdir -p $$(OBJ_PATH))
+$(TARGET):OBJ_ALL:=$$(OBJ_C) $$(OBJ_CXX)
+$(TARGET):LINK:=$(if $(filter %.cpp,$2),$(CXX),$(CC))
+$(TARGET)_clean:CLEAN_FILES:=$(TARGET) $$(OBJ_PATH) $(TARGET)_o
+ifneq (,$(findstring shared_lib,$1))
+ifneq ($(suffix $(TARGET)),.so)
+all:$(basename $(TARGET))
+$(basename $(TARGET)):$(TARGET)
+ ln -frs $$< $$@
+endif
+endif
+$(TARGET): $$(OBJ_C) $$(OBJ_CXX)
+ifneq (,$(findstring shared_lib,$1))
+ $$(LINK) $$(CPPFLAGS) $$(LDFLAGS) -shared -Wl,-soname,$(notdir $(TARGET)) -o $$@ $$(OBJ_ALL) $$(LDLIBS)
+else ifneq (,$(findstring static_lib,$1))
+ $(AR) rcs -o $$@ $$+
+ $(RANLIB) $$@
+else
+ $$(LINK) $$(CPPFLAGS) $$(LDFLAGS) -o $$@ $$(OBJ_ALL) $$(LDLIBS)
+endif
+
+$$(OBJ_C):$(TARGET)_o/%.o:%.c
+ $$(CC) $$(CPPFLAGS) $$(CFLAGS) -c $$< -o $$@
+
+$$(OBJ_CXX):$(TARGET)_o/%.o:%.cpp
+ $$(CXX) $$(CPPFLAGS) $$(CXXFLAGS) -c $$< -o $$@
+
+.PHONY: $(TARGET)_clean
+
+$(TARGET)_clean:
+ -rm -rf $$(abspath $$(CLEAN_FILES))
+
+clean: $(TARGET)_clean
+
+all:$(TARGET)
+
+endef
+
+TARGET := $(BUILDDIR)/libamldbus.so.$(LIB_VER)
+$(eval $(call build_project,shared_lib,aml-dbus.c))
+
+TARGET := $(BUILDDIR)/aml-dbus-test
+$(eval $(call build_project,exe,aml-dbus-test.cpp aml-dbus.c))
+
+TARGET := $(BUILDDIR)/ambus-sample-server
+$(eval $(call build_project,exe,sample-server.c aml-dbus.c))
+
+TARGET := $(BUILDDIR)/ambus-sample-client
+$(eval $(call build_project,exe,sample-client.c aml-dbus.c))
+
diff --git a/aml_dbus/aml-dbus-generator.h b/aml_dbus/aml-dbus-generator.h
new file mode 100644
index 0000000..9bc7abc
--- /dev/null
+++ b/aml_dbus/aml-dbus-generator.h
@@ -0,0 +1,114 @@
+#ifndef AMBUS_GENERATOR
+#define AMBUS_GENERATOR
+#endif
+
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#define AMBUS_BEGIN_INTF(SERVICE, OBJ, INTF) enum {
+#define AMBUS_PROP(_member, _signature) MACRO_CAT2(AMBUS_INTERFACE_ID, _member##_enum),
+#define AMBUS_PROPRW(_member, _signature) MACRO_CAT2(AMBUS_INTERFACE_ID, _member##_enum),
+#define AMBUS_METHOD(_member, _signature, _result) MACRO_CAT2(AMBUS_INTERFACE_ID, _member##_enum),
+#define AMBUS_SIGNAL(_member, _signature) MACRO_CAT2(AMBUS_INTERFACE_ID, _member##_enum),
+#define AMBUS_END_INTF() \
+ MACRO_CAT2(AMBUS_INTERFACE_ID, _END) \
+ } \
+ ;
+#include AMBUS_INTERFACE_FILE
+
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#define AMBUS_BEGIN_INTF(SERVICE, OBJ, INTF) extern struct ambus_interface MACRO_CAT2(AMBUS_INTERFACE_ID, _interface);
+#define AMBUS_PROP(_member, _signature)
+#define AMBUS_PROPRW(_member, _signature)
+#define AMBUS_METHOD(_member, _signature, _result)
+#define AMBUS_SIGNAL(_member, _signature)
+#define AMBUS_END_INTF()
+#include AMBUS_INTERFACE_FILE
+
+#ifdef AMBUS_GENERATE_INTERFACE
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#define AMBUS_BEGIN_INTF(SERVICE, OBJ, INTF) \
+ struct ambus_interface MACRO_CAT2(AMBUS_INTERFACE_ID, _interface) = {SERVICE, OBJ, INTF, {
+#define AMBUS_PROP(_member, _signature) {#_member, _signature, NULL},
+#define AMBUS_PROPRW(_member, _signature) {#_member, _signature, NULL},
+#define AMBUS_METHOD(_member, _signature, _result) {#_member, _signature, _result},
+#define AMBUS_SIGNAL(_member, _signature) {#_member, _signature, NULL},
+#define AMBUS_END_INTF() \
+ { NULL, NULL, NULL } \
+ } \
+ } \
+ ;
+#include AMBUS_INTERFACE_FILE
+#endif // AMBUS_GENERATE_INTERFACE
+
+#ifdef AMBUS_GENERATE_VTABLE
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#define AMBUS_BEGIN_INTF(SERVICE, OBJ, INTF)
+#define AMBUS_PROP(_member, _signature) \
+ static int MACRO_CAT2(AMBUS_INTERFACE_ID, _property_get)(sd_bus * bus, const char *path, const char *interface, \
+ const char *property, sd_bus_message *reply, \
+ void *userdata, sd_bus_error *ret_error);
+#define AMBUS_PROPRW(_member, _signature) \
+ static int MACRO_CAT2(AMBUS_INTERFACE_ID, _property_get)(sd_bus * bus, const char *path, const char *interface, \
+ const char *property, sd_bus_message *reply, \
+ void *userdata, sd_bus_error *ret_error); \
+ static int MACRO_CAT2(AMBUS_INTERFACE_ID, _property_set)(sd_bus * bus, const char *path, const char *interface, \
+ const char *property, sd_bus_message *value, \
+ void *userdata, sd_bus_error *ret_error);
+#define AMBUS_METHOD(_member, _signature, _result) \
+ static int MACRO_CAT2(AMBUS_INTERFACE_ID, _method_##_member)(sd_bus_message * m, void *userdata, \
+ sd_bus_error *ret_error);
+#define AMBUS_SIGNAL(_member, _signature)
+#define AMBUS_END_INTF()
+#include AMBUS_INTERFACE_FILE
+
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#define AMBUS_BEGIN_INTF(SERVICE, OBJ, INTF) \
+ static const sd_bus_vtable MACRO_CAT2(AMBUS_INTERFACE_ID, _vtable)[] = {SD_BUS_VTABLE_START(0),
+#define AMBUS_PROP(_member, _signature) \
+ SD_BUS_PROPERTY(#_member, _signature, MACRO_CAT2(AMBUS_INTERFACE_ID, _property_get), 0, 0),
+#define AMBUS_PROPRW(_member, _signature) \
+ SD_BUS_WRITABLE_PROPERTY(#_member, _signature, MACRO_CAT2(AMBUS_INTERFACE_ID, _property_get), \
+ MACRO_CAT2(AMBUS_INTERFACE_ID, _property_set), 0, 0),
+#define AMBUS_METHOD(_member, _signature, _result) \
+ SD_BUS_METHOD(#_member, _signature, _result, MACRO_CAT2(AMBUS_INTERFACE_ID, _method_##_member), \
+ SD_BUS_VTABLE_UNPRIVILEGED),
+#define AMBUS_SIGNAL(_member, _signature) SD_BUS_SIGNAL(#_member, _signature, 0),
+#define AMBUS_END_INTF() \
+ SD_BUS_VTABLE_END \
+ } \
+ ;
+#include AMBUS_INTERFACE_FILE
+#endif // AMBUS_GENERATE_VTABLE
+
+#undef AMBUS_BEGIN_INTF
+#undef AMBUS_PROP
+#undef AMBUS_PROPRW
+#undef AMBUS_METHOD
+#undef AMBUS_SIGNAL
+#undef AMBUS_END_INTF
+#undef AMBUS_GENERATOR
+
diff --git a/aml_dbus/aml-dbus-test.cpp b/aml_dbus/aml-dbus-test.cpp
new file mode 100644
index 0000000..6b0e544
--- /dev/null
+++ b/aml_dbus/aml-dbus-test.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014-2019 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * 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.
+ */
+
+#include "aml-dbus.h"
+#include <ctype.h>
+#include <string>
+#include <vector>
+
+const char *test_service = "amlogic.yocto.test";
+const char *test_object = "/amlogic/yocto/test/obj1";
+const char *test_interface = "amlogic.yocto.test.intf1";
+
+struct TestStruct {
+ std::string name;
+ int ival;
+ float fval;
+ bool bval;
+};
+
+int test_func1(int a1, const int a2, const int &a3, int &a4) {
+ a4 = a1 + a2 + a3;
+ int ret = a1;
+ fprintf(stderr, "call test_func1(a1=%d,a2=%d, a3=%d, a4=%d, ret=%d\n", a1, a2, a3, a4, ret);
+ return ret;
+}
+
+int test_func2(const std::string &arg1, std::vector<std::string> &out1, TestStruct & out2) {
+ fprintf(stderr, "call test_func2 %s\n", arg1.c_str());
+ out1 = {"1", "2", "3", arg1};
+ out2 = {arg1, arg1.size(), arg1.size() * 1.0, isdigit(arg1[0])};
+ return 0;
+}
+
+std::unordered_map<std::string, TestStruct> test_func3() {
+ return {{"key1", {"n1", 10, 0.123, true}}, {"key2", {"n2", 20, 0.456, false}}};
+}
+
+AMBUS_STRUCT_DEFINE(TestStruct, name, ival, fval, bval);
+
+static int ambus_method_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ struct ambus_method_call<> *pcall = (struct ambus_method_call<> *)userdata;
+ return pcall->call(m);
+}
+
+#define NEW_METHOD_ITEM(P, f, ...) new ambus_method_call<decltype(&f)>(#f, &f),
+#define NEW_METHOD_VTABLE(P, f, ...) \
+ SD_BUS_METHOD_WITH_OFFSET(#f, ambus_method_call<decltype(&f)>::data_pack::signature_input::value, \
+ ambus_method_call<decltype(&f)>::signature_output::value, ambus_method_handler, \
+ (size_t)*P##_methods_ptr++, 0),
+
+#define REGISTER_DBUS_METHOD(P, ...) \
+ static const ambus_method_call<> *P##_methods[] = {MACRO_MAP(NEW_METHOD_ITEM, P, __VA_ARGS__)}, \
+ **P##_methods_ptr = P##_methods; \
+ static const sd_bus_vtable P##_vtable[] = {SD_BUS_VTABLE_START(0), \
+ MACRO_MAP(NEW_METHOD_VTABLE, P, __VA_ARGS__) SD_BUS_VTABLE_END};
+
+#define CALL_DBUS(f, ...) \
+ ambus_method_proxy<decltype(&f)>::call(ambus, test_service, test_object, test_interface, #f, ##__VA_ARGS__)
+
+REGISTER_DBUS_METHOD(test, test_func1, test_func2, test_func3);
+// above macro will generate code similar as the comment line below:
+#if 0
+static const ambus_method_call<> *test_methods[] = {
+ new ambus_method_call<decltype(&test_func1)>("test_func1", &test_func1),
+ new ambus_method_call<decltype(&test_func2)>("test_func2", &test_func2),
+};
+
+static const sd_bus_vtable test_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD_WITH_OFFSET("test_func1", ambus_method_call<decltype(&test_func1)>::data_pack::signature_input::value,
+ ambus_method_call<decltype(&test_func1)>::signature_output::value, ambus_method_handler,
+ (size_t)test_methods[0], 0),
+ SD_BUS_METHOD_WITH_OFFSET("test_func2", ambus_method_call<decltype(&test_func2)>::data_pack::signature_input::value,
+ ambus_method_call<decltype(&test_func2)>::signature_output::value, ambus_method_handler,
+ (size_t)test_methods[1], 0),
+ SD_BUS_VTABLE_END};
+
+#endif
+
+int main(int argc, char *argv[]) {
+ int r;
+ if (argc != 2) {
+ printf("USAGE: %s server/client\n", argv[0]);
+ return 1;
+ }
+ if (strcmp(argv[1], "server") == 0) {
+ struct aml_dbus *ambus = ambus_new(NULL, 0);
+ sd_bus_add_object_vtable(ambus_sdbus(ambus), NULL, test_object, test_interface, test_vtable, NULL);
+ sd_bus_request_name(ambus_sdbus(ambus), test_service, 0LL);
+ ambus_run(ambus);
+ } else if (strcmp(argv[1], "client") == 0) {
+ struct aml_dbus *ambus = ambus_ensure_run(NULL);
+ int a1 = 1;
+ int a2 = 2;
+ const int a3 = 10;
+ int a4 = 0;
+ // int r = ambus_method_proxy<decltype(&test_func1)>::call(ambus, test_service, test_object,
+ // test_interface, "test_func1", a1, a2, a3, a4);
+ int r = CALL_DBUS(test_func1, a1, a2, a3, a4);
+ printf("call test_func1 %d %d %d %d ret %d\n", a1, a2, a3, a4, r);
+
+ const std::string arg1 = "arg1";
+ std::vector<std::string> out1;
+ TestStruct out2;
+ r = ambus_method_proxy<decltype(&test_func2)>::call(ambus, test_service, test_object, test_interface, "test_func2",
+ arg1, out1, out2);
+ printf("call test_func2(%s) ret %d, out2: name:%s ival:%d fval:%f bval:%d out1:", arg1.c_str(), r,
+ out2.name.c_str(), out2.ival, out2.fval, out2.bval);
+ for (auto &e : out1)
+ printf("%s ", e.c_str());
+ printf("\n");
+
+ const std::unordered_map<std::string, TestStruct> &out3 = CALL_DBUS(test_func3);
+ printf("call test_func3 return ");
+ for (auto &e : out3)
+ printf("%s:(%s,%d,%f,%d),", e.first.c_str(), e.second.name.c_str(), e.second.ival, e.second.fval, e.second.bval);
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/aml_dbus/aml-dbus.c b/aml_dbus/aml-dbus.c
new file mode 100644
index 0000000..77b9cba
--- /dev/null
+++ b/aml_dbus/aml-dbus.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2014-2019 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * 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.
+ */
+
+#include "aml-dbus.h"
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <time.h>
+#include <unistd.h>
+
+struct delay_task {
+ struct delay_task *next;
+ void (*cb)(void *);
+ void *param;
+ sd_event_source *src;
+ struct aml_dbus *ambus;
+ uint32_t delay_ms;
+};
+
+struct aml_dbus {
+ sd_bus *bus;
+ sd_event *event;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ pthread_t dispatch_thread;
+ int msgpipe[2];
+ struct delay_task *free_task;
+};
+
+static int msgpipe_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ void *args[2];
+ int len = read(fd, &args, sizeof(args));
+ if (len != sizeof(args)) {
+ AMBUS_LOGW("read %d bytes return %d, errno %d %s", (int)sizeof(args), len, errno, strerror(errno));
+ } else
+ ((void (*)(void *))args[0])(args[1]);
+ return 0;
+}
+
+int ambus_post_task(struct aml_dbus *ambus, void (*cb)(void *), void *param) {
+ void *args[] = {cb, param};
+ int len = write(ambus->msgpipe[1], args, sizeof(args));
+ if (len != sizeof(args)) {
+ AMBUS_LOGW("write %d bytes return %d, errno %d %s", (int)sizeof(args), len, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int delay_task_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ struct delay_task *task = (struct delay_task *)userdata;
+ struct aml_dbus *ambus = task->ambus;
+ pthread_mutex_lock(&ambus->lock);
+ task->next = ambus->free_task;
+ ambus->free_task = task;
+ pthread_mutex_unlock(&ambus->lock);
+ task->cb(task->param);
+ return 0;
+}
+
+static void delay_task_settimer(void *param) {
+ struct delay_task *task = (struct delay_task *)param;
+ struct aml_dbus *ambus = task->ambus;
+ uint64_t timeout;
+ int r = sd_event_now(ambus->event, CLOCK_MONOTONIC, &timeout);
+ timeout += task->delay_ms * 1000LL;
+ if (task->src)
+ r = sd_event_source_set_time(task->src, timeout);
+ else
+ r = sd_event_add_time(ambus->event, &task->src, CLOCK_MONOTONIC, timeout, 1000LL * 10, delay_task_timeout, task);
+ if (r >= 0)
+ sd_event_source_set_enabled(task->src, SD_EVENT_ONESHOT);
+}
+
+int ambus_post_delay_task(struct aml_dbus *ambus, uint32_t delay_ms, void (*cb)(void *), void *param) {
+ if (delay_ms == 0)
+ return ambus_post_task(ambus, cb, param);
+ pthread_mutex_lock(&ambus->lock);
+ struct delay_task *task = ambus->free_task;
+ if (task)
+ ambus->free_task = task->next;
+ else {
+ task = calloc(1, sizeof(*task));
+ task->ambus = ambus;
+ }
+ pthread_mutex_unlock(&ambus->lock);
+ task->cb = cb;
+ task->param = param;
+ task->delay_ms = delay_ms;
+ return ambus_post_task(ambus, delay_task_settimer, task);
+}
+
+void ambus_free(struct aml_dbus *ambus) {
+ if (!ambus_in_dispatch_thread(ambus)) {
+ POST_AND_WAIT_DISPATCH(ambus, ambus_free(ambus));
+ pthread_join(ambus->dispatch_thread, NULL);
+ free(ambus);
+ } else {
+ if (ambus->event) {
+ sd_event_exit(ambus->event, 0);
+ sd_event_unref(ambus->event);
+ }
+ if (ambus->bus)
+ sd_bus_unref(ambus->bus);
+ if (ambus->msgpipe[0])
+ close(ambus->msgpipe[0]);
+ if (ambus->msgpipe[1])
+ close(ambus->msgpipe[1]);
+ }
+}
+
+struct aml_dbus *ambus_new(const char *address, int mode) {
+ struct aml_dbus *ambus = calloc(1, sizeof(*ambus));
+ ambus->dispatch_thread = pthread_self();
+ int r;
+ if (address == AMBUS_DEFAULT_SYSTEM || address == NULL) {
+ AMBUS_CHECK(r, sd_event_default(&ambus->event), goto fail);
+ AMBUS_CHECK(r, sd_bus_default_system(&ambus->bus), goto fail);
+ } else if (address == AMBUS_DEFAULT_USER) {
+ AMBUS_CHECK(r, sd_event_default(&ambus->event), goto fail);
+ AMBUS_CHECK(r, sd_bus_default_user(&ambus->bus), goto fail);
+ } else {
+ AMBUS_CHECK(r, sd_event_new(&ambus->event), goto fail);
+ if (address != AMBUS_DEFAULT_NONE) {
+ AMBUS_CHECK(r, sd_bus_new(&ambus->bus), goto fail);
+ AMBUS_CHECK(r, sd_bus_set_address(ambus->bus, address), goto fail);
+ AMBUS_CHECK(r, sd_bus_start(ambus->bus), goto fail);
+ }
+ }
+ pthread_mutex_init(&ambus->lock, NULL);
+ pthread_cond_init(&ambus->cond, NULL);
+ if (ambus->bus) {
+ AMBUS_CHECK(r, sd_bus_attach_event(ambus->bus, ambus->event, 0), goto fail);
+ }
+ AMBUS_CHECK(r, pipe(ambus->msgpipe), goto fail);
+ AMBUS_CHECK(r, sd_event_add_io(ambus->event, NULL, ambus->msgpipe[0], POLLIN, msgpipe_handler, ambus), goto fail);
+ return ambus;
+fail:
+ ambus_free(ambus);
+ return NULL;
+}
+
+static pthread_mutex_t global_ambus_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t global_ambus_cond = PTHREAD_COND_INITIALIZER;
+static void *ambus_dispatcher(void *param) {
+ struct aml_dbus *ambus = ambus_new(NULL, 0);
+ pthread_mutex_lock(&global_ambus_mutex);
+ *(struct aml_dbus **)param = ambus;
+ pthread_cond_broadcast(&global_ambus_cond);
+ pthread_mutex_unlock(&global_ambus_mutex);
+ ambus_run(ambus);
+ return NULL;
+}
+
+struct aml_dbus *ambus_ensure_run(struct aml_dbus **ppambus) {
+ static struct aml_dbus *ambus_invalid = (struct aml_dbus *)-1;
+ struct aml_dbus *tmpbus = NULL;
+ if (ppambus == NULL)
+ ppambus = &tmpbus;
+ if (*ppambus == NULL || *ppambus == ambus_invalid) {
+ pthread_mutex_lock(&global_ambus_mutex);
+ if (*ppambus == NULL) {
+ pthread_t t;
+ *ppambus = ambus_invalid;
+ pthread_create(&t, NULL, ambus_dispatcher, ppambus);
+ }
+ while (*ppambus == ambus_invalid)
+ pthread_cond_wait(&global_ambus_cond, &global_ambus_mutex);
+ pthread_mutex_unlock(&global_ambus_mutex);
+ }
+ return *ppambus;
+}
+
+int ambus_run(struct aml_dbus *ambus) {
+ ambus->dispatch_thread = pthread_self();
+ return sd_event_loop(ambus->event);
+}
+
+sd_bus *ambus_sdbus(struct aml_dbus *ambus) { return ambus->bus; }
+
+sd_event *ambus_sdevent(struct aml_dbus *ambus) { return ambus->event; }
+
+bool ambus_in_dispatch_thread(struct aml_dbus *ambus) { return pthread_equal(pthread_self(), ambus->dispatch_thread); }
+
+void ambus_wait_flag(struct aml_dbus *ambus, uint32_t *val, uint32_t mask) {
+ pthread_mutex_lock(&ambus->lock);
+ while ((*val & mask) == 0)
+ pthread_cond_wait(&ambus->cond, &ambus->lock);
+ pthread_mutex_unlock(&ambus->lock);
+}
+
+void ambus_set_flag(struct aml_dbus *ambus, uint32_t *val, uint32_t mask) {
+ pthread_mutex_lock(&ambus->lock);
+ *val |= mask;
+ pthread_cond_broadcast(&ambus->cond);
+ pthread_mutex_unlock(&ambus->lock);
+}
+
+int ambus_call_async(struct aml_dbus *ambus, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata) {
+ int r = -1;
+ RUN_IN_DISPATCH_THREAD(ambus, r = sd_bus_call_async(ambus->bus, NULL, m, callback, userdata, 0));
+ return r;
+}
+
+sd_bus_message *ambus_call_sync(struct aml_dbus *ambus, sd_bus_message *m) {
+ int r = -1;
+ sd_bus_message *ret = NULL;
+ if (ambus_in_dispatch_thread(ambus)) {
+ AMBUS_LOGW("cannot make sync call in dispatch thread");
+ return NULL;
+ } else {
+ int done = 0;
+ int method_done(sd_bus_message * dm, void *userdata, sd_bus_error *ret_error) {
+ ret = sd_bus_message_ref(dm);
+ AMBUS_LOGD("call done, notify caller");
+ ambus_set_flag(ambus, &done, 1);
+ return 0;
+ }
+ POST_AND_WAIT_DISPATCH(ambus, r = sd_bus_call_async(ambus->bus, NULL, m, method_done, NULL, 0));
+ if (r >= 0)
+ ambus_wait_flag(ambus, &done, 1);
+ }
+ return ret;
+}
+
+int ambus_call_simple_async_va(struct aml_dbus *ambus, struct ambus_interface *intf, int idx,
+ sd_bus_message_handler_t callback, void *userdata, va_list ap) {
+ int r = -1;
+ int done = 0;
+ void do_task(void *p) {
+ sd_bus_message *msg = NULL;
+ r = sd_bus_message_new_method_call(ambus->bus, &msg, intf->service, intf->object, intf->interface,
+ intf->vtable[idx].member);
+ if (r >= 0 && intf->vtable[idx].signature)
+ r = sd_bus_message_appendv(msg, intf->vtable[idx].signature, ap);
+ if (r >= 0)
+ r = sd_bus_call_async(ambus->bus, NULL, msg, callback, userdata, 0);
+ ambus_set_flag(ambus, &done, 1);
+ }
+ if (ambus_in_dispatch_thread(ambus))
+ do_task(NULL);
+ else if (ambus_post_task(ambus, do_task, NULL) == 0)
+ ambus_wait_flag(ambus, &done, 1);
+ return r;
+}
+
+int ambus_call_simple_async(struct aml_dbus *ambus, struct ambus_interface *intf, int idx,
+ sd_bus_message_handler_t callback, void *userdata, ...) {
+ va_list ap;
+ va_start(ap, userdata);
+ int r = ambus_call_simple_async_va(ambus, intf, idx, callback, userdata, ap);
+ va_end(ap);
+ return r;
+}
+
+int ambus_call_simple_sync_va(struct aml_dbus *ambus, struct ambus_interface *intf, int idx, va_list ap) {
+ if (ambus_in_dispatch_thread(ambus)) {
+ AMBUS_LOGE("cannot make sync call in dispatch thread");
+ return -1;
+ }
+ int r;
+ int done = 0;
+ int msg_handle(sd_bus_message * m, void *userdata, sd_bus_error *ret_error) {
+ if (intf->vtable[idx].result)
+ r = sd_bus_message_readv(m, intf->vtable[idx].result, ap);
+ ambus_set_flag(ambus, &done, 1);
+ return 0;
+ }
+ r = ambus_call_simple_async_va(ambus, intf, idx, msg_handle, NULL, ap);
+ va_end(ap);
+ if (r >= 0)
+ ambus_wait_flag(ambus, &done, 1);
+ return r;
+}
+
+int ambus_call_simple_sync(struct aml_dbus *ambus, struct ambus_interface *intf, int idx, ...) {
+ va_list ap;
+ va_start(ap, idx);
+ int r = ambus_call_simple_sync_va(ambus, intf, idx, ap);
+ va_end(ap);
+ return r;
+}
+
+int ambus_call_sync_general(struct aml_dbus *ambus, const char *destination, const char *path, const char *interface,
+ const char *member, void *userdata, int (*msgpack)(sd_bus_message *m, void *userdata),
+ int (*msgunpack)(sd_bus_message *m, void *userdata)) {
+ if (ambus_in_dispatch_thread(ambus)) {
+ AMBUS_LOGE("cannot make sync call in dispatch thread");
+ return -1;
+ }
+ int r = -1;
+ int done = 0;
+ int call_done(sd_bus_message * m, void *userdata, sd_bus_error *ret_error) {
+ if (r >= 0 && msgunpack)
+ r = msgunpack(m, userdata);
+ ambus_set_flag(ambus, &done, 1);
+ return 0;
+ }
+ void do_task(void *p) {
+ sd_bus_message *msg = NULL;
+ r = sd_bus_message_new_method_call(ambus->bus, &msg, destination, path, interface, member);
+ if (r >= 0 && msgpack)
+ r = msgpack(msg, userdata);
+ if (r >= 0)
+ r = sd_bus_call_async(ambus->bus, NULL, msg, call_done, userdata, 0);
+ else {
+ sd_bus_message_unref(msg);
+ ambus_set_flag(ambus, &done, 1);
+ }
+ }
+ if (ambus_post_task(ambus, do_task, NULL) == 0)
+ ambus_wait_flag(ambus, &done, 1);
+ return r;
+}
+
+int ambus_call_async_general(struct aml_dbus *ambus, const char *destination, const char *path, const char *interface,
+ const char *member, void *userdata, int (*msgpack)(sd_bus_message *m, void *userdata),
+ int (*reply_msg_handle)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)) {
+ int r = -1;
+ int done = 0;
+ void do_task(void *p) {
+ sd_bus_message *msg = NULL;
+ r = sd_bus_message_new_method_call(ambus->bus, &msg, destination, path, interface, member);
+ if (r >= 0 && msgpack)
+ r = msgpack(msg, userdata);
+ if (r >= 0)
+ r = sd_bus_call_async(ambus->bus, NULL, msg, reply_msg_handle, userdata, 0);
+ else {
+ sd_bus_message_unref(msg);
+ }
+ if (p)
+ ambus_set_flag(ambus, (uint32_t *)p, 1);
+ }
+ if (ambus_in_dispatch_thread(ambus)) {
+ do_task(NULL);
+ } else {
+ uint32_t done = 0;
+ if (ambus_post_task(ambus, do_task, &done) == 0)
+ ambus_wait_flag(ambus, &done, 1);
+ }
+ return r;
+}
+
+
+int ambus_run_in_dispatch(struct aml_dbus *ambus, void (*cb)(void *), void *param) {
+ if (ambus_in_dispatch_thread(ambus)) {
+ cb(param);
+ } else {
+ uint32_t done = 0;
+ void do_task(void *p) {
+ cb(param);
+ ambus_set_flag(ambus, &done, 1);
+ }
+ if (ambus_post_task(ambus, do_task, NULL) == 0)
+ ambus_wait_flag(ambus, &done, 1);
+ }
+ return 0;
+}
diff --git a/aml_dbus/aml-dbus.h b/aml_dbus/aml-dbus.h
new file mode 100644
index 0000000..e3f57ae
--- /dev/null
+++ b/aml_dbus/aml-dbus.h
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2014-2019 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License Agreement
+ * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
+ * only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission from
+ * Amlogic.
+ *
+ * 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.
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+
+#ifndef AML_DBUS_H
+#define AML_DBUS_H
+
+#define AMBUS_LOGE(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define AMBUS_LOGW(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define AMBUS_LOGI(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define AMBUS_LOGD(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define AMBUS_LOGV(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+
+#define MACRO_CAT(a, b) a##b
+#define MACRO_CAT2(a, b) MACRO_CAT(a, b)
+#define MACRO_STRINGIFY(a) #a
+#define MACRO_STRINGIFY2(a) MACRO_STRINGIFY(a)
+#define MACRO_GET_8TH(_1,_2,_3,_4,_5,_6,_7,_8,...) _8
+#define MACRO_GET1ST(...) MACRO_GET_8TH(_1,_2,_3,_4,_5,_6,_7,__VA_ARGS__)
+#define MACRO_GET2ND(...) MACRO_GET_8TH(_1,_2,_3,_4,_5,_6,__VA_ARGS__)
+#define MACRO_GET3RD(...) MACRO_GET_8TH(_1,_2,_3,_4,_5,__VA_ARGS__)
+#define MACRO_GET4TH(...) MACRO_GET_8TH(_1,_2,_3,_4,__VA_ARGS__)
+#define MACRO_GET5TH(...) MACRO_GET_8TH(_1,_2,_3,__VA_ARGS__)
+#define MACRO_GET6TH(...) MACRO_GET_8TH(_1,_2,__VA_ARGS__)
+#define MACRO_GET7TH(...) MACRO_GET_8TH(_1,__VA_ARGS__)
+#define MACRO_GET8TH(...) MACRO_GET_8TH(__VA_ARGS__)
+#define MACRO_REMOVE_1ST_(a,...) __VA_ARGS__
+#define MACRO_REMOVE_1ST(...) MACRO_REMOVE_1ST_(__VA_ARGS__)
+#define MACRO_EMPTY(...)
+
+
+// https://github.com/swansontec/map-macro
+// modified to avoid name conflicts and add additional parameter
+#define MACRO_EVAL0(...) __VA_ARGS__
+#define MACRO_EVAL1(...) MACRO_EVAL0(MACRO_EVAL0(MACRO_EVAL0(__VA_ARGS__)))
+#define MACRO_EVAL2(...) MACRO_EVAL1(MACRO_EVAL1(MACRO_EVAL1(__VA_ARGS__)))
+#define MACRO_EVAL3(...) MACRO_EVAL2(MACRO_EVAL2(MACRO_EVAL2(__VA_ARGS__)))
+#define MACRO_EVAL4(...) MACRO_EVAL3(MACRO_EVAL3(MACRO_EVAL3(__VA_ARGS__)))
+#define MACRO_EVAL(...) MACRO_EVAL4(MACRO_EVAL4(MACRO_EVAL4(__VA_ARGS__)))
+
+#define MACRO_MAP_END(...)
+#define MACRO_MAP_OUT
+#define MACRO_MAP_COMMA ,
+
+#define MACRO_MAP_GET_END2() 0, MACRO_MAP_END
+#define MACRO_MAP_GET_END1(...) MACRO_MAP_GET_END2
+#define MACRO_MAP_GET_END(...) MACRO_MAP_GET_END1
+#define MACRO_MAP_NEXT0(test, next, ...) next MACRO_MAP_OUT
+#define MACRO_MAP_NEXT1(test, next) MACRO_MAP_NEXT0(test, next, 0)
+#define MACRO_MAP_NEXT(test, next) MACRO_MAP_NEXT1(MACRO_MAP_GET_END test, next)
+
+#define MACRO_MAP0(f, P, x, peek, ...) f(P, x) MACRO_MAP_NEXT(peek, MACRO_MAP1)(f, P, peek, __VA_ARGS__)
+#define MACRO_MAP1(f, P, x, peek, ...) f(P, x) MACRO_MAP_NEXT(peek, MACRO_MAP0)(f, P, peek, __VA_ARGS__)
+#define MACRO_MAP(f, P, ...) MACRO_EVAL(MACRO_MAP1(f, P, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define MACRO_MAP_PAIR0(f, P, x, y, peek, ...) MACRO_MAP_NEXT(x,f)(P, x, y) MACRO_MAP_NEXT(peek, MACRO_MAP_PAIR1)(f, P, peek, __VA_ARGS__)
+#define MACRO_MAP_PAIR1(f, P, x, y, peek, ...) MACRO_MAP_NEXT(x,f)(P, x, y) MACRO_MAP_NEXT(peek, MACRO_MAP_PAIR0)(f, P, peek, __VA_ARGS__)
+#define MACRO_MAP_PAIR(f, P, ...) MACRO_EVAL(MACRO_MAP_PAIR1(f, P, ##__VA_ARGS__, ()()(), ()()(), ()()()))
+
+#define AMBUS_CHECK(v, x, e) \
+ do { \
+ if ((v = (x)) < 0) { \
+ AMBUS_LOGW("call %s fail %d %s\n", #x, v, strerror(-v)); \
+ e; \
+ } \
+ } while (0)
+
+#define POST_AND_WAIT_DISPATCH(ambus, thread_expr) \
+ do { \
+ uint32_t done = 0; \
+ void do_task(void *p) { \
+ thread_expr; \
+ ambus_set_flag(ambus, &done, 1); \
+ } \
+ if (ambus_post_task(ambus, do_task, NULL) == 0) \
+ ambus_wait_flag(ambus, &done, 1); \
+ } while (0)
+
+#define RUN_IN_DISPATCH_THREAD(ambus, thread_expr) \
+ do { \
+ if (!ambus_in_dispatch_thread(ambus)) { \
+ POST_AND_WAIT_DISPATCH(ambus, thread_expr); \
+ } else { \
+ thread_expr; \
+ } \
+ } while (0)
+
+#define AMBUS_INTERFACE_PTR(_intf) (&_intf##_interface)
+#define AMBUS_VTABLE(_intf, _member) (AMBUS_INTERFACE_PTR(_intf)->vtable[AMBUS_MEMBER_IDX(_intf, _member)])
+#define AMBUS_SERVICE(_intf) AMBUS_INTERFACE_PTR(_intf)->service
+#define AMBUS_OBJECT(_intf) AMBUS_INTERFACE_PTR(_intf)->object
+#define AMBUS_INTERFACE(_intf) AMBUS_INTERFACE_PTR(_intf)->interface
+
+#define AMBUS_MEMBER_IDX(_intf, _member) _intf##_enum_##_member
+#define AMBUS_ADD_VTABLE(_ambus, _intf, _userData) \
+ sd_bus_add_object_vtable(ambus_sdbus(_ambus), NULL, AMBUS_OBJECT(_intf), AMBUS_INTERFACE(_intf), _intf##_vtable, \
+ _userData)
+#define AMBUS_NEW_SIGNAL(_sig, _ambus, _intf, _member) \
+ sd_bus_message_new_signal(ambus_sdbus(_ambus), _sig, AMBUS_OBJECT(_intf), AMBUS_INTERFACE(_intf), _member)
+#define AMBUS_REQUEST_NAME(_ambus, _intf) sd_bus_request_name(ambus_sdbus(_ambus), AMBUS_SERVICE(_intf), 0)
+
+#define GEN_ENUM_ITEM(p, _member, ...) AMBUS_MEMBER_IDX(p, _member),
+#define GEN_EMPTY(...)
+#define GEN_VTABLE2(p, _member, _signature) {#_member, _signature, NULL},
+#define GEN_VTABLE3(p, _member, _signature, _result) {#_member, _signature, _result},
+#define GEN_PROP_DECL(p, _member, _signature) \
+ static int p##_property_get(sd_bus *bus, const char *path, const char *interface, const char *property, \
+ sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
+#define GEN_PROPRW_DECL(p, _member, _signature) \
+ static int p##_property_get(sd_bus *bus, const char *path, const char *interface, const char *property, \
+ sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); \
+ static int p##_property_set(sd_bus *bus, const char *path, const char *interface, const char *property, \
+ sd_bus_message *value, void *userdata, sd_bus_error *ret_error);
+#define GEN_METHOD_DECL(p, _member, _signature, _result) \
+ static int p##_method_##_member(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+
+#define GEN_VTABLE_PROP(p, _member, _signature) SD_BUS_PROPERTY(#_member, _signature, p##_property_get, 0, 0),
+#define GEN_VTABLE_PROPRW(p, _member, _signature) \
+ SD_BUS_WRITABLE_PROPERTY(#_member, _signature, p##_property_get, p##_property_set, 0, 0),
+#define GEN_VTABLE_METHOD(p, _member, _signature, _result) \
+ SD_BUS_METHOD(#_member, _signature, _result, p##_method_##_member, SD_BUS_VTABLE_UNPRIVILEGED),
+#define GEN_VTABLE_SIGNAL(p, _member, _signature) SD_BUS_SIGNAL(#_member, _signature, 0),
+
+#define AMBUS_DECLARE_INTERFACE(M) \
+ enum { M(M, GEN_ENUM_ITEM, GEN_ENUM_ITEM, GEN_ENUM_ITEM, GEN_ENUM_ITEM) M##_enum_END_ }; \
+ extern struct ambus_interface M##_interface;
+
+#define AMBUS_DEFINE_INTERFACE(M, service, object, interface) \
+ struct ambus_interface M##_interface = { \
+ service, object, interface, {M(M, GEN_VTABLE2, GEN_VTABLE2, GEN_VTABLE3, GEN_VTABLE2){0, 0, 0}}};
+
+#define AMBUS_DECLARE_VTABLE(M) M(M, GEN_PROP_DECL, GEN_PROPRW_DECL, GEN_METHOD_DECL, GEN_EMPTY)
+#define AMBUS_DEFINE_VTABLE(M) \
+ static const sd_bus_vtable M##_vtable[] = { \
+ SD_BUS_VTABLE_START(0), \
+ M(M, GEN_VTABLE_PROP, GEN_VTABLE_PROPRW, GEN_VTABLE_METHOD, GEN_VTABLE_SIGNAL) SD_BUS_VTABLE_END};
+
+
+#define AMBUS_DATA_TYPE_uint8_t "y", uint8_t, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_bool "b", int, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_int16_t "n", int16_t, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_uint16_t "q", uint16_t, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_int32_t "i", int32_t,ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_uint32_t "u", uint32_t,ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_int64_t "x", int64_t, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_uint64_t "t", uint64_t, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_double "d", double, ambus_data_pack_basic, ambus_data_unpack_basic
+#define AMBUS_DATA_TYPE_string "s", char *,ambus_data_pack_basic, ambus_data_unpack_string
+
+#define AMBUS_DATA_TYPE_SIG(x) MACRO_GET1ST(MACRO_CAT2(AMBUS_DATA_TYPE_,x))
+#define AMBUS_DATA_TYPE_CT(x) MACRO_GET2ND(MACRO_CAT2(AMBUS_DATA_TYPE_,x))
+#define AMBUS_DATA_TYPE_PACK(x) MACRO_GET3RD(MACRO_CAT2(AMBUS_DATA_TYPE_,x))
+#define AMBUS_DATA_TYPE_UNPACK(x) MACRO_GET4TH(MACRO_CAT2(AMBUS_DATA_TYPE_,x))
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct aml_dbus;
+
+struct ambus_vtable {
+ const char *member;
+ const char *signature;
+ const char *result;
+};
+
+struct ambus_interface {
+ const char *service;
+ const char *object;
+ const char *interface;
+ struct ambus_vtable vtable[];
+};
+
+static const char *AMBUS_DEFAULT_SYSTEM = (const char *)(0);
+static const char *AMBUS_DEFAULT_USER = (const char *)(1);
+static const char *AMBUS_DEFAULT_NONE = (const char *)(2);
+/**
+ * @brief create a new dbus connection, this function MUST be called in dispatch thread (before ambus_run)
+ *
+ * @param address, dbus address, special addresses:
+ * NULL/AMBUS_DEFAULT_SYSTEM: default system bus
+ * AMBUS_DEFAULT_USER: default session bus
+ * AMBUS_DEFAULT_NONE: do not open dbus connection, only create event loop
+ * @param mode, resolved, must be 0 by now
+ *
+ * @return return a pointer of opaque aml_dbus object
+ */
+struct aml_dbus *ambus_new(const char *address, int mode);
+
+/**
+ * @brief ensure dbus is created and dispatch thread is running
+ *
+ * @param ppambus, specify pointer of the bus to be ensured, and output the new created bus
+ * if NULL, it will always create new bus and dispatch thread
+ *
+ * @return return new created ambus if not created, else return *ppambus
+ */
+struct aml_dbus *ambus_ensure_run(struct aml_dbus **ppambus);
+
+/**
+ * @brief free the bus object
+ *
+ * @param ambus
+ */
+void ambus_free(struct aml_dbus *ambus);
+
+/**
+ * @brief run the event loop, dispatch dbus messages, must be called in the same thread with ambus_new
+ *
+ * @param ambus
+ *
+ * @return
+ */
+int ambus_run(struct aml_dbus *ambus);
+sd_bus *ambus_sdbus(struct aml_dbus *ambus);
+sd_event *ambus_sdevent(struct aml_dbus *ambus);
+// check whether current thread is dispatch thread
+bool ambus_in_dispatch_thread(struct aml_dbus *ambus);
+// wait until (*val & mask) != 0
+void ambus_wait_flag(struct aml_dbus *ambus, uint32_t *val, uint32_t mask);
+// set flag *val |= mask and notify all waiters
+void ambus_set_flag(struct aml_dbus *ambus, uint32_t *val, uint32_t mask);
+// call cb(param) in dispatch thread asynchronously
+int ambus_post_task(struct aml_dbus *ambus, void (*cb)(void *), void *param);
+// call cb(param) in dispatch thread synchronously
+int ambus_run_in_dispatch(struct aml_dbus *ambus, void (*cb)(void *), void *param);
+// call cb(param) after delay_ms in dispatch thread asynchronously
+int ambus_post_delay_task(struct aml_dbus *ambus, uint32_t delay_ms, void (*cb)(void *), void *param);
+// call dbus method asynchronously, msgpack is used to pack input arguments of the method
+int ambus_call_async_general(struct aml_dbus *ambus, const char *destination, const char *path, const char *interface,
+ const char *member, void *userdata, int (*msgpack)(sd_bus_message *m, void *userdata),
+ int (*reply_msg_handle)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error));
+// call dbus method synchronously, it MUST be call in a thread other than dispatch thread
+int ambus_call_sync_general(struct aml_dbus *ambus, const char *destination, const char *path, const char *interface,
+ const char *member, void *userdata, int (*msgpack)(sd_bus_message *m, void *userdata),
+ int (*msgunpack)(sd_bus_message *m, void *userdata));
+
+#ifdef __cplusplus
+} /* extern "C" */
+#include <iostream>
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <functional>
+#include <map>
+#include <unordered_map>
+
+// T shall be decay type, no const, no reference, no pointer
+template <typename T, typename TEMPTY = void> struct ambus_data_type;
+
+template <char... sigs> struct ambus_signature {
+ constexpr static char value[] = {sigs..., 0};
+};
+template <char... sigs> constexpr char ambus_signature<sigs...>::value[];
+template <typename... Args> struct ambus_signature_concat;
+template <char... sig1, char... sig2>
+struct ambus_signature_concat<ambus_signature<sig1...>, ambus_signature<sig2...>> {
+ using type = ambus_signature<sig1..., sig2...>;
+};
+template <typename T1, typename... Args> struct ambus_signature_concat<T1, Args...> {
+ using type = typename ambus_signature_concat<T1, typename ambus_signature_concat<Args...>::type>::type;
+};
+
+template <typename T, int sig, typename CT = T> struct ambus_simple_type {
+ using signature = ambus_signature<sig>;
+ static int pack(sd_bus_message *msg, const T &val) {
+ const CT ct = static_cast<CT>(val);
+ return sd_bus_message_append_basic(msg, sig, &ct);
+ }
+ static int unpack(sd_bus_message *msg, T &val) {
+ CT ct;
+ int r = sd_bus_message_read_basic(msg, sig, &ct);
+ if (r > 0)
+ val = static_cast<T>(ct);
+ return r;
+ }
+};
+
+template <typename T, int S = sizeof(T)> struct ambus_simple_struct {
+ using signature = ambus_signature<'a', 'y'>;
+ static int pack(sd_bus_message *msg, const T &val) {
+ return sd_bus_message_append_array(msg, 'y', (const void *)&val, S);
+ }
+ static int unpack(sd_bus_message *msg, T &val) {
+ const void *ptr;
+ size_t size = 0;
+ int r = sd_bus_message_read_array(msg, 'y', &ptr, &size);
+ if (r >= 0 && size == S)
+ memcpy(&val, ptr, size);
+ else
+ AMBUS_LOGW("fail to read array from msg, ret %d size %d sizeof(T) %d", r, (int)size, S);
+ return r;
+ }
+};
+template <typename T, int N> struct ambus_data_type<T[N]> : ambus_simple_struct<T[N]> {};
+
+// buildin types
+template <> struct ambus_data_type<char> : ambus_simple_type<char, 'y'> {};
+template <> struct ambus_data_type<uint8_t> : ambus_simple_type<uint8_t, 'y'> {};
+template <> struct ambus_data_type<int8_t> : ambus_simple_type<int8_t, 'y'> {};
+template <> struct ambus_data_type<bool> : ambus_simple_type<bool, 'b', int> {};
+template <> struct ambus_data_type<int16_t> : ambus_simple_type<int16_t, 'n'> {};
+template <> struct ambus_data_type<uint16_t> : ambus_simple_type<uint16_t, 'q'> {};
+template <> struct ambus_data_type<int32_t> : ambus_simple_type<int32_t, 'i'> {};
+template <> struct ambus_data_type<uint32_t> : ambus_simple_type<uint32_t, 'u'> {};
+template <> struct ambus_data_type<int64_t> : ambus_simple_type<int64_t, 'x'> {};
+template <> struct ambus_data_type<uint64_t> : ambus_simple_type<uint64_t, 't'> {};
+template <> struct ambus_data_type<double> : ambus_simple_type<double, 'd'> {};
+template <> struct ambus_data_type<long> : ambus_simple_type<long, 'x', int64_t> {};
+//template <> struct ambus_data_type<const char *> : ambus_simple_type<const char *, 's'> {};
+template <typename T>
+struct ambus_data_type<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
+ : ambus_simple_type<T, 'd', double> {};
+template <typename T>
+struct ambus_data_type<T, typename std::enable_if<std::is_enum<T>::value>::type> : ambus_simple_type<T, 'i', int32_t> {
+};
+template <typename T>
+struct ambus_data_type<T, typename std::enable_if<std::is_pod<T>::value && std::is_class<T>::value>::type>
+ : ambus_simple_struct<T> {};
+template <> struct ambus_data_type<std::string> {
+ using signature = ambus_signature<'s'>;
+ static int pack(sd_bus_message *msg, const std::string &val) {
+ return sd_bus_message_append_basic(msg, 's', val.c_str());
+ }
+ static int unpack(sd_bus_message *msg, std::string &val) {
+ const char *ptr = NULL;
+ int r = sd_bus_message_read_basic(msg, 's', &ptr);
+ if (r >= 0 && ptr)
+ val = ptr;
+ return r;
+ }
+};
+template <template <class...> class C, typename T> struct ambus_data_type<C<T>> {
+ using signature =
+ typename ambus_signature_concat<ambus_signature<'a'>,
+ typename ambus_data_type<typename std::decay<T>::type>::signature>::type;
+ static int pack(sd_bus_message *msg, const C<T> &val) {
+ int r = sd_bus_message_open_container(msg, 'a', ambus_data_type<typename std::decay<T>::type>::signature::value);
+ for (auto it = val.begin(); r >= 0 && it != val.end(); ++it)
+ r = ambus_data_type<typename std::decay<T>::type>::pack(msg, *it);
+ sd_bus_message_close_container(msg);
+ return 0;
+ }
+ static int unpack(sd_bus_message *msg, C<T> &val) {
+ int r = sd_bus_message_enter_container(msg, 'a', ambus_data_type<typename std::decay<T>::type>::signature::value);
+ T item;
+ while ((r = ambus_data_type<typename std::decay<T>::type>::unpack(msg, item)) > 0)
+ val.push_back(item);
+ sd_bus_message_exit_container(msg);
+ return 0;
+ }
+};
+
+template <template <class...> class M, typename K, typename V>
+struct ambus_data_type<M<K, V>, typename std::enable_if<std::is_same<M<K, V>, std::map<K, V>>::value ||
+ std::is_same<M<K, V>, std::unordered_map<K, V>>::value>::type> {
+ using decay_val_type = typename std::decay<V>::type;
+ using signature_kv = typename ambus_signature_concat<typename ambus_data_type<K>::signature,
+ typename ambus_data_type<decay_val_type>::signature>::type;
+ using signature_map = typename ambus_signature_concat<ambus_signature<'{'>, signature_kv, ambus_signature<'}'>>::type;
+ using signature = typename ambus_signature_concat<ambus_signature<'a'>, signature_map>::type;
+ static int pack(sd_bus_message *msg, const M<K, V> &val) {
+ int r = sd_bus_message_open_container(msg, 'a', signature_map::value);
+ for (auto it = val.begin(); r >= 0 && it != val.end(); ++it) {
+ if ((r = sd_bus_message_open_container(msg, 'e', signature_kv::value)) >= 0) {
+ if ((r = ambus_data_type<K>::pack(msg, it->first)) >= 0)
+ r = ambus_data_type<decay_val_type>::pack(msg, it->second);
+ sd_bus_message_close_container(msg);
+ }
+ }
+ sd_bus_message_close_container(msg);
+ return 0;
+ }
+ static int unpack(sd_bus_message *msg, M<K, V> &val) {
+ int r = sd_bus_message_enter_container(msg, 'a', signature_map::value);
+ for (; (r = sd_bus_message_enter_container(msg, 'e', signature_kv::value)) > 0;
+ sd_bus_message_exit_container(msg)) {
+ K k;
+ if ((r = ambus_data_type<K>::unpack(msg, k)) > 0)
+ r = ambus_data_type<decay_val_type>::unpack(msg, val[k]);
+ }
+ sd_bus_message_exit_container(msg);
+ return r;
+ }
+};
+
+// output argument must be non-const reference
+template <typename T>
+struct is_output_parameter
+ : public std::integral_constant<bool, std::is_lvalue_reference<T>::value &&
+ !std::is_const<typename std::remove_reference<T>::type>::value> {};
+
+template <typename... Args> struct ambus_data_pack;
+
+template <typename T, typename... Args> struct ambus_data_pack<T, Args...> : public ambus_data_pack<Args...> {
+ constexpr static bool is_output =
+ std::is_lvalue_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value;
+ using parent_class = ambus_data_pack<Args...>;
+ using decay_value_type = typename std::conditional<std::is_array<T>::value, T, typename std::decay<T>::type>::type;
+ using signature_output = typename ambus_signature_concat<
+ typename std::conditional<is_output, typename ambus_data_type<decay_value_type>::signature,
+ ambus_signature<>>::type,
+ typename parent_class::signature_output>::type;
+ using signature_input = typename ambus_signature_concat<
+ typename std::conditional<!is_output, typename ambus_data_type<decay_value_type>::signature,
+ ambus_signature<>>::type,
+ typename parent_class::signature_input>::type;
+
+ static int packall(bool output, sd_bus_message *msg, const decay_value_type &val1, const Args &... vals) {
+ int ret = is_output == output ? ambus_data_type<decay_value_type>::pack(msg, val1) : 0;
+ return ret >= 0 ? parent_class::packall(output, msg, vals...) : ret;
+ }
+ static int unpackall(bool output, sd_bus_message *msg, T &val1, Args &... vals) {
+ int ret = is_output == output ? ambus_data_type<decay_value_type>::unpack(msg, const_cast<decay_value_type&>(val1)) : 1;
+ return ret > 0 ? parent_class::unpackall(output, msg, vals...) : ret;
+ }
+ decay_value_type val;
+ int unpack(bool output, sd_bus_message *msg) {
+ int ret = output == is_output_parameter<T>::value ? ambus_data_type<decay_value_type>::unpack(msg, val) : 0;
+ return ret >= 0 ? parent_class::unpack(output, msg) : ret;
+ }
+ int pack(bool output, sd_bus_message *msg) {
+ int ret = output == is_output_parameter<T>::value ? ambus_data_type<decay_value_type>::pack(msg, val) : 0;
+ return ret >= 0 ? parent_class::pack(output, msg) : ret;
+ }
+ template <typename RET, typename... FArgs, typename... CArgs>
+ int apply(RET &ret, RET (*pfn)(FArgs...), CArgs &... args) {
+ return parent_class::apply(ret, pfn, args..., val);
+ }
+ template <typename TOBJ, typename RET, typename... FArgs, typename... CArgs>
+ int apply_member(TOBJ *pThis, RET &ret, RET (TOBJ::*pfn)(FArgs...), CArgs &... args) {
+ return parent_class::apply_member(pThis, ret, pfn, args..., val);
+ }
+};
+
+template <> struct ambus_data_pack<> {
+ // virtual ~ambus_data_pack<>() {}
+ using signature_output = ambus_signature<>;
+ using signature_input = ambus_signature<>;
+ static int packall(bool output, sd_bus_message *msg) { return 0; }
+ static int unpackall(bool output, sd_bus_message *msg) { return 1; }
+ int unpack(bool output, sd_bus_message *msg) { return 0; }
+ int pack(bool output, sd_bus_message *msg) { return 0; }
+ template <typename RET, typename... FArgs, typename... CArgs>
+ int apply(RET &ret, RET (*pfn)(FArgs...), CArgs &... args) {
+ ret = pfn(args...);
+ return 0;
+ }
+ template <typename TOBJ, typename RET, typename... FArgs, typename... CArgs>
+ int apply_member(TOBJ *pThis, RET &ret, RET (TOBJ::*pfn)(FArgs...), CArgs &... args) {
+ ret = (pThis->*pfn)(args...);
+ return 0;
+ }
+};
+
+#define GEN_STRUCT_FIELDS_TYPE(T, F) , decltype(T::F)
+#define GEN_STRUCT_FIELDS_VAL(v, F) , v.F
+#define GEN_STRUCT_FIELDS_UNPACK(T, F) \
+ if (r >= 0) \
+ r = ambus_data_type<decltype(T::F)>::unpack(msg, val.F);
+
+#define AMBUS_STRUCT_DEFINE(T, F1, ...) \
+ template <> struct ambus_data_type<T> { \
+ using fields_pack = ambus_data_pack<decltype(T::F1) MACRO_MAP(GEN_STRUCT_FIELDS_TYPE, T, __VA_ARGS__)>; \
+ using signature = typename ambus_signature_concat<ambus_signature<'('>, fields_pack::signature_input, \
+ ambus_signature<')'>>::type; \
+ static int pack(sd_bus_message *msg, const T &val) { \
+ int r = sd_bus_message_open_container(msg, 'r', fields_pack::signature_input::value); \
+ if (r >= 0) \
+ r = fields_pack::packall(false, msg, val.F1 MACRO_MAP(GEN_STRUCT_FIELDS_VAL, val, __VA_ARGS__)); \
+ sd_bus_message_close_container(msg); \
+ return r; \
+ } \
+ static int unpack(sd_bus_message *msg, T &val) { \
+ int r = sd_bus_message_enter_container(msg, 'r', fields_pack::signature_input::value); \
+ if (r >= 0) \
+ r = fields_pack::unpackall(false, msg, val.F1 MACRO_MAP(GEN_STRUCT_FIELDS_VAL, val, __VA_ARGS__)); \
+ sd_bus_message_exit_container(msg); \
+ return r; \
+ } \
+ }
+
+template <typename... Args> struct ambus_method_call;
+template <> struct ambus_method_call<> : public ambus_vtable {
+ ambus_method_call<>(const char *_name, const char *_sig, const char *_res) {
+ member = _name;
+ signature = _sig;
+ result = _res;
+ }
+ virtual int call(sd_bus_message *m) { return 0; };
+};
+template <typename RET, typename CLS, typename... Args>
+struct ambus_method_call<RET (CLS::*)(Args...)> : public ambus_method_call<> {
+ using data_pack = ambus_data_pack<Args...>;
+ using signature_output = typename ambus_signature_concat<typename ambus_data_type<RET>::signature,
+ typename data_pack::signature_output>::type;
+ ambus_method_call<RET (CLS::*)(Args...)>(CLS *_this, const char *name, RET (CLS::*pfn)(Args...))
+ : pThis(_this),
+ callback(pfn), ambus_method_call<>(name, data_pack::signature_input::value, signature_output::value) {}
+ virtual int call(sd_bus_message *m) {
+ data_pack val;
+ int r = 0;
+ if (signature[0])
+ r = val.unpack(false, m);
+ RET ret;
+ if (r >= 0)
+ r = val.apply_member(pThis, ret, callback);
+ sd_bus_message *reply = NULL;
+ if (r >= 0)
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r >= 0)
+ r = ambus_data_type<RET>::pack(reply, ret);
+ if (r >= 0 && result[0])
+ r = val.pack(true, reply);
+ if (r >= 0)
+ r = sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
+ else if (reply)
+ sd_bus_message_unref(reply);
+ return r;
+ }
+ RET (CLS::*callback)(Args...);
+ CLS *pThis;
+};
+
+template <typename RET, typename... Args> struct ambus_method_call<RET (*)(Args...)> : public ambus_method_call<> {
+ using data_pack = ambus_data_pack<Args...>;
+ using signature_output = typename ambus_signature_concat<typename ambus_data_type<RET>::signature,
+ typename data_pack::signature_output>::type;
+ ambus_method_call<RET (*)(Args...)>(const char *name, RET (*pfn)(Args...))
+ : callback(pfn), ambus_method_call<>(name, data_pack::signature_input::value, signature_output::value) {}
+ virtual int call(sd_bus_message *m) {
+ data_pack val;
+ int r = 0;
+ if (signature[0])
+ r = val.unpack(false, m);
+ RET ret;
+ if (r >= 0)
+ r = val.apply(ret, callback);
+ sd_bus_message *reply = NULL;
+ if (r >= 0)
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r >= 0)
+ r = ambus_data_type<RET>::pack(reply, ret);
+ if (r >= 0 && result[0])
+ r = val.pack(true, reply);
+ if (r >= 0)
+ r = sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
+ else if (reply)
+ sd_bus_message_unref(reply);
+ return r;
+ }
+ RET (*callback)(Args...);
+};
+
+struct ambus_runnable_task {
+ using prototype = std::function<void(void)>;
+ prototype func;
+ ambus_runnable_task(prototype &&f) : func(f){};
+ static void cb(void *p) { static_cast<ambus_runnable_task *>(p)->func(); };
+ int run_on(struct aml_dbus *ambus) { return ambus_run_in_dispatch(ambus, ambus_runnable_task::cb, this); }
+};
+
+template <typename T> struct ambus_method_proxy;
+struct ambus_method_proxy_packer {
+ std::function<int(sd_bus_message *)> pk, upk;
+ static int pack(sd_bus_message *m, void *userdata) { return ((ambus_method_proxy_packer *)userdata)->pk(m); }
+ static int unpack(sd_bus_message *m, void *userdata) { return ((ambus_method_proxy_packer *)userdata)->upk(m); }
+};
+template <typename RET, typename... Args> struct ambus_method_proxy<RET (*)(Args...)> {
+ static RET call(struct aml_dbus *ambus, const char *service, const char *object, const char *interface,
+ const char *member, Args... args) {
+ RET ret;
+ ambus_method_proxy_packer p = {
+ [&](sd_bus_message *msg) { return ambus_data_pack<Args...>::packall(false, msg, args...); },
+ [&](sd_bus_message *msg) { return ambus_data_pack<RET &, Args...>::unpackall(true, msg, ret, args...); }};
+ int r = ambus_call_sync_general(ambus, service, object, interface, member, &p, ambus_method_proxy_packer::pack,
+ ambus_method_proxy_packer::unpack);
+ return ret;
+ }
+};
+
+#endif
+
+#endif /* end of include guard: AML_DBUS_H */
diff --git a/aml_dbus/sample-client.c b/aml_dbus/sample-client.c
new file mode 100644
index 0000000..0c0d3bb
--- /dev/null
+++ b/aml_dbus/sample-client.c
@@ -0,0 +1,92 @@
+#include "aml-dbus.h"
+
+
+#define TEST_SERVICE "amlogic.yocto.test"
+#define TEST_OBJECT "/amlogic/yocto/test/obj1"
+#define TEST_INTERFACE "amlogic.yocto.test.intf1"
+#define TEST_INTF(p, PROP, RROPRW, METHOD, SIGNAL) \
+ PROP(p, Count, "i") \
+ METHOD(p, TestBasicType, "ybnqiuxtds", "ybnqiuxtds") \
+ METHOD(p, TestArray, "a(is)", "a(si)") \
+ SIGNAL(p, Changed, "i")
+
+AMBUS_DECLARE_INTERFACE(TEST_INTF);
+AMBUS_DEFINE_INTERFACE(TEST_INTF, TEST_SERVICE, TEST_OBJECT, TEST_INTERFACE);
+
+#define AMBUS_SERV_OBJ_INTF(_intf) AMBUS_SERVICE(_intf), AMBUS_OBJECT(_intf), AMBUS_INTERFACE(_intf)
+#define AMBUS_SERV_OBJ_INTF_MEM(_intf, _mem) AMBUS_SERV_OBJ_INTF(_intf), #_mem
+
+// we use two bus, one for method, one for signal
+static struct aml_dbus *bus_method;
+static struct aml_dbus *bus_signal;
+
+static int dbus_signal_handle(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *mem = sd_bus_message_get_member(message);
+ if (strcmp(mem, "Changed") == 0) {
+ int v;
+ sd_bus_message_read_basic(message, 'i', &v);
+ //printf("got signal Changed, %d\n", v);
+ }
+ return 0;
+}
+
+#define MACRO_GET_2ND_(a, b, ...) b
+#define MACRO_GET_2ND(...) MACRO_GET_2ND_(__VA_ARGS__)
+#define AMBUS_DATA_PACK_BASIC(msg, type, ptr) sd_bus_message_append_basic(msg, type, ptr)
+#define AMBUS_DATA_UNPACK_BASIC(msg, type, ptr) sd_bus_message_read_basic(msg, type, ptr)
+#define AMBUS_DATA_TYPE_y uint8_t, AMBUS_DATA_PACK_BASIC, AMBUS_DATA_UNPACK_BASIC
+
+static int call_TestBasicType(uint8_t y, int b, int16_t n, uint16_t q, int32_t i, uint32_t u, int64_t x, uint64_t t,
+ double d, char *s, uint8_t *oy, int *ob, int16_t *on, uint16_t *oq, int32_t *oi,
+ uint32_t *ou, int64_t *ox, uint64_t *ot, double *od, char **os) {
+ struct ambus_vtable *mem = &AMBUS_VTABLE(TEST_INTF, TestBasicType);
+ int r = 0;
+ int pack(sd_bus_message * m, void *userdata) {
+ r = sd_bus_message_append(m, mem->signature, y, b, n, q, i, u, x, t, d, s);
+ return r;
+ }
+ int unpack(sd_bus_message * m, void *userdata) {
+ char *ts = NULL;
+ r = sd_bus_message_read(m, mem->result, oy, ob, on, oq, oi, ou, ox, ot, od, &ts);
+ if (r >= 0 && ts && os) // string type memory is in sd_bus_message, which becomes invalid after this function return
+ *os = strdup(ts);
+ return r;
+ }
+ return ambus_call_sync_general(bus_method, AMBUS_SERV_OBJ_INTF_MEM(TEST_INTF, TestBasicType), NULL, pack, unpack);
+}
+
+static int test_dbus_call() {
+ uint8_t y = 1;
+ int b = false;
+ int16_t n = 2;
+ uint16_t q = 3;
+ int32_t i = 4;
+ uint32_t u = 5;
+ int64_t x = 6;
+ uint64_t t = 7;
+ double d = 8.123;
+ char buf[32];
+ char *s = buf;
+ for (int ii = 0; ii < 3; ii++) {
+ sprintf(s = buf, "test%d", i);
+ int r = call_TestBasicType(y, b, n, q, i, u, x, t, d, s, &y, &b, &n, &q, &i, &u, &x, &t, &d, &s);
+ printf("call TestBasicType return y:%d b:%d n:%d q:%d i:%d u:%u x:%" PRId64 " t:%" PRIu64 " d:%f s:%s\n", y, b, n,
+ q, i, u, x, t, d, s);
+ free(s);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ bus_method = ambus_ensure_run(NULL);
+ bus_signal = ambus_ensure_run(NULL);
+
+ char match[512];
+ snprintf(match, sizeof(match), "type='signal',sender='%s',path='%s',interface='%s'", AMBUS_SERV_OBJ_INTF(TEST_INTF));
+ int r = 0;
+ void installcb(void *param) { r = sd_bus_add_match(ambus_sdbus(bus_signal), NULL, match, dbus_signal_handle, NULL); }
+ // make sd_bus_add_match be called in bus_signal dispatch thread
+ ambus_run_in_dispatch(bus_signal, installcb, NULL);
+ test_dbus_call();
+ ambus_run(bus_signal);
+ return 0;
+}
diff --git a/aml_dbus/sample-server.c b/aml_dbus/sample-server.c
new file mode 100644
index 0000000..dadffcd
--- /dev/null
+++ b/aml_dbus/sample-server.c
@@ -0,0 +1,135 @@
+#include "aml-dbus.h"
+#include <errno.h>
+
+#define TEST_SERVICE "amlogic.yocto.test"
+#define TEST_OBJECT "/amlogic/yocto/test/obj1"
+#define TEST_INTERFACE "amlogic.yocto.test.intf1"
+#define TEST_INTF(p, PROP, RROPRW, METHOD, SIGNAL) \
+ PROP(p, Count, "i") \
+ METHOD(p, TestBasicType, "ybnqiuxtds", "ybnqiuxtds") \
+ METHOD(p, TestArray, "a(is)", "a(si)") \
+ SIGNAL(p, Changed, "i")
+
+AMBUS_DECLARE_INTERFACE(TEST_INTF);
+//AMBUS_DEFINE_INTERFACE(TEST_INTF, TEST_SERVICE, TEST_OBJECT, TEST_INTERFACE);
+AMBUS_DEFINE_INTERFACE(TEST_INTF, NULL, NULL, NULL);
+
+#define AMBUS_SERV_OBJ_INTF(_intf) AMBUS_SERVICE(_intf), AMBUS_OBJECT(_intf), AMBUS_INTERFACE(_intf)
+
+struct TestObject {
+ int count;
+};
+
+static int TEST_INTF_property_get(sd_bus *bus, const char *path, const char *interface, const char *property,
+ sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
+ struct TestObject *o = (struct TestObject *)userdata;
+ if (strcmp(property, "Count") == 0) {
+ return sd_bus_message_append(reply, "i", o->count);
+ }
+ return -EINVAL;
+}
+
+static int TEST_INTF_method_TestBasicType(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ struct TestObject *o = (struct TestObject *)userdata;
+ uint8_t y;
+ int b;
+ int16_t n;
+ uint16_t q;
+ int32_t i;
+ uint32_t u;
+ int64_t x;
+ uint64_t t;
+ double d;
+ char *s;
+ int r = sd_bus_message_read(m, "ybnqiuxtds", &y, &b, &n, &q, &i, &u, &x, &t, &d, &s);
+ o->count++;
+ sd_bus_emit_signal(sd_bus_message_get_bus(m), sd_bus_message_get_path(m), sd_bus_message_get_interface(m), "Changed",
+ "i", o->count);
+ y++;
+ b=!b;
+ n++;
+ q++;
+ i++;
+ u++;
+ x++;
+ t++;
+ d+=1;
+ s+=1;
+ return sd_bus_reply_method_return(m,"ybnqiuxtds",y, b, n, q, i, u, x, t, d, s);
+}
+
+static int TEST_INTF_method_TestArray(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ struct TestObject *o = (struct TestObject *)userdata;
+ int r;
+ int i;
+ char *s;
+ sd_bus_message *reply;
+ AMBUS_CHECK(r, sd_bus_message_enter_container(m, 'a', "(is)"),);
+ AMBUS_CHECK(r, sd_bus_message_new_method_return(m, &reply),);
+ AMBUS_CHECK(r, sd_bus_message_open_container(reply, 'a', "(si)"),);
+ while ((r = sd_bus_message_read(m, "(is)", &i, &s)) > 0) {
+ AMBUS_CHECK(r,sd_bus_message_append(reply, "(si)", s, i),);
+ }
+ sd_bus_message_exit_container(m);
+ sd_bus_message_close_container(reply);
+ return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
+}
+
+AMBUS_DEFINE_VTABLE(TEST_INTF);
+
+static int call_done_TestBasicType(sd_bus_message *m, void *userdata, sd_bus_error *ret_error){
+ uint8_t y;
+ int b;
+ int16_t n;
+ uint16_t q;
+ int32_t i;
+ uint32_t u;
+ int64_t x;
+ uint64_t t;
+ double d;
+ char *s;
+ struct ambus_vtable *mem = &AMBUS_VTABLE(TEST_INTF, TestBasicType);
+ int r = sd_bus_message_read(m, mem->result, &y, &b, &n, &q, &i, &u, &x, &t, &d, &s);
+ printf("call TestBasicType return y:%d b:%d n:%d q:%d i:%d u:%u x:%" PRId64 " t:%" PRIu64 " d:%f s:%s\n", y, b, n, q,
+ i, u, x, t, d, s);
+ // the memory of 's' string is point to somewhere in sd_bus_message, is is invalid when sd_bus_message is unrefed
+ // you can sd_bus_message_ref to keep the memory of sd_bus_message, but don't forget to sd_bus_message_unref
+ return 0;
+}
+
+static int test_call_async(struct aml_dbus *ambus) {
+ struct ambus_vtable *mem = &AMBUS_VTABLE(TEST_INTF, TestBasicType);
+ int r = 0;
+ uint8_t y = 1;
+ int b = false;
+ int16_t n = 2;
+ uint16_t q = 3;
+ int32_t i = 4;
+ uint32_t u = 5;
+ int64_t x = 6;
+ uint64_t t = 7;
+ double d = 8.123;
+ char *s = "aaaaa";
+ int pack(sd_bus_message * m, void *userdata) {
+ return sd_bus_message_append(m, mem->signature, y, b, n, q, i, u, x, t, d, s);
+ }
+ ambus_call_async_general(ambus, AMBUS_SERV_OBJ_INTF(TEST_INTF), "TestBasicType", NULL, pack, call_done_TestBasicType);
+}
+
+int main(int argc, char *argv[])
+{
+ struct TestObject obj;
+ memset(&obj, 0, sizeof(obj));
+ int r = 0;
+ struct aml_dbus *ambus = ambus_new(NULL, 0);
+ AMBUS_SERVICE(TEST_INTF) = TEST_SERVICE;
+ AMBUS_OBJECT(TEST_INTF) = TEST_OBJECT;
+ AMBUS_INTERFACE(TEST_INTF) = TEST_INTERFACE;
+ AMBUS_CHECK(r, AMBUS_ADD_VTABLE(ambus, TEST_INTF, &obj), goto error);
+ AMBUS_CHECK(r, AMBUS_REQUEST_NAME(ambus, TEST_INTF), goto error);
+ test_call_async(ambus);
+ ambus_run(ambus);
+error:
+ ambus_free(ambus);
+ return 0;
+}