同人逼死官方系列!基于sddc 协议的SDK框架 sddc_sdk_lib 解析
基于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);
}
本文仅个人学习使用,如有错误,欢迎指正, ( ੭ ˙ᗜ˙ )੭谢谢老板!
同人逼死官方系列!基于sddc 协议的SDK框架 sddc_sdk_lib 解析的更多相关文章
- 同人逼死官方系列!从 DDC 嗅探器到 sddc_sdk_lib 的数据解析
从 DDC 嗅探器到 sddc_sdk_lib 的数据解析 之前的 DDC 协议介绍 主要讲了设备加入.退出以及维持设备状态,而 SDK框架 sddc_sdk_lib 解析 主要讲了 SDK 库的结构 ...
- dubbo基于tcp协议的RPC框架
什么是 RPC 框架 谁能用通俗的语言解释一下什么是 RPC 框架? - 远程过程调用协议RPC(Remote Procedure Call Protocol) 首先了解什么叫RPC,为什么要RPC, ...
- 基于Django的Rest Framework框架的解析器
本文目录 一 解析器的作用 二 全局使用解析器 三 局部使用解析器 四 源码分析 回到目录 一 解析器的作用 根据请求头 content-type 选择对应的解析器对请求体内容进行处理. 有appli ...
- 基于http协议实现RPC远程调用
今天简单说一下基本Http协议来实现RPC框架~ 基于Http协议实现RPC框架: 优点: 1.简单.实用.开发方便 缺点: 1.性能不是很稳定,在海量数据时,完全顶不住,容易宕机 2.因为不是走的注 ...
- LoadRunner系列之—-04 录制基于https协议的脚本
实际性能测试过程中,有些需录制脚本的页面或接口是基于https协议的,按原来方法录制脚本,录完了脚本是空的.为解决这个问题,第一步了解https协议的具体实现,这块网上资料很多,可参考页面下方参考资料 ...
- LoadRunner系列之—-02 基于webservice协议的接口测试(脚本实例)
Loadrunner 基于webservice协议的接口压力测试(脚本实例) 接口功能如下:请求接口,报文只有一个参数为证件号码:返回报文中,有证件号码是否能查到对应数据,查到几条数据. 思路:请求w ...
- 基于MySQL协议的数据库中间层项目Atlas - 360团队
一.简介 Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了 ...
- 基于Http协议订阅发布系统设计
基于Http协议订阅发布系统设计 --物联网系统架构设计 1,订阅发布(subscriber-publisher) 订阅发布模式最典型的应用场景就是消息系统的设计.在消息系统的架构中 ...
- python 全栈开发,Day34(基于UDP协议的socket)
昨日内容回顾 网络的基础概念arp协议 :通过ip地址找到mac地址五层模型 : 应用层 传输层 网络层 数据链路层 物理层tcp协议 : 可靠的 面向连接 全双工 三次握手 四次挥手udp协议 : ...
随机推荐
- MySQL-技术专题-MySQL主从架构以及[半同步机制]模式大全
MySQL的主从复制 一般在大规模的项目上,都是使用MySQL的复制功能来创建MySQL的主从集群的. 主要是可以通过为数据库服务器配置一个或多个备库的方式来进行数据同步. 复制的功能不仅有利于构建高 ...
- JavaScript进行表单提交
表单结构,设置form表单的id属性,method="post/get","action"要跳转的页面(jsp或servlet) <form name=& ...
- Windows环境下实现WireShark抓取HTTPS
https 加密传输,Wireshark 没有设置的情况下是没有办法抓到包的 https 的数据包. 设置系统环境变量(SSLKEYLOGFILE) WireShark 设置 SSL 选项 参考文章: ...
- JScript.net
参考网址一.JScript帮助指南 http://doc.51windows.net/jscript5/?url=/jscript5/dir.htm 参考网址二.以下网址列出的类,可以尝试一下,会有意 ...
- Python创建Excel表格,Word并写入数据
from tkinter import Tk from time import sleep from tkinter.messagebox import showwarning import win3 ...
- linux mint 18.1 安装备忘录
本次全新安装mint18.1,遇到一些问题,全部解决,怕日后忘记,再捣鼓琢磨,浪费时间,特记录在此: 一.楷体字体问题 安装完后的mint18.1,显示都是楷体,经请教薄荷论坛高手,可用以下办法解决: ...
- P4606-[SDOI2018]战略游戏【圆方树,虚树】
正题 题目链接:https://www.luogu.com.cn/problem/P4606 题目大意 给出\(n\)个点\(m\)条边的一张图,\(q\)次询问给出一个点集,询问有多少个点割掉后可以 ...
- 如何借助 JuiceFS 为 AI 模型训练提速 7 倍
背景 海量且优质的数据集是一个好的 AI 模型的基石之一,如何存储.管理这些数据集,以及在模型训练时提升 I/O 效率一直都是 AI 平台工程师和算法科学家特别关注的事情.不论是单机训练还是分布式训练 ...
- 智汀家庭云-开发指南Golang:设备插件开发
设备插件模块 开发前先阅读插件设计概要:智汀家庭云-开发指南Golang: 插件模块 使用 plugin-sdk 可以忽略不重要的逻辑,快速实现插件 插件实现 获取sdk go get github. ...
- SpringCloud升级之路2020.0.x版-26.OpenFeign的组件
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 首先,我们给出官方文档中的组件结构图: 官方文档中的组件,是以实现功能为维度的,我们这里是 ...