1 /**
2  * @file aiot_dm_api.h
3  * @brief 数据模型模块头文件, 提供了物模型数据格式的上云能力, 包括属性, 事件, 服务和物模型二进制格式的数据上下行能力
4  * @date 2020-01-20
5  *
6  * @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
7  *
8  * @details
9  *
10  * 请按照以下流程使用API
11  *
12  * 1. 在使用物模型模块前, 用户应首先创建好一个MQTT实例
13  *
14  * 2. 调用`aiot_dm_init`创建一个物模型实例, 保存实例句柄
15  *
16  * 3. 调用`aiot_dm_setopt`配置`AIOT_DMOPT_MQTT_HANDLE`选项以设置MQTT句柄, 此选项为强制配置选项
17  *
18  * 4. 调用`aiot_dm_setopt`配置`AIOT_DMOPT_RECV_HANDLER`和`AIOT_DMOPT_USERDATA`选项以注册数据接受回调函数和用户上下文数据指针
19  *
20  * 5. 在使用`aiot_dm_send`发送消息前, 应先完成MQTT实例的建连
21  *
22  * 6. 调动`aiot_dm_send`发送不同类型的消息到云平台, 在注册的回调函数中处理各种类型的云平台下行消息
23  *
24  */
25 
26 #ifndef __AIOT_DM_API_H__
27 #define __AIOT_DM_API_H__
28 
29 #if defined(__cplusplus)
30 extern "C" {
31 #endif
32 
33 #include <stdint.h>
34 
35 /**
36  * @brief -0x0A00~-0x0AFF表达SDK在data-model模块内的状态码
37  */
38 #define STATE_DM_BASE                                           (-0x0A00)
39 
40 /**
41  * @brief 用户发送@ref AIOT_DMMSG_EVENT_POST 消息时, 消息数据中的event_id为NULL
42  */
43 #define STATE_DM_EVENT_ID_IS_NULL                               (-0x0A01)
44 
45 /**
46  * @brief 用户发送@ref AIOT_DMMSG_ASYNC_SERVICE_REPLY 或@ref AIOT_DMMSG_SYNC_SERVICE_REPLY 消息时, 消息数据中的event_id为NULL
47  */
48 #define STATE_DM_SERVICE_ID_IS_NULL                             (-0x0A02)
49 
50 /**
51  * @brief 用户发送@ref AIOT_DMMSG_SYNC_SERVICE_REPLY 消息时, 消息数据中的rrpc_id为NULL
52  */
53 #define STATE_DM_RRPC_ID_IS_NULL                                (-0x0A03)
54 
55 /**
56  * @brief 用户发送请求类消息时, 消息数据中的param为NULL
57  */
58 #define STATE_DM_MSG_PARAMS_IS_NULL                             (-0X0A04)
59 
60 /**
61  * @brief 用户发送应答类消息时, 消息数据中的data为NULL
62  */
63 #define STATE_DM_MSG_DATA_IS_NULL                               (-0X0A05)
64 
65 /**
66  * @brief 解析下行数据对应的topic时发生错误
67  */
68 #define STATE_DM_INTERNAL_TOPIC_ERROR                           (-0x0A06)
69 
70 /**
71  * @brief 用户未调用@ref aiot_dm_setopt 配置MQTT句柄
72  */
73 #define STATE_DM_MQTT_HANDLE_IS_NULL                            (-0x0A07)
74 
75 /**
76  * @brief 接收到服务器下行消息时的日志状态码
77  */
78 #define STATE_DM_LOG_RECV                                       (-0x0A08)
79 
80 /**
81  * @brief 解析服务器下行消息失败时的日志状态码
82  */
83 #define SATAE_DM_LOG_PARSE_RECV_MSG_FAILED                      (-0x0A09)
84 
85 
86 /**
87  * @brief data-model模块的配置选项枚举类型定义. @ref aiot_dm_setopt 函数入数data的数据类型根据不同的选项而不同
88  *
89  */
90 typedef enum {
91     /**
92      * @brief 模块依赖的MQTT句柄
93      *
94      * @details
95      *
96      * data-model模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作
97      *
98      * 数据类型: (void *)
99      */
100     AIOT_DMOPT_MQTT_HANDLE,
101 
102     /**
103      * @brief 数据接收回调函数, data-model接收物联网平台的下行消息后调用此回调函数
104      *
105      * @details
106      *
107      * 数据类型: (aiot_dm_recv_handler_t), 详细查看@ref aiot_dm_recv_handler_t 回调函数原型
108      */
109     AIOT_DMOPT_RECV_HANDLER,
110 
111     /**
112      * @brief 指向用户上下文数据的指针
113      *
114      * @details
115      *
116      * 在用户注册的@ref aiot_dm_recv_handler_t 数据接收回调函数中会同过userdata参数将此指针返回给用户
117      *
118      * 数据类型: (void *)
119      */
120     AIOT_DMOPT_USERDATA,
121 
122     /**
123      * @brief 用户是否希望接收post消息后的reply
124      *
125      * @details
126      *
127      * 是否要接收云端的reply消息. 1表示要接收, 0表示不要.
128      *
129      * 数据类型: (uint8_t) *)
130      */
131     AIOT_DMOPT_POST_REPLY,
132 
133     /**
134      * @brief 配置选项数量最大值, 不可用作配置参数
135      */
136     AIOT_DMOPT_MAX,
137 } aiot_dm_option_t;
138 
139 /**
140  * @brief data-model模块发送消息类型
141  *
142  * @details
143  *
144  * 这个枚举类型包括了dm模块支持发送的所有数据类型, 不同的消息类型将对于不同的消息结构体
145  * 用户可查看网页文档<a href="https://help.aliyun.com/document_detail/89301.html">设备属性/事件/服务</a>进一步了解各种数据类型
146  *
147  */
148 typedef enum {
149     /**
150      * @brief 属性上报, 消息结构体参考@ref aiot_dm_msg_property_post_t \n
151      * 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
152      */
153     AIOT_DMMSG_PROPERTY_POST,
154 
155     /**
156      * @brief 事件上报, 消息结构体参考@ref aiot_dm_msg_event_post_t \n
157      * 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
158      */
159     AIOT_DMMSG_EVENT_POST,
160 
161     /**
162      * @brief 属性设置应答, 消息结构体参考@ref aiot_dm_msg_property_set_reply_t
163      */
164     AIOT_DMMSG_PROPERTY_SET_REPLY,
165 
166     /**
167      * @brief 异步服务应答, 消息结构体参考@ref aiot_dm_msg_async_service_reply_t
168      */
169     AIOT_DMMSG_ASYNC_SERVICE_REPLY,
170 
171     /**
172      * @brief 同步服务应答, 消息结构体参考@ref aiot_dm_msg_sync_service_reply_t
173      */
174     AIOT_DMMSG_SYNC_SERVICE_REPLY,
175 
176     /**
177      * @brief 二进制格式的物模型上行数据, 消息结构体参考@ref aiot_dm_msg_raw_data_t
178      */
179     AIOT_DMMSG_RAW_DATA,
180 
181     /**
182      * @brief 二进制格式的同步服务应答, 消息结构体参考@ref aiot_dm_msg_raw_service_reply_t
183      */
184     AIOT_DMMSG_RAW_SERVICE_REPLY,
185 
186     /**
187      * @brief 获取期望属性值, 消息结构体请参考@ref aiot_dm_msg_get_desired_t, \n
188      * 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
189      */
190     AIOT_DMMSG_GET_DESIRED,
191 
192     /**
193      * @brief 清除指定的期望值, 消息结构体请参考@ref aiot_dm_msg_delete_desired_t \n
194      * 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
195      */
196     AIOT_DMMSG_DELETE_DESIRED,
197 
198     /**
199      * @brief 清除指定的期望值, 消息结构体请参考@ref aiot_dm_msg_delete_desired_t \n
200      * 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
201      */
202     AIOT_DMMSG_PROPERTY_BATCH_POST,
203 
204     /**
205      * @brief 消息数量最大值, 不可用作消息类型
206      */
207     AIOT_DMMSG_MAX,
208 } aiot_dm_msg_type_t;
209 
210 /**
211  * @brief <b>物模型属性上报</b>消息结构体
212  */
213 typedef struct {
214     /**
215      * @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要上报的属性数据, 如<i>"{\"LightSwitch\":0}"</i>
216      */
217     char *params;
218 } aiot_dm_msg_property_post_t;
219 
220 /**
221  * @brief <b>物模型事件上报</b>消息结构体
222  */
223 typedef struct {
224     /**
225      * @brief 事件标示符, <b>必须为以结束符'\0'结尾的字符串</b>
226      */
227     char *event_id;
228     /**
229      * @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要上报的事件数据, 如<i>"{\"ErrorNum\":0}"</i>
230      */
231     char *params;
232 } aiot_dm_msg_event_post_t;
233 
234 /**
235  * @brief <b>属性设置应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_PROPERTY_SET 类型的属性设置后, 可发送此消息进行回复
236  */
237 typedef struct {
238     /**
239      * @brief 消息标识符, uint64_t类型的整数, <b>必须与属性设置的消息标示符一致</b>
240      */
241     uint64_t msg_id;
242     /**
243      * @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
244      */
245     uint32_t code;
246     /**
247      * @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
248      */
249     char    *data;
250 } aiot_dm_msg_property_set_reply_t;
251 
252 /**
253  * @brief <b>异步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_ASYNC_SERVICE_INVOKE 类型的异步服务调用消息后, 应发送此消息进行应答
254  */
255 typedef struct {
256     /**
257      * @brief 消息标识符, uint64_t类型的整数, <b>必须与异步服务调用的消息标示符一致</b>
258      */
259     uint64_t msg_id;
260     /**
261      * @brief 服务标示符, 标识了要响应服务
262      */
263     char    *service_id;
264     /**
265      * @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
266      */
267     uint32_t code;
268     /**
269      * @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
270      */
271     char    *data;
272 } aiot_dm_msg_async_service_reply_t;
273 
274 /**
275  * @brief <b>同步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_SYNC_SERVICE_INVOKE 类型的同步服务调用消息后, 应在超时时间(默认7s)内进行应答
276  */
277 typedef struct {
278     /**
279      * @brief 消息标识符, uint64_t类型的整数, <b>必须与同步服务调用的消息标示符一致</b>
280      */
281     uint64_t msg_id;
282     /**
283      * @brief RRPC标示符, 用于唯一标识每一个同步服务的字符串, <b>必须与同步服务调用消息的RRPC标示符一致</b>
284      */
285     char    *rrpc_id;
286     /**
287      * @brief 服务标示符, 标识了要响应服务
288      */
289     char    *service_id;
290     /**
291      * @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
292      */
293     uint32_t code;
294     /**
295      * @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
296      */
297     char    *data;
298 } aiot_dm_msg_sync_service_reply_t;
299 
300 /**
301  * @brief <b>物模型二进制数据</b>消息结构体, 发送的二进制数据将通过物联网平台的JavaScript脚本转化为JSON格式数据, 用户发送此消息前应确保已正确启用云端解析脚本
302  */
303 typedef struct {
304     /**
305      * @brief 指向待发送二进制数据的指针
306      */
307     uint8_t *data;
308     /**
309      * @brief 待发送数据的长度
310      */
311     uint32_t data_len;
312 } aiot_dm_msg_raw_data_t;
313 
314 /**
315  * @brief <b>二进制格式的同步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE 类型消息后, 应在超时时间(默认7s)内进行应答\n
316  * 用户在使用此消息前应确保已启用云端解析脚本, 并且脚本工作正常
317  */
318 typedef struct {
319     /**
320      * @brief RRPC标示符, 特殊字符串, <b>必须与同步服务调用消息的RRPC标示符一致</b>
321      */
322     char    *rrpc_id;
323     /**
324      * @brief 指向待发送二进制数据的指针
325      */
326     uint8_t *data;
327     /**
328      * @brief 待发送数据的长度
329      */
330     uint32_t data_len;
331 } aiot_dm_msg_raw_service_reply_t;
332 
333 /**
334  * @brief <b>获取期望属性值</b>消息结构体, 发送
335  */
336 typedef struct {
337     /**
338      * @brief 字符串形式的JSON<b>数组</b>, <b>必须以结束符'\0'结尾</b>. 应包含用户要获取的期望属性的ID, 如<i>"[\"LightSwitch\"]"</i>
339      */
340     char *params;
341 } aiot_dm_msg_get_desired_t;
342 
343 /**
344  * @brief <b>删除指定期望值</b>消息结构体
345  */
346 typedef struct {
347     /**
348      * @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 应包含用户要删除的期望属性的ID和期望值版本号, 如<i>"{\"LightSwitch\":{\"version\":1},\"Color\":{}}"</i>
349      */
350     char *params;
351 } aiot_dm_msg_delete_desired_t;
352 
353 
354 /**
355  * @brief <b>物模型属性上报</b>消息结构体
356  */
357 typedef struct {
358     /**
359      * @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要批量上报的属性和事件数据, 如 {"properties":{"Power": [ { "value": "on", "time": 1524448722000 },
360      *  { "value": "off", "time": 1524448722001 } ], "WF": [ { "value": 3, "time": 1524448722000 }]}, "events": {"alarmEvent": [{ "value": { "Power": "on", "WF": "2"},
361      *  "time": 1524448722000}]}}
362      */
363     char *params;
364 } aiot_dm_msg_property_batch_post_t;
365 
366 /**
367  * @brief data-model模块发送消息的消息结构体
368  */
369 typedef struct {
370     /**
371      * @brief 消息所属设备的product_key, 若为NULL则使用通过aiot_dm_setopt配置的product_key\n
372      * 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
373      */
374     char *product_key;
375     /**
376      * @brief 消息所属设备的device_name, 若为NULL则使用通过aiot_dm_setopt配置的device_name\n
377      * 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
378      */
379     char *device_name;
380     /**
381      * @brief 消息类型, 可参考@ref aiot_dm_msg_type_t
382      */
383     aiot_dm_msg_type_t type;
384     /**
385      * @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
386      */
387     union {
388         aiot_dm_msg_property_post_t         property_post;
389         aiot_dm_msg_event_post_t            event_post;
390         aiot_dm_msg_property_set_reply_t    property_set_reply;
391         aiot_dm_msg_sync_service_reply_t    sync_service_reply;
392         aiot_dm_msg_async_service_reply_t   async_service_reply;
393         aiot_dm_msg_raw_data_t              raw_data;
394         aiot_dm_msg_raw_service_reply_t     raw_service_reply;
395         aiot_dm_msg_get_desired_t           get_desired;
396         aiot_dm_msg_delete_desired_t        delete_desired;
397     } data;
398 } aiot_dm_msg_t;
399 
400 
401 /**
402  * @brief data-model模块接受消息类型枚举
403  *
404  * @details
405  *
406  * 这个枚举类型包括了dm模块支持接收的所有数据类型, 不同的消息类型将对于不同的消息结构体
407  * 用户可查看网页文档<a href="https://help.aliyun.com/document_detail/89301.html">设备属性/事件/服务</a>进一步了解各种数据类型
408  *
409  */
410 typedef enum {
411     /**
412      * @brief 上报属性/实践后服务器返回的应答消息, 消息数据结构体参考@ref aiot_dm_recv_generic_reply_t
413      */
414     AIOT_DMRECV_GENERIC_REPLY,
415 
416     /**
417      * @brief 服务器下发的属性设置消息, 消息数据结构体参考@ref aiot_dm_recv_property_set_t
418      */
419     AIOT_DMRECV_PROPERTY_SET,
420 
421     /**
422      * @brief 服务器下发的异步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_async_service_invoke_t
423      */
424     AIOT_DMRECV_ASYNC_SERVICE_INVOKE,
425 
426     /**
427      * @brief 服务器下发的同步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_sync_service_invoke_t
428      */
429     AIOT_DMRECV_SYNC_SERVICE_INVOKE,
430 
431     /**
432      * @brief 服务器对设备上报的二进制数据应答, 消息数据结构体参考@ref aiot_dm_recv_raw_data_t
433      */
434     AIOT_DMRECV_RAW_DATA_REPLY,
435 
436     /**
437      * @brief 服务器下发的物模型二进制数据, 消息数据结构体参考@ref aiot_dm_recv_raw_data_t
438      */
439     AIOT_DMRECV_RAW_DATA,
440 
441     /**
442      * @brief 服务器下发的二进制格式的同步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_raw_service_invoke_t
443      */
444     AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE,
445 
446     /**
447      * @brief 消息数量最大值, 不可用作消息类型
448      */
449     AIOT_DMRECV_MAX,
450 } aiot_dm_recv_type_t;
451 
452 /**
453  * @brief <b>云端通用应答</b>消息结构体, 设备端上报@ref AIOT_DMMSG_PROPERTY_POST, @ref AIOT_DMMSG_EVENT_POST 或者@ref AIOT_DMMSG_GET_DESIRED 等消息后, 服务器会应答此消息
454  */
455 typedef struct {
456     /**
457      * @brief 消息标识符, uint64_t类型的整数, 与属性上报或事件上报的消息标示符一致
458      */
459     uint32_t msg_id;
460     /**
461      * @brief 设备端错误码, 200-请求成功, 更多错误码码查看<a href="https://help.aliyun.com/document_detail/120329.html">设备端错误码</a>
462      */
463     uint32_t code;
464     /**
465      * @brief 指向云端应答数据的指针
466      */
467     char *data;
468     /**
469      * @brief 云端应答数据的长度
470      */
471     uint32_t data_len;
472     /**
473      * @brief 指向状态消息字符串的指针, 当设备端上报请求成功时对应的应答消息为"success", 若请求失败则应答消息中包含错误信息
474      */
475     char *message;
476     /**
477      * @brief 消息字符串的长度
478      */
479     uint32_t message_len;
480 } aiot_dm_recv_generic_reply_t;
481 
482 /**
483  * @brief <b>属性设置</b>消息结构体
484  */
485 typedef struct {
486     /**
487      * @brief 消息标识符, uint64_t类型的整数
488      */
489     uint64_t    msg_id;
490     /**
491      * @brief 服务器下发的属性数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
492      */
493     char       *params;
494     /**
495      * @brief 属性数据的字符串长度
496      */
497     uint32_t    params_len;
498 } aiot_dm_recv_property_set_t;
499 
500 /**
501  * @brief <b>同步服务调用</b>消息结构体, 用户收到同步服务后, 必须在超时时间(默认7s)内进行应答
502  */
503 typedef struct {
504     /**
505      * @brief 消息标识符, uint64_t类型的整数
506      */
507     uint64_t    msg_id;
508     /**
509      * @brief RRPC标识符, 用于唯一标识每一个同步服务的特殊字符串
510      */
511     char       *rrpc_id;
512     /**
513      * @brief 服务标示符, 字符串内容由用户定义的物模型决定
514      */
515     char       *service_id;
516     /**
517      * @brief 服务调用的输入参数数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
518      */
519     char       *params;
520     /**
521      * @brief 输入参数的字符串长度
522      */
523     uint32_t    params_len;
524 } aiot_dm_recv_sync_service_invoke_t;
525 
526 /**
527  * @brief <b>同步服务调用</b>消息结构体
528  */
529 typedef struct {
530     /**
531      * @brief 消息标识符, uint64_t类型的整数
532      */
533     uint64_t    msg_id;
534     /**
535      * @brief 服务标示符, 字符串内容由用户定义的物模型决定
536      */
537     char       *service_id;
538     /**
539      * @brief 服务调用的输入参数数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
540      */
541     char       *params;
542     /**
543      * @brief 输入参数的字符串长度
544      */
545     uint32_t    params_len;
546 } aiot_dm_recv_async_service_invoke_t;
547 
548 /**
549  * @brief <b>物模型二进制数据</b>消息结构体, 服务器的JSON格式物模型数据将通过物联网平台的JavaScript脚本转化为二进制数据, 用户在接收此消息前应确保已正确启用云端解析脚本
550  */
551 typedef struct {
552     /**
553      * @brief 指向接受数据缓冲区的指针
554      */
555     uint8_t    *data;
556     /**
557      * @brief 二进制数据的长度
558      */
559     uint32_t    data_len;
560 } aiot_dm_recv_raw_data_t;
561 
562 /**
563  * @brief <b>二进制数据的同步服务调用</b>消息结构体, 服务器的JSON格式物模型数据将通过物联网平台的JavaScript脚本转化为二进制数据, 用户在接收此消息前应确保已正确启用云端解析脚本
564  */
565 typedef struct {
566     /**
567      * @brief RRPC标识符, 用于唯一标识每一个同步服务的特殊字符串
568      */
569     char       *rrpc_id;
570     /**
571      * @brief 指向接受数据缓冲区的指针
572      */
573     uint8_t    *data;
574     /**
575      * @brief 二进制数据的长度
576      */
577     uint32_t    data_len;
578 } aiot_dm_recv_raw_service_invoke_t;
579 
580 /**
581  * @brief data-model模块接收消息的结构体
582  */
583 typedef struct {
584     /**
585      * @brief 消息所属设备的product_key, 不配置则默认使用MQTT模块配置的product_key
586      */
587     char *product_key;
588     /**
589      * @brief 消息所属设备的device_name, 不配置则默认使用MQTT模块配置的device_name
590      */
591     char *device_name;
592     /**
593      * @brief 接收消息的类型, 可参考@ref aiot_dm_recv_type_t
594      */
595     aiot_dm_recv_type_t type;
596     /**
597      * @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
598      */
599     union {
600         aiot_dm_recv_generic_reply_t        generic_reply;
601         aiot_dm_recv_property_set_t         property_set;
602         aiot_dm_recv_async_service_invoke_t async_service_invoke;
603         aiot_dm_recv_sync_service_invoke_t  sync_service_invoke;
604         aiot_dm_recv_raw_data_t             raw_data;
605         aiot_dm_recv_raw_service_invoke_t   raw_service_invoke;
606     } data;
607 } aiot_dm_recv_t;
608 
609 /**
610  * @brief data-model模块消息接收回调函数的函数原型定义, 当模块接收到服务器下行数据后将调用此回调函数, 并将消息数据通过<i>recv</i>参数输入给用户, \n
611  * 同时将用户上下文数据指针通过<i>userdata</i>参数返回给用户
612  *
613  * @param[in] handle data-model实例句柄
614  * @param[in] recv   服务下发的消息数据, <b>消息结构体中的所有数据指针在离开回调函数后将失效, 保存消息数据必须使用内存复制的方式</b>
615  * @param[in] userdata 指向用户上下文数据的指针, 这个指针由用户通过调用@ref aiot_dm_setopt 配置@ref AIOT_DMOPT_USERDATA 选项设置
616  *
617  * @return void
618  */
619 typedef void (*aiot_dm_recv_handler_t)(void *handle, const aiot_dm_recv_t *recv, void *userdata);
620 
621 /**
622  * @brief 初始化data-model实例
623  *
624  * @return void*
625  * @retval 非NULL data-model实例句柄
626  * @retval NULL 初始化失败, 一般是内存分配失败导致
627  */
628 void *aiot_dm_init(void);
629 
630 /**
631  * @brief 设置data-model参数
632  *
633  * @param[in] handle data-model实例句柄
634  * @param[in] option 配置选项, 更多信息请查看@ref aiot_dm_option_t
635  * @param[in] data   配置数据, 更多信息请查看@ref aiot_dm_option_t
636  *
637  * @return int32_t
638  * @retval STATE_SUCCESS 参数配置成功
639  * @retval STATE_USER_INPUT_NULL_POINTER 入参handle或data为NULL
640  * @retval STATE_USER_INPUT_OUT_RANGE 入参optioin的枚举值>=AIOT_DMOPT_MAX
641  * @retval others 参考@ref aiot_state_api.h
642  *
643  */
644 int32_t aiot_dm_setopt(void *handle, aiot_dm_option_t option, void *data);
645 
646 /**
647  * @brief 发送一条data-model消息到物联网平台, 消息类型和消息数据由msg入参决定
648  *
649  * @param[in] handle data-model实例句柄
650  * @param[in] msg    消息结构体, 可指定发送消息的设备<i>productKey</i>, <i>deviceName</i>; 消息类型, 消息数据等, 更多信息请参考@ref aiot_dm_msg_t
651  *
652  * @return int32_t
653  * @retval >=STATE_SUCCESS 消息发送成功, 对于@ref AIOT_DMMSG_PROPERTY_POST, @ref AIOT_DMMSG_EVENT_POST, @ref AIOT_DMMSG_GET_DESIRED 和@ref AIOT_DMMSG_DELETE_DESIRED 消息, \n
654  * 发送成功返回值为>STATE_SUCCESS的消息标示符<i>msg_id</i>值
655  * @retval STATE_USER_INPUT_NULL_POINTER 入参<i>handle</i>或<i>msg</i>为NULL
656  * @retval STATE_USER_INPUT_OUT_RANGE 入参<i>msg</i>的结构体成员<i>type</i> >= AIOT_DMMSG_MAX
657  * @retval STATE_SYS_DEPEND_MALLOC_FAILED 内存分配失败
658  * @retval STATE_DM_MQTT_HANDLE_IS_NULL 用户未调用@ref aiot_dm_setopt 配置MQTT句柄
659  * @retval others 参考@ref aiot_state_api.h 或@ref STATE_DM_BASE 中对应的错误码说明
660  *
661  */
662 int32_t aiot_dm_send(void *handle, const aiot_dm_msg_t *msg);
663 
664 /**
665  * @brief 销毁data-model实例, 释放资源
666  *
667  * @param[in] p_handle 指向data-model实例句柄的指针
668  * @return int32_t
669  * @retval STATE_SUCCESS 执行成功
670  * @retval <STATE_SUCCESS 执行失败
671  *
672  */
673 int32_t aiot_dm_deinit(void **p_handle);
674 
675 
676 #if defined(__cplusplus)
677 }
678 #endif
679 
680 #endif /* #ifndef __AIOT_DM_API_H__ */
681 
682