基于 sddc 协定的 SDK 框架 sddc_sdk_lib 解析
之前在移植 libsddc 库的时候感觉官网 demo 太低效了 (~.~),复制粘贴代码好累,而且写出一个 BUG,其余复制的代码整个就裂开了,于是写了一个 sddc_sdk_lib 库,让 sddc 接入设施更加疾速无效,本文就次要解说一下这个库的结构以及新设施通过该库疾速的应用 sddc 接入 Spirit 1,从而变成一个智能设施。ヽ (・ω・´メ)
对于 SDDC 协定的介绍能够参考:对立了 WiFi 和 ZigBee 下层应用的跨厂商发现与管制 DDC 协定介绍
目前 sddc_sdk_lib 反对三个平台别离是提出 sddc 协定的翼辉信息公布的 MS-RTOS、安信可基于 FreeRTOS 的 ESP 平台、还有就是最近比拟火的 Arduino 平台(这货色是真好使。习惯 Arduino 之后齐全不想用传统平台了),老样子货色都放在了灵感桌面的机密宝库。
SDDC 构造以及各类设施的定义
在 SDDC_SDK_lib.h
中,SDDC 整体构造形容如下:
/*********************************************************************************************************
SDDC 整体构造形容
*********************************************************************************************************/
typedef struct {
char *token;
DEV_INFO *devinfo;
IO_DEV_REGINFO *io_dev_reg;
int io_dev_reg_num;
NUM_DEV_REGINFO *num_dev_reg;
int num_dev_reg_num;
DEV_STATE_GET *state_get_reg;
int state_get_reg_num;
DIS_DEV_REGINFO *dis_dev_reg;
int dis_dev_num;
} SDDC_CONFIG_INFO;
其中 DEV_INFO
中的内容是通过 SDDC 上报到 Spirit 1 的信息,例如设施名称、设施类型、形容等:
/*********************************************************************************************************
SDDC 外面信息上报波及到的设施信息形容
*********************************************************************************************************/
typedef struct {
char *name;
char *type;
sddc_bool_t excl;
char *desc;
char *model;
char *vendor;
} DEV_INFO;
IO_DEV_REGINFO
、NUM_DEV_REGINFO
、DIS_DEV_REGINFO
别离是 IO 类型、数字类型、显示类型设施的形容,其中蕴含对象名称以及对应的 Set 函数;
/*********************************************************************************************************
SDDC 外面 IO 类设施的注册构造体
*********************************************************************************************************/
typedef struct {
char *objname;
Io_Set IO_Fun;
} IO_DEV_REGINFO;
/*********************************************************************************************************
SDDC 外面数字类设施的注册构造体
*********************************************************************************************************/
typedef struct {
char *objname;
Num_Set Num_Fun;
} NUM_DEV_REGINFO;
/*********************************************************************************************************
SDDC 外面显示类设施的注册构造体
*********************************************************************************************************/
typedef struct {
char *objname;
Dis_Set Dis_Fun;
} DIS_DEV_REGINFO;
DEV_STATE_GET
中是所有设施对象的 Get 函数汇合;
/*********************************************************************************************************
SDDC 后果查问类函数注册构造体
*********************************************************************************************************/
#define DEV_IO_TYPE 0
#define DEV_NUM_TYPE 1
#define DEV_DISPLAY_TYPE 2
typedef struct {
char *objname;
int type;
STATE_GET state_fun;
} DEV_STATE_GET;
SDDC 协定及扩大构造实现函数
在 对立了 WiFi 和 ZigBee 下层应用的跨厂商发现与管制 DDC 协定介绍 这个文章中介绍了具体的协定流程,仿照着官网的 libsddc demo,在 SDDC_SDK_lib.c
中是对于 SDDC 通信协议的实现函数,其中连贯相干的函数能够不必怎么关注,次要的就是 sddc_on_message_lib 函数,这个函数当中是和 Spirit 1 业务通信的入口,依据报文中的 method 字段来匹配是 get 或者 set,再调用对应的处理函数,联合 SDDC 的整体构造,能够看出,所有类型设施共用同一个 get 接口,对于 set 接口依据设施类型不同,有着不同的处理函数,实际上就是把官网的 demo 中的 sddc_on_message 函数形象了一下,把可能收到的报文都形象进去了,这样就免去了写解析报文的步骤。
超级牛逼,超级不便是不是ヾ (゚∀゚ゞ),接下来就给大家承受一下这个 SDK 的扩大构造和应用:
/*********************************************************************************************************
** 函数名称: sddc_on_message_lib
** 性能形容: SDDC 协定收到音讯后的解决回调函数
** 输 入 : sddc SDDC 构造体
** uid 发送音讯的 ID
** message 接管到的报文音讯
** len 报文长度
** 输 出 : 0: 解决失败, 1: 解决胜利.
** 全局变量:
** 调用模块: 无
*********************************************************************************************************/
static sddc_bool_t sddc_on_message_lib(sddc_t *sddc, const uint8_t *uid, const char *message, uint32_t len)
{cJSON *root = cJSON_Parse(message);
cJSON *Json_method;
uint8_t uimethod =DDC_METHOD_VALIDE;
Json_method = cJSON_GetObjectItem(root, "method");
if (NULL == Json_method) {return SDDC_FALSE;}
if (cJSON_IsString(Json_method)) {if (strcmp(Json_method->valuestring,"set") == 0) {uimethod = DDC_METHOD_SET;} else if (strcmp(Json_method->valuestring,"get") == 0) {uimethod = DDC_METHOD_GET;} else {return SDDC_FALSE;}
} else {return SDDC_FALSE;}
if (uimethod == DDC_METHOD_VALIDE) {return SDDC_FALSE;}
if (uimethod == DDC_METHOD_SET) {
int i;
/*
* 数字量、显示量先查问设置,避免开关量是设施的使能
*/
for (i=0; i<G_config->num_dev_reg_num; i++) {object_Number_Set(root, G_config->num_dev_reg->objname, G_config->num_dev_reg->Num_Fun);
}
for (i=0; i<G_config->dis_dev_num; i++) {object_Display_Set(root, G_config->dis_dev_reg->objname, G_config->dis_dev_reg->Dis_Fun);
}
for (i=0; i<G_config->io_dev_reg_num; i++) {object_IO_Set(root, G_config->io_dev_reg->objname, G_config->io_dev_reg->IO_Fun);
}
} else if (uimethod == DDC_METHOD_GET) {object_get(sddc, uid, root, G_config->state_get_reg, G_config->state_get_reg_num);
} else {return SDDC_FALSE;}
return SDDC_TRUE;
}
库中还提供了一个被动上报音讯的接口,具体如下,留神输出参数的格局要符合规范(重点!敲黑板!
):
/*********************************************************************************************************
** 函数名称: object_report
** 性能形容: 封装给内部用户用的上报接口
** 输 入 : reportlist 上报的内容列表,格局为 {obj:"LED1","LED2","TMP"}
** 输 出 : 0: 解决失败, 1: 解决胜利.
** 全局变量:
** 调用模块: 无
*********************************************************************************************************/
int object_report(cJSON *reportlist)
{if (NULL == G_sddc) {return SDDC_FALSE;}
return object_get(G_sddc, NULL, reportlist, G_config->state_get_reg, G_config->state_get_reg_num);
}
能够应用这个函数疾速实现一个符合标准的被动上报音讯接口的输出参数:
/*
* 被动数据上报函数
*/
static void report_sensor()
{
int sensorValue = 0;
cJSON *value;
cJSON *root;
// char *msg;
value = cJSON_CreateArray();
root = cJSON_CreateObject();
sddc_return_if_fail(value);
sddc_return_if_fail(root);
// 按格局生成须要的参数
cJSON_AddItemToArray(value, cJSON_CreateString("上报数据 1")); // 这里的字符串要和零碎对象状态获取注册构造体里的对应
// cJSON_AddItemToArray(value, cJSON_CreateString("上报数据 2")); // 须要上报几个就增加几个
cJSON_AddItemToObject(root, "obj", value);
// 发送数据给 EdgerOS
// msg = cJSON_Print(root);
// printf("触发上报: %s\n",msg);
object_report(root);
cJSON_Delete(value);
cJSON_free(msg);
}
疾速接入应用 DEMO
接下来就教大家如何疾速应用这个 SDK 开发接入设施 (✪ω✪)。
首先要定义好设施实现 dev_info
的内容,再依据设施定义所须要的不同类型的对象,能够是一个设施只有一个对象,也能够是简单的一个设施对应多个对象,依据这些来实现各个类型对象的构建以及 set、get 函数注册。
/*********************************************************************************************************
以后设施的信息定义
*********************************************************************************************************/
DEV_INFO dev_info = {
.name = "InfraredSensor", // 设施名,你增加设施搜寻到的就是这个名字
.type = "device", // 设施类型,利用那边须要通过这个来辨别设施类型
.excl = SDDC_FALSE,
.desc = "Infrared sensor based on nodemcu",
.model = "1",
.vendor = "inspiration-desktop", // 属于你的名字
};
/*********************************************************************************************************
IO 设施对象设置函数与解决办法注册
*********************************************************************************************************/
IO_DEV_REGINFO io_dev[] = { // 注册 IO(string 类型) 音讯 set 处理函数
{"attr1", NULL},
{"attr2", NULL},
};
/*********************************************************************************************************
数字量设施对象函数与解决办法注册
*********************************************************************************************************/
NUM_DEV_REGINFO num_dev[] = { // 注册 数字量 (int,float 之类的) 音讯 set 处理函数
{"attr1", NULL},
{"attr2", NULL},
};
/*********************************************************************************************************
显示设施对象函数与解决办法注册
*********************************************************************************************************/
DIS_DEV_REGINFO dis_dev[] = { // 注册显示设施 ( 屏幕之类的) 音讯 set 处理函数
{"attr1", NULL},
{"attr2", NULL},
};
/*********************************************************************************************************
零碎对象状态获取注册
*********************************************************************************************************/
DEV_STATE_GET dev_state_get_reg[] = {{"attr1", DEV_IO_TYPE, gpio_dev_state_get}, // 注册 get 处理函数
{"attr2", DEV_IO_TYPE, gpio_dev_state_get}, // 注册 get 处理函数
};
/*********************************************************************************************************
零碎注册对象汇聚
*********************************************************************************************************/
SDDC_CONFIG_INFO sys_cfg = {
.token = "12345678",
.devinfo = &dev_info,
.io_dev_reg = io_dev,
.io_dev_reg_num = MS_ARRAY_SIZE(io_dev),
.num_dev_reg = num_dev,
.num_dev_reg_num = MS_ARRAY_SIZE(num_dev),
.state_get_reg = dev_state_get_reg,
.state_get_reg_num = MS_ARRAY_SIZE(dev_state_get_reg),
.dis_dev_reg = dis_dev,
.dis_dev_num = MS_ARRAY_SIZE(dis_dev),
};
至于相干的 set、get 函数以及初始化操作就须要依据不同的设施来实现不同的实现了,之后在主函数中将 sys_cfg 作为参数执行 sddc_lib_main 就能够启动 SDDC 并实现相干配置,下方是基于 FreeRTOS 的安信可平台上的主函数代码:
int app_main (int argc, char **argv)
{ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());
gpio_dev_init();
while (1) {sddc_lib_main(&sys_cfg);
}
return (0);
}
而对于 Arduino 平台,因为主函数构造不同分为 setup() 和 loop(),局部代码无奈在库中调用,具体代码如下:
void setup() {byte mac[6];
uart_dev_init();
// 启动 WiFi 并且连贯网络
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{delay(500);
Serial.print(".");
}
// 获取并打印 IP 地址
Serial.println("");
Serial.println("WiFi connected");
Serial.print("'ip :");
Serial.print(WiFi.localIP());
Serial.println("'to connect");
// 革除一下按键状态机的状态
button.reset();
// 创立按键扫描线程,长按 IO0 按键,松开后 ESP32 将会进入 SmartConfig 模式
sddc_printf("长按按键进入 Smartconfig...\n");
button.attachLongPressStop(esp_io0_key_task);
xTaskCreate(esp_tick_task, "button_tick", ESP_TASK_STACK_SIZE, NULL, ESP_TASK_PRIO, NULL);
// sddc 协定初始化
sddc_lib_main(&sys_cfg);
// 获取并打印网卡 mac 地址
WiFi.macAddress(mac);
sddc_printf("MAC addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
// 应用网卡 mac 地址设置设施惟一标识 UID
sddc_set_uid(G_sddc, mac);
}
void loop() {
// 运行 SDDC 协定循环
while (1)
{sddc_printf("SDDC running...\n");
sddc_run(G_sddc);
sddc_printf("SDDC quit!\n");
}
// 销毁 SDDC 协定
sddc_destroy(G_sddc);
}
本文仅集体学习应用,如有谬误,欢送斧正,(੭ ˙ᗜ˙)੭谢谢老板!