基于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_REGINFONUM_DEV_REGINFODIS_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 解析的更多相关文章

  1. 同人逼死官方系列!从 DDC 嗅探器到 sddc_sdk_lib 的数据解析

    从 DDC 嗅探器到 sddc_sdk_lib 的数据解析 之前的 DDC 协议介绍 主要讲了设备加入.退出以及维持设备状态,而 SDK框架 sddc_sdk_lib 解析 主要讲了 SDK 库的结构 ...

  2. dubbo基于tcp协议的RPC框架

    什么是 RPC 框架 谁能用通俗的语言解释一下什么是 RPC 框架? - 远程过程调用协议RPC(Remote Procedure Call Protocol) 首先了解什么叫RPC,为什么要RPC, ...

  3. 基于Django的Rest Framework框架的解析器

    本文目录 一 解析器的作用 二 全局使用解析器 三 局部使用解析器 四 源码分析 回到目录 一 解析器的作用 根据请求头 content-type 选择对应的解析器对请求体内容进行处理. 有appli ...

  4. 基于http协议实现RPC远程调用

    今天简单说一下基本Http协议来实现RPC框架~ 基于Http协议实现RPC框架: 优点: 1.简单.实用.开发方便 缺点: 1.性能不是很稳定,在海量数据时,完全顶不住,容易宕机 2.因为不是走的注 ...

  5. LoadRunner系列之—-04 录制基于https协议的脚本

    实际性能测试过程中,有些需录制脚本的页面或接口是基于https协议的,按原来方法录制脚本,录完了脚本是空的.为解决这个问题,第一步了解https协议的具体实现,这块网上资料很多,可参考页面下方参考资料 ...

  6. LoadRunner系列之—-02 基于webservice协议的接口测试(脚本实例)

    Loadrunner 基于webservice协议的接口压力测试(脚本实例) 接口功能如下:请求接口,报文只有一个参数为证件号码:返回报文中,有证件号码是否能查到对应数据,查到几条数据. 思路:请求w ...

  7. 基于MySQL协议的数据库中间层项目Atlas - 360团队

    一.简介 Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了 ...

  8. 基于Http协议订阅发布系统设计

      基于Http协议订阅发布系统设计 --物联网系统架构设计   1,订阅发布(subscriber-publisher)      订阅发布模式最典型的应用场景就是消息系统的设计.在消息系统的架构中 ...

  9. python 全栈开发,Day34(基于UDP协议的socket)

    昨日内容回顾 网络的基础概念arp协议 :通过ip地址找到mac地址五层模型 : 应用层 传输层 网络层 数据链路层 物理层tcp协议 : 可靠的 面向连接 全双工 三次握手 四次挥手udp协议 : ...

随机推荐

  1. AWK的内置变量

    ARGC: number (2) 在命令行提供的参数的个数,不包括命令awkARGIND: number (0) 当前文件中正在处理的 ARGV 数组的索引值. 文件的位置,从1开始计数.一个文件处在 ...

  2. 10个实战及面试常用Linux Shell脚本编写

    来自:http://blog.51cto.com/lizhenliang/1929044 注意事项 1)开头加解释器:#!/bin/bash 2)语法缩进,使用四个空格:多加注释说明. 3)命名建议规 ...

  3. JDK源码阅读:Object类阅读笔记

    Object 1. @HotSpotIntrinsicCandidate @HotSpotIntrinsicCandidate public final native Class<?> g ...

  4. eclipse安装配置

    安装eclipse,并运行了第一个Hello World!

  5. AT4144-[ARC098D]Donation【Kruskal重构树,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/AT4144 题目大意 \(n\)个点\(m\)条边的一张无向联通图,每个点有两个值\(a_i,b_i\).表示经过该 ...

  6. 一凡老师亲录视频,Python从零基础到高级进阶带你飞

    如需Q群交流 群:893694563 不定时更新2-3节视频 零基础学生请点击 Python基础入门视频 如果你刚初入测试行业 如果你刚转入到测试行业 如果你想学习Python,学习自动化,搭建自动化 ...

  7. 你说要你想玩爬虫,但你说你不懂Python正则表达式,我信你个鬼,那你还不来看看?

    前言 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数. re.mat ...

  8. android 使用SQLite的基本操作

    Android操作数据库SQLite使用sql语句基本操作 1:自定义自己的SQLiteOpenHelper public class DBHelper extends SQLiteOpenHelpe ...

  9. A Three-Stage Self-Training Framework for Semi-Supervised Semantic Segmentation

    论文阅读笔记: A Three-Stage Self-Training Framework for Semi-Supervised Semantic Segmentation 基本信息 \1.标题:A ...

  10. Java实现红黑树(平衡二叉树)

    前言 在实现红黑树之前,我们先来了解一下符号表. 符号表的描述借鉴了Algorithms第四版,详情在:https://algs4.cs.princeton.edu/home/ 符号表有时候被称为字典 ...