基于小智派-LZ3863星闪开发板:OpenHarmony 星闪 SLE 开发 — 基础连接客户端
1、实验简介
本实验参考网址:https://gitee.com/Lockzhiner-Electronics/lz3863/tree/master/apps/e2_sle_connect_client
准备事项:
- 小智派-LZ3863开发板
- USB烧录线
- Windows电脑
其中,小智派-LZ3863开发板是福州市凌睿智捷电子有限公司研发的一款基于海思WS63(Hi3863)芯片、高度集成2.4GHz Wi-Fi6、BLE(低功耗蓝牙)和SLE(星闪低功耗接入技术,简称SLE)、专用于短距离数据传输的新兴无线通信技术模块。

1.1、实验目的
本实验旨在帮助学习者掌握 OpenHarmony 轻量系统中 SLE(Smart Link Extension,星闪)SSAP 客户端 的基本使用方法。通过本实验,你将学会:
- 理解 SLE 设备发现(Announce/Seek) 扫描与连接机制,以及 SSAP Client(SLE Service Access Protocol 客户端) 服务发现流程;
- 在开发板上实现 SLE UART 客户端,完成扫描、连接、服务/属性发现与数据收发;
- 使用 CMSIS-RTOS v2 创建独立的收发任务,实现与服务端的双向数据通信;
- 掌握 SLE 扫描回调、连接状态回调、Notify 接收与 Write 写请求发送的处理流程;
- 完成案例代码的编译、烧录,并与
e1_sle_connect_server服务端案例进行双板联调。
1.2、实验内容
本案例在 LZ3863-星闪开发板上实现 SLE SSAP 客户端 功能:初始化星闪协议栈并注册 SSAP 客户端,扫描并连接广播名称为 sle_uart_server 的服务端;连接建立后完成 SSAP 服务发现,通过 Write 周期性向服务端发送数据,同时接收服务端 Notify 通知并打印到串口。
| 项目 | 说明 |
|---|---|
| 应用层源文件 | sle_client_app.c(任务与收发逻辑) |
| 协议栈封装 | sle_client_lib.c / sle_client_lib.h(扫描、连接、SSAP 发现、回调) |
| 目标服务端名称 | sle_uart_server(与 e1 服务端一致) |
| 客户端 MAC 地址 | 13:67:5c:07:00:51 |
| 服务端 MAC 地址 | 78:70:60:88:96:46(由 e1 服务端配置) |
| 服务 UUID | 0x2222(由服务端提供,客户端发现所有服务) |
| 属性 UUID | 0x2323(双向数据收发属性) |
| 发送数据 | "hello sle:from client" |
| 发送周期 | 约 1 秒(osDelay(100),tick = 10 ms) |
| 接收缓冲区 | g_sle_rx_data[256] |
| 初始化入口 | APP_FEATURE_INIT(sle_server_app) |
典型联调拓扑:
┌─────────────────────┐ SLE 连接 ┌─────────────────────┐
│ 开发板 A(e1 服务端)│ ◄────────────► │ 开发板 B(本案例) │
│ e1_sle_connect_ │ SSAP Notify │ e2_sle_connect_ │
│ server(Server) │ SSAP Write │ client(Client) │
│ 广播: sle_uart_ │ │ 扫描并连接服务端 │
│ server │ │ 发送: hello sle: │
│ 发送: hello sle: │ │ from client │
│ from server │ │ │
└─────────────────────┘ └─────────────────────┘
说明:本案例为 SLE 客户端,需配合
e1_sle_connect_server服务端案例完成联调。建议先烧录并启动服务端开发板,确认广播就绪后再启动客户端开发板。
1.3、实验环境
| 项目 | 说明 |
|---|---|
| 硬件 | 两块 LZ3863-星闪开发板(服务端 + 客户端)、USB 数据线 |
| 软件 | OpenHarmony v5.1.0 源码、hb 编译工具 |
| 联调案例 | e1_sle_connect_server(服务端,烧录至第一块开发板) |
| 调试工具 | 串口助手(波特率 115200,8N1) |
| 案例路径 | applications/sample/wifi-iot/app/e2_sle_connect_client/ |
注意:完整双向通信实验需要 两块开发板,分别烧录服务端固件(
e1_sle_connect_server)和客户端固件(本案例)。
2、基础知识
2.1、SLE 协议栈概述
SLE(Smart Link Extension,星闪) 是面向物联网场景的短距离无线通信技术,具备低功耗、低延迟、高吞吐量等优势。SLE 协议栈从下到上可分为:
| 层次 | 英文名称 | 主要功能 |
|---|---|---|
| 物理层 | PHY | 射频收发 |
| 链路层 | LL | 连接建立、数据包封装 |
| 主机控制器接口 | HCI | 控制器与主机间通信 |
| 服务访问协议 | SSAP | 服务/属性读写、句柄管理 |
| 设备发现 | Announce/Seek | 广播、扫描、连接 |
| 连接管理 | Connection Manager | 连接状态、配对管理 |
本案例主要涉及 设备发现(Seek) 和 SSAP Client(客户端服务发现与属性读写) 两层。
2.2、设备发现:扫描与连接
SLE 设备通过 Announce(广播) 和 Seek(扫描) 完成发现与连接。本案例客户端采用 主动扫描(Active Seek) 发现服务端,匹配目标广播名称后发起连接:
客户端启动
↓
注册 SSAP 客户端回调
↓
EnableSle() → sle_client_sample_sle_enable_cbk
↓
设置扫描参数 → SleSetSeekParam()
↓
SleStartSeek() → 开始扫描
↓
扫描到 sle_uart_server → 停止扫描 → SleConnectRemoteDevice()
↓
连接建立 → SLE_ACB_STATE_CONNECTED
↓
连接断开 → 重新扫描
本案例扫描参数:
| 参数 | 值 | 说明 |
|---|---|---|
| 扫描间隔 | SLE_SEEK_INTERVAL_DEFAULT(100) |
单位 0.625 ms,约 62.5 ms |
| 扫描窗口 | SLE_SEEK_WINDOW_DEFAULT(100) |
与间隔相等,持续扫描 |
| 扫描类型 | seekType[0] = 1 |
主动扫描 |
| 扫描物理通道 | seekphys = 1 |
LE 物理通道 |
| 过滤策略 | seekfilterpolicy = 0 |
接受所有广播包 |
| 目标名称 | sle_uart_server |
与服务端广播名称一致 |
2.3、SSAP Client:服务发现
SSAP 采用 Client/Server 模型。客户端连接服务端后,需要通过 服务发现(Service Discovery) 获取服务端提供的服务与属性句柄,才能进行数据读写。
本案例连接的服务端提供 SLE UART 透传服务,结构如下:
Service: 0x2222 (SLE UART Service)
└── Property: 0x2323
权限: Read | Write
操作指示: Read | Write
描述符: Client Configuration (0x2902)
用途: 双向数据收发(Notify 接收 + Write 发送)
| 角色 | 数据方向 | 本案例实现方式 |
|---|---|---|
| 服务端 → 客户端 | Property Notify | ssapc_notification_callbacks() → 写入 g_sle_rx_data |
| 客户端 → 服务端 | Property Write | sle_client_send_report_by_handle() → SsapWriteReq() |
SSAP 发现流程:
连接建立 → MTU 交换(SsapcExchangeInfoReq)
↓
ssapc_find_structure() 发现所有服务
↓
sle_client_sample_find_structure_cbk 保存服务句柄范围
↓
sle_client_sample_find_property_cbk 保存属性句柄
↓
服务发现完成 → 开始数据收发
2.4、SLE 事件回调机制
SLE 协议栈通过回调函数异步通知应用层状态变化。本案例注册了设备发现、连接管理与 SSAP Client 三类回调:
设备发现回调:
| 回调函数 | 触发时机 | 处理逻辑 |
|---|---|---|
sle_client_sample_sle_enable_cbk |
SLE 协议栈启用完成 | 延时 1s 后开始扫描 |
sle_client_sample_seek_enable_cbk |
扫描启动成功 | 打印日志 |
sle_client_sample_seek_result_info_cbk |
扫描到广播设备 | 匹配 sle_uart_server,保存地址并停止扫描 |
sle_client_sample_seek_disable_cbk |
扫描停止 | 发起连接 SleConnectRemoteDevice() |
连接管理回调:
| 回调函数 | 触发时机 | 处理逻辑 |
|---|---|---|
sle_client_sample_connect_state_changed_cbk |
连接状态变化 | 连接时交换 MTU 并配对;断开时移除配对并重新扫描 |
SSAP Client 回调:
| 回调函数 | 触发时机 | 处理逻辑 |
|---|---|---|
sle_client_sample_exchange_info_cbk |
MTU 协商完成 | 发起服务发现 ssapc_find_structure() |
sle_client_sample_find_structure_cbk |
发现服务 | 保存服务句柄范围与 UUID |
sle_client_sample_find_property_cbk |
发现属性 | 保存属性句柄至 g_sle_send_param |
sle_client_sample_find_structure_cmp_cbk |
服务发现完成 | 打印发现结果 |
sle_client_sample_write_cfm_cb |
写操作完成 | 打印写操作结果 |
ssapc_notification_callbacks |
收到 Notify 通知 | 将数据拷贝至 g_sle_rx_data,置位 g_sle_new_data_ready |
ssapc_indication_callbacks |
收到 Indicate 指示 | 预留指示处理 |
2.5、软件调用层次
本案例的软件调用层次如下:
应用层(sle_client_app.c)
├── sle_server_app() ← APP_FEATURE_INIT 注册入口
├── sle_rx_client() ← 接收任务:打印服务端 Notify 数据
└── sle_tx_client() ← 发送任务:周期性 Write 发送数据
│
封装层(sle_client_lib.c)
├── SleClientInit() ← 初始化:注册回调、启用 SLE
├── SleStartScan() ← 配置并启动扫描
├── sle_client_sample_seek_result_info_cbk ← 扫描匹配与连接
├── sle_client_sample_exchange_info_cbk ← MTU 交换与服务发现
├── sle_client_send_report_by_handle() ← SSAP Write 发送
└── ssapc_notification_callbacks() ← SSAP Notify 接收
│
协议栈 / 驱动层
├── SleAnnounceSeek*() ← 扫描与设备发现
├── SleConnection*() ← 连接与配对管理
├── Ssapc*() ← SSAP Client 发现/读写
└── EnableSle() ← 启用 SLE 协议栈
2.6、核心 API 介绍
2.6.1、头文件
#include "sle_client_lib.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
2.6.2、应用层 API
| API 名称 | 功能说明 |
|---|---|
SleClientInit() |
初始化 SLE 客户端:注册回调、启用 SLE 协议栈 |
sle_client_send_report_by_handle(data, len) |
通过 SSAP Write 向已连接服务端发送数据 |
osThreadNew(func, arg, &attr) |
创建 RTOS 线程 |
osDelay(ticks) |
线程延时,100 ticks ≈ 1 秒(tick = 10 ms) |
APP_FEATURE_INIT(func) |
注册应用特性初始化入口,系统启动后自动执行 |
2.6.3、协议栈 API(sle_client_lib.c 内部调用)
| API 名称 | 功能说明 |
|---|---|
EnableSle() |
启用 SLE 协议栈 |
SleSetLocalAddr() |
设置 SLE 设备 MAC 地址 |
SleSetSeekParam() / SleStartSeek() |
配置并启动扫描 |
SleStopSeek() |
停止扫描 |
SleConnectRemoteDevice() |
连接远程 SLE 设备 |
SsapcRegisterClient() |
注册 SSAP 客户端 |
SsapcExchangeInfoReq() |
请求 MTU 交换 |
ssapc_find_structure() |
发现 SSAP 服务/属性 |
SsapWriteReq() |
向服务端属性写入数据 |
SleConnectionRegisterCallbacks() |
注册连接状态回调 |
3、程序设计
3.1、程序架构
本案例目录结构:
e2_sle_connect_client/
├── sle_client_app.c # 应用层:收发任务与入口
├── sle_client_lib.c # 协议栈封装:扫描、连接、SSAP 发现、回调
├── sle_client_lib.h # 头文件:宏定义与 API 声明
├── BUILD.gn # GN 编译配置
├── README_zh.md # 案例简要说明
└── 实验手册.md # 本实验手册
程序执行流程:
系统启动
│
▼
sle_server_app() ← APP_FEATURE_INIT 注册,自动执行
│
├── SleClientInit() ← 注册客户端 → 注册回调 → 启用 SLE
│ └── sle_enable_cbk → 延时 1s → SleStartScan()
│
├── osThreadNew(sle_rx_client) ← 创建接收任务
└── osThreadNew(sle_tx_client) ← 创建发送任务
│
▼
┌───────────────────────────────────────────┐
│ 扫描回调链(sle_client_lib.c) │
│ 扫描到 sle_uart_server → 连接 → MTU 交换 │
│ → 服务发现 → 属性发现 → 保存写句柄 │
└───────────────────────────────────────────┘
┌───────────────────────────────────────────┐
│ sle_rx_client(接收任务) │
│ 轮询 g_sle_new_data_ready → 打印 Notify 数据│
└───────────────────────────────────────────┘
┌───────────────────────────────────────────┐
│ sle_tx_client(发送任务) │
│ 每 1s 通过 Write 向服务端发送 send_date │
└───────────────────────────────────────────┘
3.2、源文件说明
| 文件 | 说明 |
|---|---|
sle_client_app.c |
应用层主程序,定义发送数据缓冲区,创建 RX/TX 两个 RTOS 任务 |
sle_client_lib.c |
SLE 协议栈封装,实现扫描、连接、SSAP 服务发现与各类回调处理 |
sle_client_lib.h |
扫描参数、服务端名称、全局变量声明与 API 接口 |
BUILD.gn |
编译配置,生成 sle_connect 静态库 |
3.3、关键代码分析
(1)目标服务端名称与扫描参数
#define SLE_SERVER_NAME "sle_uart_server"
#define SLE_SEEK_INTERVAL_DEFAULT 100
#define SLE_SEEK_WINDOW_DEFAULT 100
#define SLE_TASK_DELAY_MS 1000
客户端通过广播数据中的设备名称匹配目标服务端,名称需与 e1_sle_connect_server 中 g_sleLocalName 保持一致。
(2)全局发送数据
uint8_t send_date[20] = "hello sle:from client";
客户端连接建立并完成服务发现后,发送任务每隔约 1 秒通过 Write 向服务端发送该字符串。
(3)接收任务 — sle_rx_client
接收任务通过轮询全局标志位 g_sle_new_data_ready 检测服务端 Notify 的新数据(由 ssapc_notification_callbacks 置位):
void sle_rx_client(void *arg)
{
unused(arg);
while (1)
{
if (g_sle_new_data_ready == true)
{
printf("sle rev date:%s", g_sle_rx_data);
g_sle_new_data_ready = false;
}
osDelay(1);
}
}
(4)发送任务 — sle_tx_client
发送任务周期性调用 Write 发送接口:
void sle_tx_client(void *arg)
{
unused(arg);
while (1)
{
sle_client_send_report_by_handle(send_date, sizeof(send_date));
osDelay(100);
}
}
注意:发送任务在连接建立前也会调用发送接口,但协议栈在无连接或服务发现未完成时不会实际发送数据。连接建立且服务发现完成后 Write 才会生效。
(5)程序入口 — sle_server_app
static void sle_server_app(void)
{
SleClientInit();
osThreadAttr_t rx_attr = {0};
rx_attr.name = "sle_rx_client";
rx_attr.stack_size = 8192;
rx_attr.priority = osPriorityNormal;
osal_kthread_lock();
if (osThreadNew(sle_rx_client, NULL, &rx_attr) == NULL)
{
printf("[LedTest] Failed to create led_pwm_main thread!\n");
}
osal_kthread_unlock();
osThreadAttr_t tx_attr = {0};
tx_attr.name = "sle_tx_client";
tx_attr.stack_size = 8192;
tx_attr.priority = osPriorityNormal;
osal_kthread_lock();
if (osThreadNew(sle_tx_client, NULL, &tx_attr) == NULL)
{
printf("[LedTest] Failed to create led_pwm_main thread!\n");
}
osal_kthread_unlock();
}
APP_FEATURE_INIT(sle_server_app);
说明:入口函数名为
sle_server_app是历史命名保留,实际功能为 SLE 客户端初始化。系统启动后自动调用该函数,先完成 SLE 客户端初始化,再创建收发两个独立任务。
(6)客户端初始化 — SleClientInit
void SleClientInit()
{
uint8_t local_addr[SLE_ADDR_LEN] = {0x13, 0x67, 0x5c, 0x07, 0x00, 0x51};
SleAddr local_address;
local_address.type = 0;
memcpy_s(local_address.addr, SLE_ADDR_LEN, local_addr, SLE_ADDR_LEN);
sle_uuid_client_register(); /* 注册 SSAP 客户端 */
SleClientSampleSeekCbkRegister(); /* 注册扫描回调 */
SleClientSampleConnectCbkRegister(); /* 注册连接回调 */
sle_client_sample_ssapc_cbk_register(ssapc_notification_callbacks,
ssapc_indication_callbacks);
EnableSle(); /* 启用 SLE */
SleSetLocalAddr(&local_address); /* 设置本地 MAC 地址 */
}
EnableSle() 成功后触发 sle_client_sample_sle_enable_cbk 回调,延时 1 秒后开始扫描。
(7)扫描匹配与连接 — sle_client_sample_seek_result_info_cbk
static void sle_client_sample_seek_result_info_cbk(SleSeekResultInfo *seek_result_data)
{
printf("%s sle uart scan data :%s\r\n", SLE_CLIENT_LOG, seek_result_data->data);
if (strstr((const char *)seek_result_data->data, SLE_SERVER_NAME) != NULL)
{
memcpy_s(&g_sle_remote_addr, sizeof(sle_addr_t),
&seek_result_data->addr, sizeof(sle_addr_t));
SleStopSeek();
}
}
扫描到广播数据中包含 sle_uart_server 时,保存服务端地址并停止扫描;扫描停止回调中自动发起连接。
(8)连接状态处理 — sle_client_sample_connect_state_changed_cbk
static void sle_client_sample_connect_state_changed_cbk(uint16_t conn_id, const SleAddr *addr,
SleAcbStateType conn_state, ...)
{
g_sle_conn_id = conn_id;
if (conn_state == SLE_ACB_STATE_CONNECTED)
{
SsapcExchangeInfo info = {0};
info.mtuSize = SLE_MTU_SIZE_DEFAULT; /* 520 */
info.version = 1;
SsapcExchangeInfoReq(0, conn_id, &info);
SlePairRemoteDevice(addr);
}
else if (conn_state == SLE_ACB_STATE_DISCONNECTED)
{
SleRemovePairedRemoteDevice(addr);
SleStartScan(); /* 断开后重新扫描 */
}
}
(9)SSAP Write 发送 — sle_client_send_report_by_handle
errcode_t sle_client_send_report_by_handle(const uint8_t *data, uint8_t len)
{
ssapc_write_param_t param = {0};
param.handle = g_sle_find_service_result.start_hdl;
param.type = 0;
param.data = receive_buf;
param.data_len = len + 1;
memcpy_s(param.data, param.data_len, data, len);
return SsapWriteReq(g_client_id, g_sle_conn_id, ¶m);
}
Write 发送依赖服务发现后保存的服务句柄和当前连接 ID。属性句柄在 sle_client_sample_find_property_cbk 中保存至 g_sle_send_param.handle。
(10)Notify 接收 — ssapc_notification_callbacks
void ssapc_notification_callbacks(uint8_t client_id, uint16_t conn_id,
ssapc_handle_value_t *data, errcode_t status)
{
data->data[data->data_len - 1] = '\0';
memcpy(g_sle_rx_data, data->data, data->data_len);
g_sle_new_data_ready = true;
}
服务端通过 Notify 发送的数据在此回调中接收,并置位 g_sle_new_data_ready 供接收任务打印。
(11)BUILD.gn — 编译配置
static_library("sle_connect") {
sources = [
"sle_client_lib.c",
"sle_client_app.c",
]
// ...
}
3.4、程序执行流程
4、编译步骤
本实验编译客户端固件并烧录至 开发板 B;服务端固件请参考 e1_sle_connect_server 案例编译烧录至 开发板 A。以下步骤只需在首次编译时完成 4.1~4.3 的配置注册。
4.1、确认案例目录
确认案例已位于 OpenHarmony 源码目录下:
applications/sample/wifi-iot/app/e2_sle_connect_client/
├── sle_client_app.c
├── sle_client_lib.c
├── sle_client_lib.h
├── BUILD.gn
└── 实验手册.md
若从外部复制,请将 e2_sle_connect_client 目录放到上述 app/ 路径下。
4.2、修改 BUILD.gn(注册编译组件)
编辑 applications/sample/wifi-iot/app/BUILD.gn,在 features 列表中添加本案例:
lite_component("app") {
features = [
"startup",
"e2_sle_connect_client:sle_connect", // 添加此行
]
}
4.3、修改 SDK 配置文件
步骤 1:编辑 device/soc/hisilicon/ws63v100/sdk/build/config/target_config/ws63/config.py
找到 'ws63-liteos-app' 配置段,在其 'ram_component' 列表中添加:
"sle_connect"
步骤 2:编辑 device/soc/hisilicon/ws63v100/sdk/libs_url/ws63/cmake/ohos.cmake
找到 "ws63-liteos-app" 对应的 set(COMPONENT_LIST 部分,添加:
"sle_connect"
4.4、编译固件
在 OpenHarmony 源码根目录下执行编译:
rm -rf out
hb set -root .
# 通过上下方向键选择 ws63 对应的编译分支(如 nearlink_txnl63 / nearlink_dk_3863)
hb build -f
编译成功后,将固件烧录到 开发板 B(作为 SLE 客户端)。
4.5、编译服务端固件(开发板 A)
按照 e1_sle_connect_server 案例的 README,完成服务端的 BUILD.gn 与 SDK 配置注册(组件名同样为 sle_connect,但需将 features 指向 e1_sle_connect_server:sle_connect),编译后将固件烧录到 开发板 A。
注意:服务端与客户端不能同时编译到同一块开发板固件中。编译服务端时,需将
features中的e2_sle_connect_client:sle_connect替换为e1_sle_connect_server:sle_connect。
4.6、烧录固件
使用开发板配套的烧录工具,将编译生成的固件分别烧写到两块 LZ3863-星闪开发板。具体烧录步骤请参考开发板用户手册。
5、运行结果
5.1、硬件准备
- 将 开发板 A(服务端固件
e1_sle_connect_server)上电或复位,等待 SLE 广播启动; - 将 开发板 B(客户端固件,本案例)上电或复位,开始扫描并连接服务端;
- 两块开发板分别通过 USB 连接 PC,打开串口助手查看日志(波特率 115200,8N1)。
建议:先启动服务端开发板,确认广播启动日志输出后,再启动客户端开发板,以提高首次连接成功率。
5.2、串口配置
| 参数 | 值 |
|---|---|
| 波特率 | 115200 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验位 | 无 |
| 流控 | 无 |
5.3、客户端预期输出(开发板 B)
烧录客户端固件并复位后,串口助手可观察到扫描、连接与数据收发过程:
[sle uart client] sle uart scan data :sle_uart_server
[sle uart client] SLE_ACB_STATE_CONNECTED
[sle uart client] exchange mtu, mtu size: 520, version: 1.
[sle uart client] find structure cbk client: 0 conn_id:1 status: 0
[sle uart client] sle_client_sample_find_property_cbk, client id: 0, conn id: 1, ...
sle rev date:hello sle:from server
其中:
sle uart scan data :sle_uart_server表示扫描到目标服务端;SLE_ACB_STATE_CONNECTED表示已成功连接服务端;exchange mtu/find structure表示 SSAP 服务发现完成;sle rev date:hello sle:from server表示收到服务端 Notify 发送的数据。
5.4、服务端预期输出(开发板 A)
烧录 e1_sle_connect_server 固件并复位后,串口助手可观察到 SLE 初始化与服务注册过程:
[sle server] init ok
[sle server] sle enable callback status:0
[sle server] sle add service in
[sle server] add service cbk callback server_id:0, handle:xx, status:0
[sle server] uuid: 22 22.
[sle server] add property cbk callback server_id:0, service_handle:xx, handle:xx, status:0
[sle server] uuid: 23 23.
[sle server] sle add service, server_id:0, service_handle:xx, property_handle:xx
[sle server] set announce data success.
[sle server] sle announce enable callback id:01, state:0
客户端连接成功后,服务端还会输出:
[sle server] connect state changed callback conn_id:0x01, conn_state:0x2, ...
[sle server] pair complete conn_id:01, status:0
client_send_data: hello sle:from client
sle rev date:hello sle:from client
其中:
conn_state:0x2表示 SLE 连接已建立(OH_SLE_ACB_STATE_CONNECTED);client_send_data表示 SSAP 写请求回调收到客户端数据;sle rev date:hello sle:from client表示接收任务打印了客户端写入的数据。
5.5、双向通信验证
连接建立后,两块开发板应持续(约每秒一次)交换数据:
| 方向 | 发送内容 | 接收端串口输出 |
|---|---|---|
| 服务端 → 客户端 | hello sle:from server |
客户端:sle rev date:hello sle:from server |
| 客户端 → 服务端 | hello sle:from client |
服务端:sle rev date:hello sle:from client |
5.6、结果分析
| 现象 | 说明 |
|---|---|
客户端输出 sle uart scan data :sle_uart_server |
扫描成功,发现目标服务端 |
客户端输出 SLE_ACB_STATE_CONNECTED |
已成功连接服务端 |
客户端输出 find structure / find property |
SSAP 服务发现完成 |
客户端输出 sle rev date:hello sle:from server |
Notify 接收正常,双向通信成功 |
服务端输出 client_send_data / sle rev date |
客户端 Write 数据接收正常 |
| 客户端长时间无连接日志 | 服务端未启动或广播未就绪,检查服务端日志 |
| 连接成功但无数据收发 | SSAP 服务发现未完成,检查 UUID 是否匹配 |
5.7、常见问题排查
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| 客户端扫描不到服务端 | 服务端未启动或广播失败 | 确认服务端输出 announce enable callback;先启动服务端 |
| 连接后立即断开 | 信号干扰或协议栈未就绪 | 两块板靠近放置;确认双方 sle_enable_cbk 延时 1s 已执行 |
客户端无 sle rev date 输出 |
Notify 未启用或服务发现未完成 | 检查服务端描述符是否默认启用 Notify |
服务端无 sle rev date 输出 |
客户端未写入或属性 UUID 不匹配 | 确认客户端已连接并完成服务发现 |
编译报错找不到 sle_connect |
BUILD.gn 或 config.py 未正确修改 | 逐步核对 4.2、4.3 节的配置项 |
| 两块板烧录了相同固件 | 未区分服务端/客户端固件 | 分别编译烧录 e1(服务端)和 e2(客户端) |
6、实验扩展
完成基本实验后,可尝试以下扩展练习:
- 修改目标服务端名称:更改
SLE_SERVER_NAME宏,同时修改服务端g_sleLocalName,观察扫描连接结果的变化; - 修改发送内容:更改
send_date字符串,验证 Write 发送自定义数据; - 调整发送频率:修改
sle_tx_client中osDelay(100)的参数,观察收发频率变化; - 断开重连测试:断开 SLE 连接后观察客户端是否自动重新扫描并成功重连;
- 修改 MAC 地址:调整
local_addr数组,了解 SLE 地址配置对连接的影响; - 结合后续案例:在 SLE 连接基础上,配合其他星闪或网络通信案例实现更复杂的物联网应用。
更多推荐



所有评论(0)