网站登记备案查询,线下营销活动有哪些,软件下载大全免费,新莱芜客户端系列文章目录
星闪开发之Server-Client 指令交互控制红灯亮灭的全流程解析#xff08;SLE_LED详解#xff09; 文章目录 系列文章目录前言一、项目地址二、客户端1.SLE_LED_Client\inc\SLE_LED_Client.h2.SLE_LED_Client\src\SLE_LED_Client.c头文件与依赖管理宏定义与全局变…系列文章目录
星闪开发之Server-Client 指令交互控制红灯亮灭的全流程解析SLE_LED详解 文章目录 系列文章目录前言一、项目地址二、客户端1.SLE_LED_Client\inc\SLE_LED_Client.h2.SLE_LED_Client\src\SLE_LED_Client.c头文件与依赖管理宏定义与全局变量LED 控制功能回调函数扫描使能开始停止结果设备扫描与连接流程服务发现与通信协议任务启动与系统集成客户端总结 三、服务端1.SLE_LED_Server\inc\SLE_LED_Server.h2.SLE_LED_Server\inc\SLE_LED_Server_adv.h广播数据结构设计广播信道配置广播数据类型枚举广播初始化接口 3.SLE_LED_Server\src\SLE_LED_Server.cLED控制任务服务器初始化流程服务与属性创建客户端交互处理通知发送机制连接状态管理 4.SLE_LED_Server\src\SLE_LED_Server_adv.c广播数据配置扫描响应数据配置设备地址与名称设置广播参数初始化回调函数与广播控制 四、从代码库拿的代码跑不通解决总结 前言
之前有粉丝想要计蒙写一篇关于sle_led样例的详细解析文章于是有了这篇文章如果拿到代码库中的项目跑不通请直接跳转至第四部分。 一、项目地址
基于海思WS63项目库中的sle_led项目
二、客户端
客户端中共两个文件。分别是SLE_LED_Client.hSLE_LED_Client.c
1.SLE_LED_Client\inc\SLE_LED_Client.h
/*** defgroup* ingroup* {*/
// LED_MODULE LED控制模块
#ifndef SLE_LED_CLIENT_H //头文件保护宏开始防止重复包含6。SLE_LED_CLIENT_H是自定义的宏名称通常与文件名对应。
#define SLE_LED_CLIENT_H //定义上述宏标记该头文件已被包含#endif //头文件保护宏结束标记这段代码是一个 LED 控制模块的头文件框架采用了标准的头文件保护机制来防止重复包含。 头文件保护宏的作用头文件保护宏也称为 Include Guard是 C/C 中防止头文件被重复包含的标准技术。当多个源文件包含同一个头文件时可能会导致函数或变量的重复定义错误。使用保护宏可以确保头文件内容只被编译一次。 2.SLE_LED_Client\src\SLE_LED_Client.c
实现了一个基于 SLE协议的 LED 客户端控制系统主要功能是通过 SLE 协议与远程设备通信并控制本地 LED 灯。整个系统采用模块化设计包含设备扫描、连接管理、服务发现和 LED 控制等核心模块。
代码特点 安全机制使用memcpy_s等安全函数防止缓冲区溢出 资源管理动态分配内存osal_vmalloc并及时释放osal_vfree 硬件抽象通过pinctrl.h和gpio.h封装底层硬件操作 协议栈集成深度集成 SLE 协议栈处理扫描、连接、服务发现全流程 调试支持通过PRINT宏输出详细日志便于问题定位
头文件与依赖管理
#include securec.h // 安全函数库如memcpy_s
#include sle_device_discovery.h // SLE设备发现相关API
#include sle_connection_manager.h// SLE连接管理
#include sle_ssap_client.h // SSAP服务发现协议客户端
#include ../inc/SLE_LED_Client.h // 自定义LED客户端头文件
#include soc_osal.h // 操作系统抽象层如线程、锁
#include app_init.h // 应用初始化
#include common_def.h // 通用定义如错误码
#include debug_print.h // 调试打印
#include pinctrl.h // 引脚控制
#include gpio.h // GPIO操作依赖多个底层库涵盖安全操作、协议栈、硬件控制和系统接口,自定义头文件SLE_LED_Client.h用于声明 LED 控制相关接口。
宏定义与全局变量
//宏定义
#define SLE_MTU_SIZE_DEFAULT 300 // 默认MTU最大传输单元大小
#define SLE_SEEK_INTERVAL_DEFAULT 100 // 扫描间隔单位可能是ms
#define SLE_SEEK_WINDOW_DEFAULT 100 // 扫描窗口
#define UUID_16BIT_LEN 2 // 16位UUID长度
#define UUID_128BIT_LEN 16 // 128位UUID长度//全局变量
static sle_announce_seek_callbacks_t g_seek_cbk {0};//扫描回调函数组static sle_connection_callbacks_t g_connect_cbk {0};//连接回调函数组static ssapc_callbacks_t g_ssapc_cbk {0};//SSAP回调函数组static sle_addr_t g_remote_addr {0};//远程设备地址宏定义配置了通信参数MTU、扫描间隔等全局变量存储协议回调函数和连接状态便于跨函数访问。 LED 控制功能
//LED控制函数
static void example_turn_onoff_led(pin_t pin, gpio_level_t level)
{uapi_pin_set_mode(pin, HAL_PIO_FUNC_GPIO);// 配置引脚为GPIO模式uapi_gpio_set_dir(pin, GPIO_DIRECTION_OUTPUT);// 设置为输出模式uapi_gpio_set_val(pin, level);// 设置电平高/低
}
//LED通知回调
static void example_led_notification_cbk(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data)
{// 解析数据并控制LED如RLED_ON控制红色LED// 支持RLED_ON, RLED_OFF, YLED_ON, YLED_OFF, GLED_ON, GLED_OFF命令if (data-data_len strlen(RLED_ON) data-data[0] R data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] N) {example_turn_onoff_led(GPIO_07, GPIO_LEVEL_HIGH);}if (data-data_len strlen(RLED_OFF) data-data[0] R data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] F data-data[7] F) {example_turn_onoff_led(GPIO_07, GPIO_LEVEL_LOW);}if (data-data_len strlen(YLED_ON) data-data[0] Y data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] N) {example_turn_onoff_led(GPIO_10, GPIO_LEVEL_HIGH);}if (data-data_len strlen(YLED_OFF) data-data[0] Y data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] F data-data[7] F) {example_turn_onoff_led(GPIO_10, GPIO_LEVEL_LOW);}if (data-data_len strlen(GLED_ON) data-data[0] G data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] N) {example_turn_onoff_led(GPIO_11, GPIO_LEVEL_HIGH);}if (data-data_len strlen(GLED_OFF) data-data[0] G data-data[1] L data-data[2] E data-data[3] D data-data[4] _ data-data[5] O data-data[6] F data-data[7] F) {example_turn_onoff_led(GPIO_11, GPIO_LEVEL_LOW);}//将LED状态写回服务器/* 将本端(Cient)的LED等状态, 通过写请求发送给对端(Server) */ssapc_write_param_t param {0};param.handle g_find_service_result.start_hdl;param.type SSAP_PROPERTY_TYPE_VALUE;param.data_len data-data_len;param.data osal_vmalloc(param.data_len);if (param.data NULL) {PRINT([SLE Client] write req mem fail\r\n);return;}if (memcpy_s(param.data, param.data_len, data, data-data_len) ! EOK) {PRINT([SLE Client] write req memcpy fail\r\n);osal_vfree(param.data);return;}
// ssapc_write_req(client_id, conn_id, param); 发送写请求if (ssapc_write_req(client_id, conn_id, param) ! ERRCODE_SUCC) {PRINT([SLE Client] write req fail\r\n);osal_vfree(param.data);return;}osal_vfree(param.data);return;
}通过 GPIO 接口直接控制硬件引脚实现 LED 开关。 支持三种颜色 LED红、黄、绿分别对应 GPIO_07、GPIO_10、GPIO_11。 接收到远程通知后不仅控制本地 LED还会将状态回传给服务器。
回调函数扫描使能开始停止结果
//扫描使能回调
static void example_sle_enable_cbk(errcode_t status)
{if (status ERRCODE_SUCC) {example_sle_start_scan();}
}
//扫描开始回调
static void example_sle_seek_enable_cbk(errcode_t status)
{if (status ERRCODE_SUCC) {return;}
}
//扫描停止回调
static void example_sle_seek_disable_cbk(errcode_t status)
{if (status ERRCODE_SUCC) {sle_connect_remote_device(g_remote_addr);// 连接设备}
}
//定义了一个静态全局数组 g_sle_expected_addr用于存储预期的SLE设备地址
static uint8_t g_sle_expected_addr[SLE_ADDR_LEN] {0x04, 0x01, 0x06, 0x08, 0x06, 0x03};
// static uint8_t g_sle_expected_addr[SLE_ADDR_LEN] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};//扫描结果回调找到特定设备后停止扫描
//触发扫描的调用流程--扫描结果处理 如果找到目标设备地址匹配则停止扫描。
static void example_sle_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data)
{if (seek_result_data NULL) {//调试输出PRINT([SLE Client] seek result seek_result_data is NULL\r\n);return;}if (memcmp((void *)seek_result_data-addr.addr, (void *)g_sle_expected_addr, SLE_ADDR_LEN) 0) {PRINT([SLE Client] seek result find expected addr:%02x***%02x%02x\r\n, seek_result_data-addr.addr[0],seek_result_data-addr.addr[4], seek_result_data-addr.addr[5]);(void)memcpy_s(g_remote_addr, sizeof(sle_addr_t), seek_result_data-addr, sizeof(sle_addr_t));sle_stop_seek();// 停止扫描}
}设备扫描与连接流程
// 扫描参数配置与启动
static void example_sle_start_scan(void) {sle_seek_param_t param;param.seek_interval[0] SLE_SEEK_INTERVAL_DEFAULT;param.seek_window[0] SLE_SEEK_WINDOW_DEFAULT;sle_set_seek_param(param);sle_start_seek(); // 启动扫描
}// 扫描结果处理匹配目标设备地址
static void example_sle_seek_result_info_cbk(...) {if (memcmp(发现地址, 预期地址, SLE_ADDR_LEN) 0) {memcpy_s(保存远程地址, 发现地址);sle_stop_seek(); // 找到目标后停止扫描}
}// 连接状态处理
static void example_sle_connect_state_changed_cbk(...) {if (conn_state 已连接) {if (未配对) sle_pair_remote_device(发起配对);g_conn_id conn_id; // 保存连接ID}
}扫描阶段按预设参数间隔、窗口搜索设备匹配到预设地址g_sle_expected_addr后停止。 连接阶段建立连接后自动发起配对并保存连接 ID 用于后续通信。
服务发现与通信协议
// SSAP协议交换信息回调
static void example_sle_exchange_info_cbk(...) {if (状态成功) {ssapc_find_structure_param_t find_param;find_param.type SSAP_FIND_TYPE_PRIMARY_SERVICE;ssapc_find_structure(查找主服务);}
}// 服务发现结果处理
static void example_sle_find_structure_cbk(...) {if (状态成功) {g_find_service_result.start_hdl service-start_hdl;memcpy_s(保存服务UUID, service-uuid);}
}// 处理远程通知核心LED控制入口
static void example_sle_notification_cbk(...) {example_led_notification_cbk(client_id, conn_id, data); // 调用LED控制函数
}通过 SSAP 协议发现远程服务获取服务句柄和 UUID 注册通知回调example_sle_notification_cbk当收到远程命令时触发 LED 控制
任务启动与系统集成
// 主任务函数
static int example_sle_led_client_task(...) {osal_msleep(5000); // 等待SLE初始化// 注册各类回调函数example_sle_seek_cbk_register();example_sle_connect_cbk_register();example_sle_ssapc_cbk_register();// 启用SLE功能if (enable_sle() ! 成功) return -1;return 0;
}// 任务创建入口
static void example_sle_led_client_entry(void) {osal_task *task_handle osal_kthread_create(example_sle_led_client_task, SLELedClientTask, SLE_LED_CLI_STACK_SIZE);if (task_handle) {osal_kthread_set_priority(task_handle, SLE_LED_CLI_TASK_PRIO);osal_kfree(task_handle);}
}app_run(example_sle_led_client_entry); // 启动应用客户端总结
核心工作流程
系统启动创建 SLE LED 客户端任务等待协议栈初始化注册回调设置扫描、连接、SSAP 协议的各类回调函数设备扫描按预设参数搜索设备匹配到目标地址后停止建立连接与目标设备配对获取连接 ID服务发现通过 SSAP协议发现远程服务获取操作句柄命令交互接收远程通知如 “RLED_ON”控制本地 LED 并回传状态
三、服务端
1.SLE_LED_Server\inc\SLE_LED_Server.h
SLE协议栈的 LED 服务器头文件框架主要定义了服务相关的 UUID 和基础结构,使用标准的头文件保护宏防止重复包含。
//使用 #ifndef、#define 和 #endif 防止头文件被重复包含避免编译错误
/*** defgroup* ingroup* {*/
#ifndef SLE_LED_SERVER_H
#define SLE_LED_SERVER_H
//引入了 sle_ssap_server.h可能是SLE协议栈中与SSAP服务发现协议服务器相关的定义。
#include sle_ssap_server.h//定义了三个UUID通用唯一标识符用于标识服务器中的服务、通知报告和属性。
/* Service UUID */
#define SLE_UUID_SERVER_SERVICE 0xABCD //标识LED服务器提供的服务。客户端通过此UUID发现服务器。/* Notify Repoert UUID */
#define SLE_UUID_SERVER_NTF_REPORT 0x1122 //标识服务器发送的通知或报告。客户端可以订阅此UUID以接收状态更新如LED开关状态。/* Property UUID */
#define SLE_UUID_SERVER_PROPERTY 0x3344 //标识服务器中的属性。客户端可以读取或写入此UUID对应的属性如控制LED开关。#endif//服务发现
//客户端通过 SLE_UUID_SERVER_SERVICE 发现服务器提供的LED控制服务。
//通知订阅
//客户端订阅 SLE_UUID_SERVER_NTF_REPORT接收服务器推送的LED状态变更通知。
//属性操作
//客户端通过 SLE_UUID_SERVER_PROPERTY 读取或设置LED状态如发送RLED_ON命令。服务 UUID (0xABCD)标识 LED 服务器提供的整体服务客户端通过此 UUID 发现服务器 通知报告 UUID (0x1122)用于服务器主动推送通知如 LED 状态变化 属性 UUID (0x3344)用于客户端读写 LED 控制属性如开关状态
2.SLE_LED_Server\inc\SLE_LED_Server_adv.h
定义了 SLE 协议中 LED 服务器的广播功能包含数据结构、信道配置和初始化接口。
广播数据结构设计
//广播通用数据结构
struct sle_adv_common_value {uint8_t length; // 数据长度uint8_t type; // 数据类型uint8_t value; // 数据值
};// 用途表示广播数据的基本结构包含长度、类型和值。
// 字段解析
// length广播数据的长度。
// type广播数据的类型如设备名称、服务UUID等。
// value广播数据的具体内容。广播信道配置
//广播信道映射枚举
typedef enum {SLE_ADV_CHANNEL_MAP_77 0x01, // 信道77SLE_ADV_CHANNEL_MAP_78 0x02, // 信道78SLE_ADV_CHANNEL_MAP_79 0x04, // 信道79SLE_ADV_CHANNEL_MAP_DEFAULT 0x07 // 默认信道77、78、79
} sle_adv_channel_map;
// 用途定义广播使用的信道映射。
// 字段解析
// 每个枚举值对应一个信道77、78、79或默认信道组合。广播数据类型枚举
//广播数据类型枚举
typedef enum {SLE_ADV_DATA_TYPE_DISCOVERY_LEVEL 0x01, /*! 发现等级 */SLE_ADV_DATA_TYPE_ACCESS_MODE 0x02, /*! 接入层能力 */SLE_ADV_DATA_TYPE_SERVICE_DATA_16BIT_UUID 0x03, /*! 标准服务数据信息 */SLE_ADV_DATA_TYPE_SERVICE_DATA_128BIT_UUID 0x04, /*! 自定义服务数据信息 */SLE_ADV_DATA_TYPE_COMPLETE_LIST_OF_16BIT_SERVICE_UUIDS 0x05, /*! 完整标准服务标识列表 */SLE_ADV_DATA_TYPE_COMPLETE_LIST_OF_128BIT_SERVICE_UUIDS 0x06, /*! 完整自定义服务标识列表 */SLE_ADV_DATA_TYPE_INCOMPLETE_LIST_OF_16BIT_SERVICE_UUIDS 0x07, /*! 部分标准服务标识列表 */SLE_ADV_DATA_TYPE_INCOMPLETE_LIST_OF_128BIT_SERVICE_UUIDS 0x08, /*! 部分自定义服务标识列表 */SLE_ADV_DATA_TYPE_SERVICE_STRUCTURE_HASH_VALUE 0x09, /*! 服务结构散列值 */SLE_ADV_DATA_TYPE_SHORTENED_LOCAL_NAME 0x0A, /*! 设备缩写本地名称 */SLE_ADV_DATA_TYPE_COMPLETE_LOCAL_NAME 0x0B, /*! 设备完整本地名称 */SLE_ADV_DATA_TYPE_TX_POWER_LEVEL 0x0C, /*! 广播发送功率 */SLE_ADV_DATA_TYPE_SLB_COMMUNICATION_DOMAIN 0x0D, /*! SLB通信域域名 */SLE_ADV_DATA_TYPE_SLB_MEDIA_ACCESS_LAYER_ID 0x0E, /*! SLB媒体接入层标识 */SLE_ADV_DATA_TYPE_EXTENDED 0xFE, /*! 数据类型扩展 */SLE_ADV_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /*! 厂商自定义信息 */
} sle_adv_data_type;// 用途定义广播数据的类型涵盖标准服务、设备名称、功率等级等。
// 字段解析
// 包括发现等级、服务UUID、设备名称、功率等级等广播数据类型。
// 0xFF 保留给厂商自定义数据。广播初始化接口
//广播初始化函数
errcode_t example_sle_server_adv_init(void);3.SLE_LED_Server\src\SLE_LED_Server.c
实现了一个基于 SLE协议的 LED 服务器应用主要用于控制不同类型 LED 的开关状态。该应用支持设备发现、连接建立、服务发布以及 LED 状态的远程控制适用于物联网设备中的 LED 管理场景。 关键数据结构
枚举类型example_control_led_type_t定义LED控制操作开关主板LED、灯板RGB灯等全局变量存储服务句柄、连接ID、属性句柄等关键信息UUID定义使用16位UUID标识服务和属性
核心模块划分
SLE协议栈接口通过sle_common.h、sle_ssap_server.h等头文件与SLE协议栈交互任务管理使用CMSIS-RTOS v2进行多任务管理创建LED控制任务和服务器主任务LED控制逻辑定义多种LED操作类型并实现周期性控制逻辑服务与属性管理创建SLE服务和属性处理读写请求连接管理处理设备连接状态变化和配对完成事件
LED控制任务
static int example_led_control_task(const char *arg)
{example_control_led_type_t last_led_operation EXAMPLE_CONTORL_LED_LEDBOARD_GLED_OFF;PRINT([SLE Server] start led control task\r\n);while (1){(void)osal_msleep(500); if (last_led_operation EXAMPLE_CONTORL_LED_LEDBOARD_GLED_OFF) {// 发送打开红色LED命令uint8_t write_req_data[] {R, L, E, D, _, O, N};example_sle_server_send_notify_by_handle(write_req_data, sizeof(write_req_data));last_led_operation EXAMPLE_CONTORL_LED_LEDBOARD_RLED_ON;} // 其他LED状态切换逻辑省略部分代码}return 0;
}周期性控制每500ms切换一次LED状态按红→黄→绿的顺序循环控制命令发送通过example_sle_server_send_notify_by_handle发送通知到客户端状态管理使用枚举变量last_led_operation跟踪上一次操作状态
服务器初始化流程
static int example_sle_led_server_task(const char *arg)
{(void)osal_msleep(5000); // 等待SLE初始化// 使能SLE协议栈if (enable_sle() ! ERRCODE_SUCC) return -1;// 注册连接管理回调if (example_sle_conn_register_cbks() ! ERRCODE_SUCC) return -1;// 注册SSAP服务器回调if (example_sle_ssaps_register_cbks() ! ERRCODE_SUCC) return -1;// 添加服务和属性if (example_sle_server_add() ! ERRCODE_SUCC) return -1;// 启动设备广播if (example_sle_server_adv_init() ! ERRCODE_SUCC) return -1;return 0;
}初始化顺序延时等待→使能SLE→注册回调→创建服务→启动广播关键函数 enable_sle()初始化SLE协议栈example_sle_server_add()创建服务和属性example_sle_server_adv_init()启动设备发现广播
服务与属性创建
static errcode_t example_sle_server_add(void)
{// 注册服务器ssaps_register_server(app_uuid, g_server_id);// 添加服务if (example_sle_server_service_add() ! ERRCODE_SUCC) return ERRCODE_FAIL;// 添加属性if (example_sle_server_property_add() ! ERRCODE_SUCC) return ERRCODE_FAIL;// 启动服务return ssaps_start_service(g_server_id, g_service_handle);
}UUID设置使用16位UUID标识服务SLE_UUID_SERVER_SERVICE和属性SLE_UUID_SERVER_PROPERTY属性权限设置为可读可写SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE描述符添加为属性添加描述符定义通知操作权限
客户端交互处理
static void example_ssaps_write_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_write_cb_t *write_cb_para, errcode_t status)
{if (status ERRCODE_SUCC) {example_print_led_state(write_cb_para);}
}static void example_print_led_state(ssaps_req_write_cb_t *write_cb_para)
{// 解析LED_ON和LED_OFF命令并打印状态if (write_cb_para-length strlen(LED_ON) memcmp(write_cb_para-value, LED_ON, 6) 0) {PRINT([SLE Server] client main board led is on.\r\n);}// 其他命令解析逻辑省略
}写请求处理接收客户端发送的LED控制命令命令解析通过字符串匹配识别LED_ON、LED_OFF等命令状态反馈通过PRINT函数输出LED状态到调试日志
通知发送机制
static errcode_t example_sle_server_send_notify_by_handle(const uint8_t *data, uint8_t len)
{ssaps_ntf_ind_t param {0};param.handle g_property_handle;param.value osal_vmalloc(len);param.value_len len;// 内存拷贝if (memcpy_s(param.value, len, data, len) ! EOK) return ERRCODE_MEMCPY;// 发送通知if (ssaps_notify_indicate(g_server_id, g_conn_id, param) ! ERRCODE_SUCC) {osal_vfree(param.value);return ERRCODE_FAIL;}osal_vfree(param.value);return ERRCODE_SUCC;
}通知结构使用ssaps_ntf_ind_t结构封装通知数据内存管理动态分配内存存储通知数据发送后释放协议接口通过ssaps_notify_indicate函数发送通知到客户端
连接状态管理
static void example_sle_connect_state_changed_cbk(uint16_t conn_id,const sle_addr_t *addr,sle_acb_state_t conn_state,sle_pair_state_t pair_state,sle_disc_reason_t disc_reason)
{PRINT([SLE Server] connect state changed conn_id:0x%02x, conn_state:0x%x\r\n, conn_id, conn_state);g_conn_id conn_id;
}static void example_sle_pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status)
{PRINT([SLE Server] pair complete conn_id:0x%02x, status:0x%x\r\n, conn_id, status);if (status ERRCODE_SUCC) {example_led_control_entry(); // 配对成功后启动LED控制任务}
}状态回调监听连接状态变化和配对完成事件任务启动配对成功后启动LED控制任务连接ID管理使用全局变量g_conn_id存储当前连接ID
4.SLE_LED_Server\src\SLE_LED_Server_adv.c
实现了SLE的广播功能主要用于设备发现和连接建立。通过配置广播参数、设置广播数据和扫描响应数据使服务器能够在网络中被其他设备发现并支持连接请求。代码包含地址设置、名称配置、广播参数初始化及回调函数注册等完整流程。
广播数据配置
// 设置设备名称到广播数据
static uint16_t example_sle_set_adv_local_name(uint8_t *adv_data, uint16_t max_len) {uint8_t local_name_len strlen((char *)sle_local_name);adv_data[0] local_name_len 1; // 长度字段含类型字节adv_data[1] SLE_ADV_DATA_TYPE_COMPLETE_LOCAL_NAME; // 数据类型memcpy_s(adv_data[2], max_len - 2, sle_local_name, local_name_len);return local_name_len 2;
}// 配置广播数据发现等级、接入模式
static uint16_t example_sle_set_adv_data(uint8_t *adv_data) {// 发现等级配置struct sle_adv_common_value adv_disc_level {.length sizeof(struct sle_adv_common_value) - 1,.type SLE_ADV_DATA_TYPE_DISCOVERY_LEVEL,.value SLE_ANNOUNCE_LEVEL_NORMAL};memcpy_s(adv_data, SLE_ADV_DATA_LEN_MAX, adv_disc_level, sizeof(adv_disc_level));// 接入模式配置struct sle_adv_common_value adv_access_mode {.length sizeof(struct sle_adv_common_value) - 1,.type SLE_ADV_DATA_TYPE_ACCESS_MODE,.value 0};memcpy_s(adv_data[sizeof(adv_disc_level)], SLE_ADV_DATA_LEN_MAX - sizeof(adv_disc_level), adv_access_mode, sizeof(adv_access_mode));return sizeof(adv_disc_level) sizeof(adv_access_mode);
}数据结构使用struct sle_adv_common_value定义广播数据项包含长度、类型和值名称设置遵循广播数据格式长度类型内容名称为SLE_LED_SERVER发现等级设置为SLE_ANNOUNCE_LEVEL_NORMAL普通发现等级接入模式值为0具体含义由协议定义
扫描响应数据配置
// 配置扫描响应数据功率等级、设备名称
static uint16_t example_sle_set_scan_response_data(uint8_t *scan_rsp_data) {uint16_t idx 0;// 发送功率配置struct sle_adv_common_value tx_power_level {.length sizeof(struct sle_adv_common_value) - 1,.type SLE_ADV_DATA_TYPE_TX_POWER_LEVEL,.value SLE_ADV_TX_POWER // 功率值10};memcpy_s(scan_rsp_data, SLE_ADV_DATA_LEN_MAX, tx_power_level, sizeof(tx_power_level));idx sizeof(tx_power_level);// 设备名称配置复用广播数据中的名称设置函数idx example_sle_set_adv_local_name(scan_rsp_data[idx], SLE_ADV_DATA_LEN_MAX - idx);return idx;
}扫描响应作用当设备被扫描时返回包含功率和名称的响应数据功率等级设置为SLE_ADV_TX_POWER10影响信号覆盖范围数据复用扫描响应中的名称设置复用广播数据的名称配置函数
设备地址与名称设置
// 本地地址设置固定地址0x04, 0x01, 0x06, 0x08, 0x06, 0x03
static void example_sle_set_addr(void) {uint8_t g_sle_local_addr[SLE_ADDR_LEN] {0x04, 0x01, 0x06, 0x08, 0x06, 0x03};sle_addr_t sle_addr {0};sle_addr.type 0;memcpy_s(sle_addr.addr, SLE_ADDR_LEN, g_sle_local_addr, SLE_ADDR_LEN);sle_set_local_addr(sle_addr);
}// 本地名称设置sle_led_server
static void example_sle_set_name(void) {uint8_t g_local_device_name[] {s, l, e, _, l, e, d, _, s, e, r, v, e, r};sle_set_local_name(g_local_device_name, sizeof(g_local_device_name));
}地址格式6字节固定地址可能为厂商自定义格式名称规范使用小写字母和下划线符合设备命名惯例协议接口通过sle_set_local_addr和sle_set_local_name设置基础信息
广播参数初始化
// 设置广播参数间隔、超时等
static errcode_t example_sle_set_default_announce_param(void) {sle_announce_param_t param {.announce_mode SLE_ANNOUNCE_MODE_CONNECTABLE_SCANABLE, // 可连接可扫描模式.announce_handle SLE_ADV_HANDLE_DEFAULT, // 广播句柄.announce_gt_role SLE_ANNOUNCE_ROLE_T_CAN_NEGO, // 角色可协商.announce_level SLE_ANNOUNCE_LEVEL_NORMAL, // 普通广播等级.announce_channel_map SLE_ADV_CHANNEL_MAP_DEFAULT, // 默认信道映射.announce_interval_min SLE_ADV_INTERVAL_MIN_DEFAULT, // 最小广播间隔25ms.announce_interval_max SLE_ADV_INTERVAL_MAX_DEFAULT, // 最大广播间隔25ms.conn_interval_min SLE_CONN_INTV_MIN_DEFAULT, // 最小连接间隔12.5ms.conn_interval_max SLE_CONN_INTV_MAX_DEFAULT, // 最大连接间隔12.5ms.conn_max_latency SLE_CONN_MAX_LATENCY, // 最大连接延迟4990ms.conn_supervision_timeout SLE_CONN_SUPERVISION_TIMEOUT_DEFAULT // 超时时间5000ms};memcpy_s(param.own_addr.addr, SLE_ADDR_LEN, g_sle_local_addr, SLE_ADDR_LEN);return sle_set_announce_param(param.announce_handle, param);
}广播模式SLE_ANNOUNCE_MODE_CONNECTABLE_SCANABLE表示支持连接和扫描间隔配置广播间隔固定为25ms连接间隔固定为12.5ms超时机制连接监控超时5000ms超过则断开连接信道映射使用默认信道适应标准网络环境
回调函数与广播控制
// 广播状态回调函数
void example_sle_announce_enable_cbk(uint32_t announce_id, errcode_t status) {PRINT([SLE Adv] 广播启用ID:%02x状态:%02x\r\n, announce_id, status);
}void example_sle_announce_disable_cbk(uint32_t announce_id, errcode_t status) {PRINT([SLE Adv] 广播禁用ID:%02x状态:%02x\r\n, announce_id, status);
}// 注册回调函数
void example_sle_announce_register_cbks(void) {sle_announce_seek_callbacks_t seek_cbks {.announce_enable_cb example_sle_announce_enable_cbk,.announce_disable_cb example_sle_announce_disable_cbk,.announce_terminal_cb example_sle_announce_terminal_cbk,.sle_enable_cb example_sle_enable_cbk};sle_announce_seek_register_callbacks(seek_cbks);
}// 广播初始化主函数
errcode_t example_sle_server_adv_init(void) {example_sle_announce_register_cbks(); // 注册回调example_sle_set_default_announce_param(); // 设置广播参数example_sle_set_default_announce_data(); // 设置广播数据example_sle_set_addr(); // 设置设备地址example_sle_set_name(); // 设置设备名称sle_start_announce(SLE_ADV_HANDLE_DEFAULT); // 启动广播return ERRCODE_SUCC;
}回调机制监听广播启用、禁用、终止和SLE启用事件初始化流程注册回调→设置参数→配置数据→地址名称→启动广播广播控制通过sle_start_announce启动广播使用默认句柄1
四、从代码库拿的代码跑不通解决
将SLE_LED_Server\src\SLE_LED_Server.c文件中的example_sle_server_property_add方法内部 descriptor.permissions SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE;descriptor.value osal_vmalloc(sizeof(ntf_value));修改为 descriptor.permissions SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE;descriptor.operate_indication SSAP_OPERATE_INDICATION_BIT_READ | SSAP_OPERATE_INDICATION_BIT_WRITE;descriptor.type SSAP_DESCRIPTOR_USER_DESCRIPTION;descriptor.value ntf_value;descriptor.value_len sizeof(ntf_value);修改后的方法如下
static errcode_t example_sle_server_property_add(void)
{errcode_t ret ERRCODE_FAIL;ssaps_property_info_t property {0};ssaps_desc_info_t descriptor {0};uint8_t ntf_value[] {0x01, 0x0};property.permissions SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE;example_sle_uuid_setu2(SLE_UUID_SERVER_PROPERTY, property.uuid);property.value osal_vmalloc(sizeof(g_sle_property_value));if (property.value NULL) {PRINT([SLE Server] sle property mem fail\r\n);return ERRCODE_MALLOC;}if (memcpy_s(property.value, sizeof(g_sle_property_value), g_sle_property_value, sizeof(g_sle_property_value)) !EOK) {osal_vfree(property.value);PRINT([SLE Server] sle property mem cpy fail\r\n);return ERRCODE_MEMCPY;}ret ssaps_add_property_sync(g_server_id, g_service_handle, property, g_property_handle);if (ret ! ERRCODE_SUCC) {PRINT([SLE Server] sle uuid add property fail, ret:0x%x\r\n, ret);osal_vfree(property.value);return ERRCODE_FAIL;}PRINT([SLE Server] sle uuid add property property_handle: %u\r\n, g_property_handle);//仓库的代码// descriptor.permissions SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE;// descriptor.value osal_vmalloc(sizeof(ntf_value));//新的代码descriptor.permissions SSAP_PERMISSION_READ | SSAP_PERMISSION_WRITE;descriptor.operate_indication SSAP_OPERATE_INDICATION_BIT_READ | SSAP_OPERATE_INDICATION_BIT_WRITE;descriptor.type SSAP_DESCRIPTOR_USER_DESCRIPTION;descriptor.value ntf_value;descriptor.value_len sizeof(ntf_value);if (descriptor.value NULL) {PRINT([SLE Server] sle descriptor mem fail\r\n);osal_vfree(property.value);return ERRCODE_MALLOC;}if (memcpy_s(descriptor.value, sizeof(ntf_value), ntf_value, sizeof(ntf_value)) ! EOK) {PRINT([SLE Server] sle descriptor mem cpy fail\r\n);osal_vfree(property.value);osal_vfree(descriptor.value);return ERRCODE_MEMCPY;}ret ssaps_add_descriptor_sync(g_server_id, g_service_handle, g_property_handle, descriptor);if (ret ! ERRCODE_SUCC) {PRINT([SLE Server] sle uuid add descriptor fail, ret:0x%x\r\n, ret);osal_vfree(property.value);osal_vfree(descriptor.value);return ERRCODE_FAIL;}osal_vfree(property.value);osal_vfree(descriptor.value);return ERRCODE_SUCC;
}差异主要体现在内存管理方式、描述符字段配置上。
总结
个人分析仅供参考。如有疑问请留言或者联系计蒙。下一篇文章计划–写一个关于OLED的星闪互联案例。