全部博文(396)
分类: 嵌入式
2018-05-09 11:46:36
在上次学习中,我们写了client小例子,非常简单,而且通过dbus-binding-tool生成的头文件,非常规范。相比执行,server稍微复杂些,仍然使用上次的xml文件,但是去掉annotation,更为本原一些。文件wei.xml如下:
客户端小程序上次学习给出,正好用于实验。下面详细讲述步骤。
步骤一:生成头文件
dbus-binding-tool --mode=glib-server --prefix=com_wei wei.xml > wei_server.h
注意,--prefix是不可缺少的参数,在有些文章中,没有提到这个,至少我在Moblin的操作系统中测试是需要的。通常来讲,对于项目,也需要提供一个区分的命名空间,无论是否必须,建议加上。"--prefix"参数定义了对象前缀。设对象前缀是$(prefix),则生成的DBusGObjectInfo结构变量名就是dbus_glib_$(prefix)_object_info。
生成了头文件wei_server.h如下:
/* Generated by dbus-binding-tool; do not edit! */
#ifndef __dbus_glib_marshal_com_wei_MARSHAL_H__
#define __dbus_glib_marshal_com_wei_MARSHAL_H__
#include
G_BEGIN_DECLS
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_char (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
/* BOOLEAN:UINT,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.OI8HBV:1) */
extern void dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
void
dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER (GClosure *closure,
GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER) (gpointer data1,
guint arg_1,
gpointer arg_2,
gpointer arg_3,
gpointer data2);
register GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
gboolean v_return;
g_return_if_fail (return_value != NULL);
g_return_if_fail (n_param_values == 4);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_BOOLEAN__UINT_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
v_return = callback (data1,
g_marshal_value_peek_uint (param_values + 1),
g_marshal_value_peek_pointer (param_values + 2),
g_marshal_value_peek_pointer (param_values + 3),
data2);
g_value_set_boolean (return_value, v_return);
}
G_END_DECLS
#endif /* __dbus_glib_marshal_com_wei_MARSHAL_H__ */
#include
static const DBusGMethodInfo dbus_glib_com_wei_methods[] = {
{ (GCallback) com_wei_test , dbus_glib_marshal_com_wei_BOOLEAN__UINT_POINTER_POINTER, 0 },
};
const DBusGObjectInfo dbus_glib_com_wei_object_info = {
0,
dbus_glib_com_wei_methods,
1,
"com.wei.MyObject.Sample/0Test/0S/0x/0I/0u/0d_ret/0O/0F/0N/0d/0/0/0",
"/0",
"/0"
};
步骤二:编写Object文件
在D-Bus学习(五) 和学习(六)中 ,我们给出了底层的例子,直接进行通信操作,没有涉及到对象的概念,使用Glib的高层接口编写的例子,我们可以生成对象,在对象中定义接口中方法和信令的操作。说实在,我对非JAVA的对象都不太熟悉,GObject更是……,不过工具嘛,照着用就是了。既然我们在xml中给出对象的路径,我们可以将对象命名为ComWeiMyObject。头文件com_wei_myobject.h如下:
#ifndef COM_WEI_MYOBJECT_H
#define COM_WEI_MYOBJECT_H
typedef struct ComWeiMyObject ComWeiMyObject;
typedef struct ComWeiMyObjectClass ComWeiMyObjectClass;
struct ComWeiMyObject
{
GObject parent;
};
struct ComWeiMyObjectClass
{
GObjectClass parent;
};
#define COM_WEI_MYOBJECT_TYPE (com_wei_myobject_get_type())
GType com_wei_myobject_get_type(void);
gboolean com_wei_test(ComWeiMyObject * obj , const guint IN_x, gdouble * OUT_d_ret, GError ** error);
#endif
在头文件,我们定义了一个方法处理函数com_wei_test,这个函数也就是wei_server.h中com_wei_test。它的第一个参数就是对象,后面是这个方法的参数,包括输入和输出。下面是com_wei_myobject.c文件:
#include "com_wei_myobject.h"
G_DEFINE_TYPE(ComWeiMyObject,com_wei_myobject,G_TYPE_OBJECT)
static void com_wei_myobject_init(ComWeiMyObject * object)
{//这个两个init函数大概是GObject的套路,在这个简单的小例子中,没有什么特别的初始化处理
}
static void com_wei_myobject_class_init(ComWeiMyObjectClass * klass)
{
}
gboolean com_wei_test (ComWeiMyObject * obj, const guint IN_x, gdouble* OUT_d_ret, GError ** error)
{ //我们只做测试,简单检测输入参数,直接回复输出结果
printf("com_wei_test() get input param: x= %d/n",IN_x);
* OUT_d_ret = 0.99;
return TRUE;
}
实验例子尽量简单,在这个ComWeiMyObject的对象中实现了com.wei.MyObject.Sample接口的Test方法:com_wei_test。
步骤三:写Server程序
OK,我们已经准备好写Server程序,由于Server需要长期监听,因此需要加入Loop循环。Loop已经在D-Bus学习四 的异步例子中学过。我们注意到使用GLib中函数与底层libdbus API的差异,例如底层API使用dbus_bus_get,高层GLib使用dbus_g_bus_get。这种命名方式,在我们提供更高层的接口时可以借鉴。GLib的D-Bus的API参考为
#include "com_wei_myobject.h"
#include "wei_server.h" //注意此两头文件的先后顺序
int main(int argc, char ** argv)
{
DBusGConnection * conn;
GMainLoop * main_loop = NULL;
ComWeiMyObject * obj;
GError * error = NULL;
DBusGProxy * bus_proxy;
int request_name_result;
g_type_init();
main_loop = g_main_loop_new(NULL,FALSE);
//在自动生成的wei_server.h中定义了DBusGObjectInfo dbus_glib_com_wei_object_info, Install introspection information about the given object GType sufficient to allow methods on the object to be invoked by name. 这样,可以在收到信息的时候,可以触发调用它的方法。
dbus_g_object_type_install_info(COM_WEI_MYOBJECT_TYPE , & dbus_glib_com_wei_object_info );
//建议与session dbus的连接,在以前学习过
conn = dbus_g_bus_get(DBUS_BUS_SESSION,&error);
if(conn == NULL){
g_printerr("Failed to connect D-Bus session Daemon!");
g_error_free(error);
return 1;
}
//为连接起一个名字,对于GLib,这个处理比底层的API接口复杂,需要向系统DBus的管理者org.freedesktop.DBus,调用它的接口的方法"RequestName"来实现。居然更复杂,比较奇怪。
bus_proxy = dbus_g_proxy_new_for_name(conn, "org.freedesktop.DBus","/","org.freedesktop.DBus");
if(!dbus_g_proxy_call(bus_proxy,"RequestName ",&error,
G_TYPE_STRING,"com.wei.test", G_TYPE_UINT,0, G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)){
g_printerr("Request Name error : %s/n",error->message);
return 1;
}
obj = g_object_new(COM_WEI_MYOBJECT_TYPE,NULL);
//将对象在指定的path注册到连接上。 Registers a GObject at the given path. 当有消息通过连接,经过路径,找到对象后,根据前面前面的dbus_g_object_type_insall_info,能够调用对应的处理方式。
dbus_g_connection_register_g_object(conn, "/com/wei/MyObject",G_OBJECT(obj));
g_main_loop_run(main_loop);
return 0;
}
OK,完成。如果我们像上一次学习在xml中对方法加上