
星闪SLE客户端开发
本文主要简要概述星闪SLE客户端开发流程,由于目前开源出来手册不多,所以主要的流程熟悉还是以阅读代码为主,个人学习建议:将星闪客户端的代码整体抄一遍,不会的可以类比蓝牙向AI提问,这也能够更加加深理解
笔者在gitee仓库开源了一整套关于WS63的外设以及星闪开发应用,欢迎大家访问:星闪学习
HiSpark官方仓库:https://gitee.com/HiSpark/fbb_ws63
整体流程
- 调用
enable_sle,打开SLE开关 - 调用
sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数 - 调用
sle_get_local_addr,设置本地设备地址 - 调用
sle_get_local_name,设置本地设备名称 - 调用
sle_set_seek_param,设置设备发现参数 - 调用
sle_start_seek,启动设备发现,并在回调函数中获取正在进行设备公开的设备信息
SLE配置流程:注册ssap,seek->connect->pair
x
sle_seek_cbk_config(); sle_announce_seek_register_callbacks(&sle_announce_seek_callbacks); sle_connection_cbk_config(); sle_connection_register_callbacks(&sle_connection_callbacks); ssap_cbk_config(); ssapc_register_callbacks(&ssapc_callbacks); enable_sle();在注册设备公开和设备发现的回调函数中参数
xxxxxxxxxxsle_announce_seek_callbacks_t sle_announce_seek_callbacks = {0};设置这几个变量:
xxxxxxxxxxsle_announce_seek_callbacks.sle_enable_cb = ;sle_announce_seek_callbacks.seek_enable_cb = ;sle_announce_seek_callbacks.seek_disable_cb = ;sle_announce_seek_callbacks.seek_result_cb = ;当SLE使能后就会调用这个回调函数sle_enable_cb,这时候就需要在这个函数中开启扫描
扫描配置参数:sle_seek_param_t
ssapc_callbacks_t说明
x
ssapc_notification_callback notification_cb; /*!< @if Eng Callback hook for receive notification. @else 通知事件上报钩子。 @endif */ ssapc_indication_callback indication_cb; /*!< @if Eng Callback hook for receive indication. @else 指示事件上报钩子。 @endif */在蓝牙低功耗(BLE)协议或类似的通信框架中,notification_cb(通知回调)和indication_cb(指示回调)是两种不同的数据传输机制,核心区别在于数据确认机制和可靠性。以下是它们的详细区别和应用场景:
数据确认机制
| 特性 | 通知(Notification) | 指示(Indication) |
|---|---|---|
| 确认要求 | 无需客户端确认 | 必须由客户端发送确认(ACK) |
| 可靠性 | 可能丢包(无重传机制) | 数据可靠传输(若未收到ACK,服务器会重传) |
| 延迟 | 低延迟(无需等待ACK) | 较高延迟(需等待ACK响应) |
注意
在客户端配对完成后需要使用这个函数去获取服务端设置的info
xxxxxxxxxxvoid sle_sample_pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status){ osal_printk("[ssap client] pair complete conn_id:%d, addr:%02x***%02x%02x\n", conn_id, addr->addr[0], addr->addr[4], addr->addr[5]); /* 0 4 5: addr index */ if (status == 0) { ssap_exchange_info_t info = {0}; info.mtu_size = SLE_MTU_SIZE_DEFAULT; info.version = 1; ssapc_exchange_info_req(0, g_conn_id, &info); <----获取服务端fifo sle_set_data_len(g_conn_id,SLE_MTU_SIZE_DEFAULT); }}源码
x
sle_addr_t g_remote_addr = {0};sle_announce_seek_callbacks_t sle_announce_seek_callbacks = {0};sle_connection_callbacks_t sle_connection_callbacks = {0};ssapc_callbacks_t ssapc_callbacks = {0};uint16_t g_conn_id = 0;ssapc_find_service_result_t g_find_service_result = {0};//***************seek******************//void sle_scan_start(void){ sle_seek_param_t sle_seek_param = { 0 }; sle_seek_param.own_addr_type = 0; //本端地址类型 sle_seek_param.filter_duplicates = 0;//重复过滤开关,0:关闭,1:开启 sle_seek_param.seek_filter_policy = SLE_SEEK_FILTER_ALLOW_ALL; sle_seek_param.seek_phys = SLE_SEEK_PHY_1M; sle_seek_param.seek_type[0] = SLE_SEEK_PASSIVE; sle_seek_param.seek_interval[0] = SLE_SEEK_INTERVAL_DEFAULT; sle_seek_param.seek_window[0] = SLE_SEEK_WINDOW_DEFAULT; sle_set_seek_param(&sle_seek_param); sle_start_seek();}void sle_enable_cbk(errcode_t status){ if(status == 0) { sle_scan_start(); }}void sle_sample_seek_enable_cbk(errcode_t status){ if (status == 0) { return; }}void sle_sample_seek_disable_cbk(errcode_t status){ if (status == 0) { sle_connect_remote_device(&g_remote_addr); }}void sle_sample_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data){ if (seek_result_data != NULL) { (void)memcpy_s(&g_remote_addr, sizeof(sle_addr_t), &seek_result_data->addr, sizeof(sle_addr_t)); sle_stop_seek(); }}void sle_seek_cbk_config(void){ sle_announce_seek_callbacks.sle_enable_cb = sle_enable_cbk; sle_announce_seek_callbacks.seek_enable_cb = sle_sample_seek_enable_cbk; sle_announce_seek_callbacks.seek_disable_cb = sle_sample_seek_disable_cbk; sle_announce_seek_callbacks.seek_result_cb = sle_sample_seek_result_info_cbk;}//-------------------seek----------------////*******************connect********************//void 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){ osal_printk("[ssap client] conn state changed conn_id:%d, addr:%02x***%02x%02x\n", conn_id, addr->addr[0], addr->addr[4], addr->addr[5]); /* 0 4 5: addr index */ osal_printk("[ssap client] conn state changed disc_reason:0x%x\n", disc_reason); if (conn_state == SLE_ACB_STATE_CONNECTED) { if (pair_state == SLE_PAIR_NONE) { sle_pair_remote_device(&g_remote_addr); } g_conn_id = conn_id; }}void pair_complete_cbk(uint16_t conn_id, const sle_addr_t *addr, errcode_t status){ osal_printk("[ssap client] pair complete conn_id:%d, addr:%02x***%02x%02x\n", conn_id, addr->addr[0], addr->addr[4], addr->addr[5]); /* 0 4 5: addr index */ if (status == 0) { ssap_exchange_info_t info = {0}; info.mtu_size = SLE_MTU_SIZE_DEFAULT; info.version = 1; ssapc_exchange_info_req(1, g_conn_id, &info); }}void sle_connection_cbk_config(void){ sle_connection_callbacks.connect_state_changed_cb = connect_state_changed_cbk;//连接状态 sle_connection_callbacks.pair_complete_cb = pair_complete_cbk;}//----------------------------connect-------------------------////*************************ssap****************************//void exchange_info_cbk(uint8_t client_id, uint16_t conn_id, ssap_exchange_info_t *param, errcode_t status){ osal_printk("[ssap client] pair complete client id:%d status:%d\n", client_id, status); osal_printk("[ssap client] exchange mtu, mtu size: %d, version: %d.\n", param->mtu_size, param->version); ssapc_find_structure_param_t find_param = {0}; find_param.type = SSAP_FIND_TYPE_PRIMARY_SERVICE; find_param.start_hdl = 1; find_param.end_hdl = 0xFFFF; ssapc_find_structure(0, conn_id, &find_param);}void sle_sample_find_structure_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_service_result_t *service, errcode_t status){ osal_printk("[ssap client] find structure cbk client: %d conn_id:%d status: %d \n", client_id, conn_id, status); osal_printk("[ssap client] find structure start_hdl:[0x%02x], end_hdl:[0x%02x], uuid len:%d\r\n", service->start_hdl, service->end_hdl, service->uuid.len); if (service->uuid.len == UUID_16BIT_LEN) { osal_printk("[ssap client] structure uuid:[0x%02x][0x%02x]\r\n", service->uuid.uuid[14], service->uuid.uuid[15]); /* 14 15: uuid index */ } else { for (uint8_t idx = 0; idx < UUID_128BIT_LEN; idx++) { osal_printk("[ssap client] structure uuid[%d]:[0x%02x]\r\n", idx, service->uuid.uuid[idx]); } } g_find_service_result.start_hdl = service->start_hdl; g_find_service_result.end_hdl = service->end_hdl; memcpy_s(&g_find_service_result.uuid, sizeof(sle_uuid_t), &service->uuid, sizeof(sle_uuid_t));}void sle_sample_find_property_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_property_result_t *property, errcode_t status){ osal_printk("[ssap client] find property cbk, client id: %d, conn id: %d, operate indication: %d, " "descriptors count: %d status:%d.\n", client_id, conn_id, property->operate_indication, property->descriptors_count, status); for (uint16_t idx = 0; idx < property->descriptors_count; idx++) { osal_printk("[ssap client] find property cbk, descriptors type [%d]: 0x%02x.\n", idx, property->descriptors_type[idx]); } if (property->uuid.len == UUID_16BIT_LEN) { osal_printk("[ssap client] find property cbk, uuid: %02x %02x.\n", property->uuid.uuid[14], property->uuid.uuid[15]); /* 14 15: uuid index */ } else if (property->uuid.len == UUID_128BIT_LEN) { for (uint16_t idx = 0; idx < UUID_128BIT_LEN; idx++) { osal_printk("[ssap client] find property cbk, uuid [%d]: %02x.\n", idx, property->uuid.uuid[idx]); } }}void find_structure_cmp_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_structure_result_t *structure_result, errcode_t status){ osal_printk("[ssap client] find structure cmp cbk client id:%d status:%d type:%d uuid len:%d \r\n", client_id, status, structure_result->type, structure_result->uuid.len); if (structure_result->uuid.len == UUID_16BIT_LEN) { osal_printk("[ssap client] find structure cmp cbk structure uuid:[0x%02x][0x%02x]\r\n", structure_result->uuid.uuid[14], structure_result->uuid.uuid[15]); /* 14 15: uuid index */ } else { for (uint8_t idx = 0; idx < UUID_128BIT_LEN; idx++) { osal_printk("[ssap client] find structure cmp cbk structure uuid[%d]:[0x%02x]\r\n", idx, structure_result->uuid.uuid[idx]); } } uint8_t data[] = {0xAA, 0xBB, 0xCC, 0xDD}; uint8_t len = sizeof(data); ssapc_write_param_t param = {0}; param.handle = g_find_service_result.start_hdl; param.type = SSAP_PROPERTY_TYPE_VALUE; param.data_len = len; param.data = data; ssapc_write_req(0, conn_id, ¶m);}void sle_sample_write_cfm_cbk(uint8_t client_id, uint16_t conn_id, ssapc_write_result_t *write_result, errcode_t status){ osal_printk("[ssap client] write cfm cbk, client id: %d status:%d.\n", client_id, status); ssapc_read_req(0, conn_id, write_result->handle, write_result->type);}void sle_sample_read_cfm_cbk(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *read_data, errcode_t status){ osal_printk("[ssap client] read cfm cbk client id: %d conn id: %d status: %d\n", client_id, conn_id, status); osal_printk("[ssap client] read cfm cbk handle: %d, type: %d , len: %d\n", read_data->handle, read_data->type, read_data->data_len); for (uint16_t idx = 0; idx < read_data->data_len; idx++) { osal_printk("[ssap client] read cfm cbk[%d] 0x%02x\r\n", idx, read_data->data[idx]); }}void ssap_cbk_config(void){ ssapc_callbacks.exchange_info_cb = exchange_info_cbk; ssapc_callbacks.find_structure_cb = sle_sample_find_structure_cbk; ssapc_callbacks.ssapc_find_property_cbk = sle_sample_find_property_cbk; ssapc_callbacks.find_structure_cmp_cb = find_structure_cmp_cbk; ssapc_callbacks.write_cfm_cb = sle_sample_write_cfm_cbk; ssapc_callbacks.read_cfm_cb = sle_sample_read_cfm_cbk;}//-------------------------ssap----------------------------//void *sle_init(void){ sle_seek_cbk_config(); sle_announce_seek_register_callbacks(&sle_announce_seek_callbacks); sle_connection_cbk_config(); sle_connection_register_callbacks(&sle_connection_callbacks); ssap_cbk_config(); ssapc_register_callbacks(&ssapc_callbacks); enable_sle(); return NULL;}static void sle_uuid_client_entry(void){ osal_task *task_handle = NULL; osal_kthread_lock(); task_handle= osal_kthread_create((osal_kthread_handler)sle_init, 0, "sle_gatt_client", SLE_UUID_CLIENT_STACK_SIZE); if (task_handle != NULL) { osal_kthread_set_priority(task_handle, SLE_UUID_CLIENT_TASK_PRIO); osal_kfree(task_handle); } osal_kthread_unlock();}/* Run the app entry. */app_run(sle_uuid_client_entry);