882 lines
50 KiB
C++
882 lines
50 KiB
C++
/*
|
|
* 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 <stddef.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_SERV_OBJ_INTF(_intf) AMBUS_SERVICE(_intf), AMBUS_OBJECT(_intf), AMBUS_INTERFACE(_intf)
|
|
|
|
#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
|
|
#define AMBUS_DATA_TYPE_bool "b", int
|
|
#define AMBUS_DATA_TYPE__Bool AMBUS_DATA_TYPE_bool
|
|
#define AMBUS_DATA_TYPE_int16_t "n", int16_t
|
|
#define AMBUS_DATA_TYPE_uint16_t "q", uint16_t
|
|
#define AMBUS_DATA_TYPE_int32_t "i", int32_t
|
|
#define AMBUS_DATA_TYPE_uint32_t "u", uint32_t
|
|
#define AMBUS_DATA_TYPE_int64_t "x", int64_t
|
|
#define AMBUS_DATA_TYPE_uint64_t "t", uint64_t
|
|
#define AMBUS_DATA_TYPE_double "d", double
|
|
#define AMBUS_DATA_TYPE_string "s", char *
|
|
#define AMBUS_DATA_TYPE_unixfd "h", int
|
|
// for a new type ttt, we need to provide macro AMBUS_DATA_TYPE_ttt and ambus_data_type_info_ttt
|
|
|
|
#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), struct x *)
|
|
|
|
#define AMBUS_DATA_TYPE_INFO(x) MACRO_CAT2(ambus_data_type_info_, x)
|
|
#define AMBUS_DATA_TYPE_INFO_PTR(x) (struct ambus_data_type_info *)&AMBUS_DATA_TYPE_INFO(x)
|
|
|
|
#define AMBUS_DATA_TYPE_IS_OUT_OUT(x) _, x
|
|
#define AMBUS_DATA_TYPE_IS_OUT(x, t, f) MACRO_GET3RD(MACRO_CAT2(AMBUS_DATA_TYPE_IS_OUT_, x), t, f)
|
|
#define AMBUS_DATA_TYPE_STRIP(x) MACRO_GET2ND(MACRO_CAT2(AMBUS_DATA_TYPE_IS_OUT_, x), x)
|
|
|
|
#define GEN_API_DECLARE_1(P, x, y) , AMBUS_DATA_TYPE_CT(AMBUS_DATA_TYPE_STRIP(x)) AMBUS_DATA_TYPE_IS_OUT(x, *y, y)
|
|
#define GEN_API_DECLARE(P, f, ...) int f(MACRO_REMOVE_1ST(MACRO_MAP_PAIR(GEN_API_DECLARE_1, P, ##__VA_ARGS__)))
|
|
|
|
#define GEN_API_METHOD_IMPL_1(P, x, y) AMBUS_DATA_TYPE_CT(AMBUS_DATA_TYPE_STRIP(x)) y = 0;
|
|
#define GEN_API_METHOD_IMPL_2(P, x, y) \
|
|
{AMBUS_DATA_TYPE_INFO_PTR(AMBUS_DATA_TYPE_STRIP(x)), &y, AMBUS_DATA_TYPE_IS_OUT(x, 0, 1)},
|
|
#define GEN_API_METHOD_IMPL_3(P, x, y) , AMBUS_DATA_TYPE_IS_OUT(x, &y, y)
|
|
// genrate dbus method handle f stub to C function impl
|
|
#define GEN_API_METHOD_IMPL_NAME(P, f, impl, ...) \
|
|
static int f(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { \
|
|
MACRO_MAP_PAIR(GEN_API_METHOD_IMPL_1, P, ##__VA_ARGS__) \
|
|
struct ambus_data_pack_info dpinfo[] = {MACRO_MAP_PAIR(GEN_API_METHOD_IMPL_2, P, ##__VA_ARGS__){NULL, NULL, 0}}; \
|
|
int call(void) { return impl(MACRO_REMOVE_1ST(MACRO_MAP_PAIR(GEN_API_METHOD_IMPL_3, P, ##__VA_ARGS__))); }; \
|
|
return ambus_dispatch_to_implement(m, dpinfo, call); \
|
|
}
|
|
#define GEN_API_METHOD_IMPL(P, f, ...) GEN_API_METHOD_IMPL_NAME(P, MACRO_CAT2(P, _method_##f), f, ##__VA_ARGS__)
|
|
|
|
#define GEN_API_METHOD_PROXY_2(P, x, y) \
|
|
{AMBUS_DATA_TYPE_INFO_PTR(AMBUS_DATA_TYPE_STRIP(x)), AMBUS_DATA_TYPE_IS_OUT(x, y, &y), \
|
|
AMBUS_DATA_TYPE_IS_OUT(x, 1, 0)},
|
|
#define GEN_API_METHOD_PROXY_1(P, x, y) , AMBUS_DATA_TYPE_CT(AMBUS_DATA_TYPE_STRIP(x)) AMBUS_DATA_TYPE_IS_OUT(x, *y, y)
|
|
// generate function f, proxy to dbus method m
|
|
#define GEN_API_METHOD_PROXY_NAME(P, f, m, ...) \
|
|
int f(MACRO_REMOVE_1ST(MACRO_MAP_PAIR(GEN_API_METHOD_PROXY_1, P, ##__VA_ARGS__))) { \
|
|
struct ambus_data_pack_info dpinfo[] = {MACRO_MAP_PAIR(GEN_API_METHOD_PROXY_2, P, ##__VA_ARGS__){NULL, NULL, 0}}; \
|
|
return ambus_call_sync_with_packer(P(), #m, dpinfo); \
|
|
};
|
|
#define GEN_API_METHOD_PROXY(P, f, ...) GEN_API_METHOD_PROXY_NAME(P, f, f, ##__VA_ARGS__)
|
|
|
|
#define GEN_VTABLE_EX_5(P, x, y) AMBUS_DATA_TYPE_IS_OUT(x, AMBUS_DATA_TYPE_SIG(AMBUS_DATA_TYPE_STRIP(x)), "")
|
|
#define GEN_VTABLE_EX_4(P, x, y) AMBUS_DATA_TYPE_IS_OUT(x, "", AMBUS_DATA_TYPE_SIG(AMBUS_DATA_TYPE_STRIP(x)))
|
|
#define GEN_VTABLE_EX_3(P, f, ...) \
|
|
{#f, MACRO_MAP_PAIR(GEN_VTABLE_EX_4, P, ##__VA_ARGS__), MACRO_MAP_PAIR(GEN_VTABLE_EX_5, P, ##__VA_ARGS__)},
|
|
#define GEN_VTABLE_EX_2(P,x,y) AMBUS_DATA_TYPE_SIG(AMBUS_DATA_TYPE_STRIP(x))
|
|
#define GEN_VTABLE_EX_1(P,f,...) {#f, MACRO_MAP_PAIR(GEN_VTABLE_EX_2, P, ##__VA_ARGS__), NULL},
|
|
#define AMBUS_DEFINE_INTERFACE_EX(M, service, object, interface) \
|
|
struct ambus_interface M##_interface = { \
|
|
service, \
|
|
object, \
|
|
interface, \
|
|
{M(M, GEN_VTABLE_EX_1, GEN_VTABLE_EX_1, GEN_VTABLE_EX_3, GEN_VTABLE_EX_1){0, 0, 0}}};
|
|
|
|
#define GEN_VTABLE_PROP_EX(P, f, x, y) SD_BUS_PROPERTY(#f, AMBUS_DATA_TYPE_SIG(x), P##_property_get, 0, 0),
|
|
#define GEN_VTABLE_PROPRW_EX(P, f, x, y) \
|
|
SD_BUS_WRITABLE_PROPERTY(#f, AMBUS_DATA_TYPE_SIG(x), P##_property_get, P##_property_set, 0, 0),
|
|
#define GEN_VTABLE_METHOD_EX_1(P, x, y) AMBUS_DATA_TYPE_IS_OUT(x, "" , SD_BUS_PARAM(y))
|
|
#define GEN_VTABLE_METHOD_EX_2(P, x, y) AMBUS_DATA_TYPE_IS_OUT(x, SD_BUS_PARAM(y), "")
|
|
#define GEN_VTABLE_METHOD_EX(P, f, ...) \
|
|
SD_BUS_METHOD_WITH_NAMES( \
|
|
#f, MACRO_MAP_PAIR(GEN_VTABLE_EX_4, P, ##__VA_ARGS__), MACRO_MAP_PAIR(GEN_VTABLE_METHOD_EX_1, P, ##__VA_ARGS__), \
|
|
MACRO_MAP_PAIR(GEN_VTABLE_EX_5, P, ##__VA_ARGS__), MACRO_MAP_PAIR(GEN_VTABLE_METHOD_EX_2, P, ##__VA_ARGS__), \
|
|
P##_method_##f, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
#define GEN_VTABLE_SIGNAL_EX(P, f, ...) \
|
|
SD_BUS_SIGNAL_WITH_NAMES(#f, MACRO_MAP_PAIR(GEN_VTABLE_EX_4, P, ##__VA_ARGS__), \
|
|
MACRO_MAP_PAIR(GEN_VTABLE_METHOD_EX_1, P, ##__VA_ARGS__), 0),
|
|
#define AMBUS_DEFINE_VTABLE_ADDITIONAL(M, ADDITIONAL) \
|
|
M(M, GEN_EMPTY, GEN_EMPTY, GEN_API_METHOD_IMPL, GEN_EMPTY); \
|
|
static const sd_bus_vtable M##_vtable[] = {SD_BUS_VTABLE_START(0), \
|
|
M(M, GEN_VTABLE_PROP_EX, GEN_VTABLE_PROPRW_EX, GEN_VTABLE_METHOD_EX, \
|
|
GEN_VTABLE_SIGNAL_EX) ADDITIONAL() SD_BUS_VTABLE_END};
|
|
#define AMBUS_DEFINE_VTABLE_EX(M) AMBUS_DEFINE_VTABLE_ADDITIONAL(M, MACRO_EMPTY)
|
|
|
|
#define AMBUS_DEFINE_PROXY_EX(M,P) M(P, GEN_EMPTY, GEN_EMPTY, GEN_API_METHOD_PROXY, GEN_EMPTY)
|
|
|
|
#define AMBUS_DECLARE_DATA_TYPE(x, ...) extern struct ambus_data_type_info AMBUS_DATA_TYPE_INFO(x);
|
|
#define AMBUS_DEFINE_DATA_TYPE(x, ...) \
|
|
struct ambus_data_type_info AMBUS_DATA_TYPE_INFO(x) = {AMBUS_DATA_TYPE_SIG(x), __VA_ARGS__};
|
|
|
|
#define AMBUS_DATA_TYPE_DECLARE_ARRAY(t, x) \
|
|
extern struct ambus_data_type_info_array AMBUS_DATA_TYPE_INFO(t); \
|
|
struct t { \
|
|
int num; \
|
|
AMBUS_DATA_TYPE_CT(x) val[]; \
|
|
};
|
|
|
|
#define AMBUS_DATA_TYPE_DEFINE_ARRAY(t, x) \
|
|
struct ambus_data_type_info_array AMBUS_DATA_TYPE_INFO(t) = { \
|
|
{AMBUS_DATA_TYPE_SIG(t), ambus_data_pack_array, ambus_data_unpack_array, ambus_data_free_array}, \
|
|
AMBUS_DATA_TYPE_INFO_PTR(x), \
|
|
sizeof(AMBUS_DATA_TYPE_CT(x)), \
|
|
offsetof(struct t, val), \
|
|
offsetof( \
|
|
struct { \
|
|
void *next; \
|
|
AMBUS_DATA_TYPE_CT(x) val[]; \
|
|
}, \
|
|
val)};
|
|
|
|
#define AMBUS_ARRAY_NEW(t, n) \
|
|
({ \
|
|
struct t *v = malloc(offsetof(struct t, val) + sizeof(v->val[0]) * n); \
|
|
v->num = n; \
|
|
v; \
|
|
})
|
|
|
|
#define AMBUS_DATA_FREE(t, v) (AMBUS_DATA_TYPE_INFO_PTR(t))->free(AMBUS_DATA_TYPE_INFO_PTR(t), v)
|
|
|
|
#define GEN_STRUCT_DECLARE_1(P, x, y) AMBUS_DATA_TYPE_CT(x) y;
|
|
#define AMBUS_DATA_TYPE_DECLARE_STRUCT(t, ...) \
|
|
extern struct ambus_data_type_info_struct AMBUS_DATA_TYPE_INFO(t); \
|
|
struct t { \
|
|
MACRO_MAP_PAIR(GEN_STRUCT_DECLARE_1, P, ##__VA_ARGS__) \
|
|
};
|
|
|
|
#define GEN_STRUCT_DEFINE_1(P, x, y) {AMBUS_DATA_TYPE_INFO_PTR(x), offsetof(P, y)},
|
|
#define GEN_STRUCT_DEFINE_2(P, x, y) AMBUS_DATA_TYPE_SIG(x)
|
|
#define AMBUS_DATA_TYPE_DEFINE_STRUCT(t, ...) \
|
|
struct ambus_data_type_info_struct AMBUS_DATA_TYPE_INFO(t) = { \
|
|
{AMBUS_DATA_TYPE_SIG(t), ambus_data_pack_struct, ambus_data_unpack_struct, ambus_data_free_struct}, \
|
|
MACRO_MAP_PAIR(GEN_STRUCT_DEFINE_2, P, ##__VA_ARGS__), \
|
|
sizeof(struct t), \
|
|
{MACRO_MAP_PAIR(GEN_STRUCT_DEFINE_1, struct t, ##__VA_ARGS__) NULL}};
|
|
|
|
#define AMBUS_DATA_TYPE_DECLARE_MAP(t, KEY, key, VAL, val) \
|
|
extern struct ambus_data_type_info_map AMBUS_DATA_TYPE_INFO(t); \
|
|
struct t { \
|
|
struct t *next; \
|
|
AMBUS_DATA_TYPE_CT(KEY) key; \
|
|
AMBUS_DATA_TYPE_CT(VAL) val; \
|
|
};
|
|
|
|
#define AMBUS_DATA_TYPE_DEFINE_MAP(t, KEY, key, VAL, val) \
|
|
struct ambus_data_type_info_map AMBUS_DATA_TYPE_INFO(t) = { \
|
|
{AMBUS_DATA_TYPE_SIG(t), ambus_data_pack_map, ambus_data_unpack_map, ambus_data_free_map}, \
|
|
AMBUS_DATA_TYPE_INFO_PTR(KEY), \
|
|
AMBUS_DATA_TYPE_INFO_PTR(VAL), \
|
|
AMBUS_DATA_TYPE_SIG(KEY) AMBUS_DATA_TYPE_SIG(VAL), \
|
|
sizeof(struct t), \
|
|
offsetof(struct t, key), \
|
|
offsetof(struct t, val)}
|
|
|
|
#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[];
|
|
};
|
|
|
|
struct ambus_data_type_info {
|
|
const char *signature;
|
|
int (*pack)(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int (*unpack)(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
void (*free)(struct ambus_data_type_info *t, void *val);
|
|
};
|
|
|
|
struct ambus_data_pack_info {
|
|
struct ambus_data_type_info *type;
|
|
void *val;
|
|
int output;
|
|
};
|
|
|
|
struct ambus_data_type_info_array {
|
|
struct ambus_data_type_info ainfo;
|
|
struct ambus_data_type_info *dinfo;
|
|
int size;
|
|
int offset;
|
|
int ptr_offset;
|
|
};
|
|
|
|
struct ambus_data_type_info_map {
|
|
struct ambus_data_type_info ainfo;
|
|
struct ambus_data_type_info *kinfo;
|
|
struct ambus_data_type_info *vinfo;
|
|
char *contents;
|
|
int size;
|
|
int koff;
|
|
int voff;
|
|
};
|
|
|
|
struct ambus_data_type_info_struct {
|
|
struct ambus_data_type_info ainfo;
|
|
char *contents;
|
|
int size;
|
|
struct {
|
|
struct ambus_data_type_info *finfo;
|
|
int offset;
|
|
} fields_info[];
|
|
};
|
|
|
|
AMBUS_DECLARE_DATA_TYPE(uint8_t);
|
|
AMBUS_DECLARE_DATA_TYPE(bool);
|
|
AMBUS_DECLARE_DATA_TYPE(uint16_t);
|
|
AMBUS_DECLARE_DATA_TYPE(int16_t);
|
|
AMBUS_DECLARE_DATA_TYPE(int32_t);
|
|
AMBUS_DECLARE_DATA_TYPE(uint32_t);
|
|
AMBUS_DECLARE_DATA_TYPE(int64_t);
|
|
AMBUS_DECLARE_DATA_TYPE(uint64_t);
|
|
AMBUS_DECLARE_DATA_TYPE(double);
|
|
AMBUS_DECLARE_DATA_TYPE(string);
|
|
AMBUS_DECLARE_DATA_TYPE(unixfd);
|
|
|
|
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);
|
|
|
|
// return aml_dbus pointer associated with current thread
|
|
struct aml_dbus *ambus_current();
|
|
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),
|
|
void *reply_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));
|
|
|
|
int ambus_data_pack_basic(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_unpack_basic(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_unpack_string(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_pack_array(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_unpack_array(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
void ambus_data_free_array(struct ambus_data_type_info *t, void *val);
|
|
void ambus_data_free_struct(struct ambus_data_type_info *t, void *val);
|
|
int ambus_data_unpack_struct(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_pack_struct(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_pack_map(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
int ambus_data_unpack_map(struct ambus_data_type_info *t, sd_bus_message *m, void *val);
|
|
void ambus_data_free_map(struct ambus_data_type_info *t, void *val);
|
|
int ambus_pack_all(sd_bus_message *m, struct ambus_data_pack_info *pi);
|
|
int ambus_unpack_all(sd_bus_message *m, struct ambus_data_pack_info *pi);
|
|
void ambus_free_all(struct ambus_data_pack_info *pi);
|
|
int ambus_dispatch_to_implement(sd_bus_message *m, struct ambus_data_pack_info *pi, int (*call)(void));
|
|
int ambus_call_sync_with_packer(struct aml_dbus *ambus, const char *destination, const char *path,
|
|
const char *interface, const char *member, struct ambus_data_pack_info *pi);
|
|
|
|
#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 <typename T>
|
|
struct ambus_data_type<T, typename std::enable_if<std::is_same<T, long>::value>::type> : ambus_simple_type<T, '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;
|
|
}
|
|
};
|
|
|
|
struct ambus_unix_fd_t {
|
|
ambus_unix_fd_t() : fd(-1) {}
|
|
ambus_unix_fd_t(const int f) : fd(f) {}
|
|
operator int() const { return fd; };
|
|
int fd;
|
|
};
|
|
template <> struct ambus_data_type<ambus_unix_fd_t> : ambus_simple_type<ambus_unix_fd_t, 'h', int> {};
|
|
|
|
// 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<> {
|
|
ambus_method_call<>(int _size, int (*_call)(void *, void *, sd_bus_message *),
|
|
int (*_reply)(void *, sd_bus_message *), void (*_deinit)(void *))
|
|
: size(_size), dp_call(_call), dp_reply(_reply), dp_deinit(_deinit), async_reply(false) {}
|
|
static int handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
|
struct ambus_method_call<> *pcall = (struct ambus_method_call<> *)userdata;
|
|
pcall->async_reply = 0;
|
|
void *val = alloca(pcall->size);
|
|
int r;
|
|
sd_bus_message *reply = NULL;
|
|
if ((r = pcall->dp_call(pcall, val, m)) < 0)
|
|
goto done;
|
|
if (!sd_bus_message_get_expect_reply(m) || pcall->async_reply) {
|
|
r = 1;
|
|
goto done;
|
|
}
|
|
AMBUS_CHECK(r, sd_bus_message_new_method_return(m, &reply), goto done);
|
|
AMBUS_CHECK(r, pcall->dp_reply(val, reply), goto done);
|
|
AMBUS_CHECK(r, sd_bus_send(sd_bus_message_get_bus(m), reply, NULL), goto done);
|
|
done:
|
|
if (reply)
|
|
sd_bus_message_unref(reply);
|
|
pcall->dp_deinit(val);
|
|
return r;
|
|
}
|
|
int size;
|
|
int (*dp_call)(void *pcall, void *data, sd_bus_message *m);
|
|
int (*dp_reply)(void *data, sd_bus_message *m);
|
|
void (*dp_deinit)(void *data);
|
|
bool async_reply;
|
|
static sd_bus_message *set_async_reply(struct aml_dbus *ambus) {
|
|
sd_bus_message *reply = NULL;
|
|
sd_bus_message *m = sd_bus_get_current_message(ambus_sdbus(ambus));
|
|
sd_bus_message_new_method_return(m, &reply);
|
|
struct ambus_method_call<> *pcall = (struct ambus_method_call<> *)sd_bus_get_current_userdata(ambus_sdbus(ambus));
|
|
pcall->async_reply = 1;
|
|
return reply;
|
|
}
|
|
};
|
|
|
|
#if 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) {}
|
|
virtual int call(sd_bus_message *m) {
|
|
data_pack val;
|
|
int r = 0;
|
|
if (data_pack::signature_input::value[0])
|
|
r = val.unpack(false, m);
|
|
RET ret;
|
|
if (r >= 0)
|
|
r = val.apply_member(pThis, ret, callback);
|
|
if (!sd_bus_message_get_expect_reply(m) || async_reply)
|
|
return 1;
|
|
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 && signature_output::value[0])
|
|
r = val.pack(true, reply);
|
|
if (r >= 0)
|
|
r = sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
|
|
if (reply)
|
|
sd_bus_message_unref(reply);
|
|
return r;
|
|
}
|
|
RET (CLS::*callback)(Args...);
|
|
CLS *pThis;
|
|
};
|
|
#endif
|
|
|
|
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;
|
|
struct data_pack_and_return {
|
|
data_pack val;
|
|
RET ret;
|
|
};
|
|
ambus_method_call<RET (*)(Args...)>(const char *name, RET (*pfn)(Args...))
|
|
: ambus_method_call<>(sizeof(data_pack_and_return), call, reply, deinit), callback(pfn) {}
|
|
static int call(void *pcall, void *data, sd_bus_message *m) {
|
|
data_pack_and_return *p = new (data) data_pack_and_return;
|
|
auto self = static_cast<ambus_method_call<RET (*)(Args...)> *>(pcall);
|
|
int r = data_pack::signature_input::value[0] ? p->val.unpack(false, m) : 0;
|
|
return r >= 0 ? p->val.apply(p->ret, self->callback) : r;
|
|
}
|
|
static int reply(void *data, sd_bus_message *m) {
|
|
data_pack_and_return *p = static_cast<data_pack_and_return *>(data);
|
|
int r = ambus_data_type<RET>::pack(m, p->ret);
|
|
return (r >= 0 && signature_output::value[0]) ? p->val.pack(true, m) : r;
|
|
}
|
|
static void deinit(void *data) {
|
|
data_pack_and_return *p = static_cast<data_pack_and_return *>(data);
|
|
p->~data_pack_and_return();
|
|
}
|
|
RET (*callback)(Args...);
|
|
};
|
|
|
|
struct ambus_runnable_task {
|
|
using prototype = std::function<void(void)>;
|
|
prototype func;
|
|
ambus_runnable_task(prototype &&f) : func(std::move(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;
|
|
}
|
|
static int call_async(sd_bus_message_handler_t cb, void *userdata, 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...); }};
|
|
return ambus_call_async_general(ambus, service, object, interface, member, &p, ambus_method_proxy_packer::pack,
|
|
userdata, cb);
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif /* end of include guard: AML_DBUS_H */
|