大联大控股世平集团WPI-NXP S32K312 DVK核心板(三)
·
(五)基于大联大控股世平集团WPI-NXP S32K312 DVK核心板&海思Hi2821E星闪SLE技术的星闪车钥匙介绍

关于星闪

星闪目标是推动新一代无线短距通信技术 NearLink 的创新和产业生态,该技术可满足智能汽车、工业智造、智慧家庭、个人穿戴等多场景对低时延、高可靠、精同步、多并发的技术需求。
星闪1.0 标准共由 12 项标准组成,包括接入层、基础服务层、通用(架构、标识等)、安全以及测试等部分。
关于星闪SLE协议
星闪SLE协议 (SparkLink Low Energy)是星闪联盟推出的新一代近距离无线连接技术,专为IoT应用场景设计,特别是汽车数字钥匙等应用。
星闪SLE协议具有以下主要特点:
- 高精度定位:能够实现分米级的精准测距,相较于传统蓝牙RSSI定位的2-5米测距精度,实现了巨大突破。
- 低延时和高带宽:支持12Mbps的传输速率和250μs的时延,适用于低功耗设备接入。
- 抗干扰能力:使用了5G同款的Polar码 ,显著提高了抗干扰能力。
星闪SLE协议的应用场景包括:
- 汽车数字钥匙:在车钥匙的多锚点组网架构中,星闪SLE凭借其高带宽和低时延,能够实现更高效的数据传输和更快速的响应,提升用户体验。
- 智能家居产品:如华为Q7路由器搭载的星闪网关,主要服务于星闪协议的智能家居产品。
小熊派 BearPi-BM H21E

产品概述
- 产品名称:BearPi-BM H21E
- 产品功能:BearPi-BM H21E是一款基于高度集成 2.4GHz SoC BLE&SLE为主控芯片的核心板,具有灵活的数字接口,IO口可复用为任意功能,集成高性能 32bit 微处理器(MCU),硬件安全引擎以及丰富的外设接口,外设接口包括 SPI、UART、I2C、PWM、GPIO、USB2.0、NFC Tag、PDM、I2S/PCM、QDEC、KEYSCAN 键盘扫描电路,支持 8 路 13bit 分辨率 ADC、ADC 支持对接音频 AMIC,内置 SRAM 和合封 Flash,并支持在 Flash 上运行程序。
- 目标用户群体:企业开发者
产品特点
- 支持 BLE4.0/4.1/4.2/5.0/5.1/5.2/5.3/5.4 和 SLE1.0 双模共存
- RISC-V 高性能 32bit CPU,最大主频支持 64MHz,支持浮点,支持 SWD。
- 内置 160KB的SRAM和1MB的Flash。
- 支持加密:AES(Advanced Encryption Standard)、SM4 和 TRNG(True Random Number Generator)
- 支持丰富的对外接口
- AFE(Analog Front-End)
- 传感器通路(General Analog Front-End):支持 8 ch 13bit 1.6Msps SAR ADC,支持单端/差分/扫描模式,支持过采样和 buf 功能。
- 音频通路(Audio Analog Front-End):支持复用 13bit SAR ADC,降采 样到 16ksps/8ksps;支持 40dB 倍放大。
- 支持 2×I2C(The Inter-Integrated Circuit),可配置为 Master 和 Slave。
- 支持 1 路 2 通道 I2S(Integrated Interchip Sound)/PCM( Pulse Code Modulation)。
- 支持 2 通道 PDM(Pulse Density Modulation)接口。
- 支持 3×SPI(Serial Peripheral Interface),支持 master 和 slave 模式可配。
- 支持 3×UART(Universal Asynchronous Receiver-Transmitter ),最大速率 4Mbit/s,其中 2 个 4 线 UART。
- 支持 6×PWM(Pulse Width Modulation)。
- 支持 USB2.0(Universal Serial Bus),支持 FS/HS mode,最大支持 480Mbit/s。
- 支持 NFC Type2 Tag 功能,支持 NFC 场唤醒功能。
- 支持 QDEC(QuaDrature EnCoding )接口。
- 支持 KeyScan 功能。
- 支持 29 个 GPIO(General-Purpose Input/Output)。
功能接口

| 编号 | 功能 | 说明 |
|---|---|---|
| 1 | 2.4G 天线 | BLE 和 SLE 天线 |
| 2 | 主控芯片 | BS21E(H2821E), RISC-V 高性能 32bit CPU,最大主频支持 64MHz,支持 BLE 和 SLE 双模共存,支持浮点,支持 SWD。 |
| 3 | 状态灯 | 慢闪:进入AT模式;快闪:进入测距模式;双闪:测距模式下设备已配对 |
引脚定义

| Pins | Group | IO功能 | 模拟复用 | 数字复用 |
|---|---|---|---|---|
| 1 | GPIO25 | 全功能路由 | O32M | - |
| 2 | GPIO26 | 全功能路由 | - | - |
| 3 | GPIO27 | 全功能路由 | - | - |
| 4 | GPIO28 | 全功能路由 | AIN4 | - |
| 5 | GPIO29 | 全功能路由 | AIN5 | - |
| 6 | GPIO30 | 全功能路由 | AIN6 | - |
| 7 | GPIO0 | 全功能路由 | - | XL1 |
| 8 | GPIO1 | 全功能路由 | - | XL2 |
| 9 | GPIO2 | 全功能路由 | AIN0 | - |
| 10 | GPIO3 | 全功能路由 | AIN1 | - |
| 11 | NC | - | - | - |
| 12 | MIC_LDO | MIC LDO | - | - |
| 13 | GPIO7 | 全功能路由 | - | USB DP |
| 14 | GPIO8 | 全功能路由 | - | USB DM |
| 15 | GND | 电源地 | - | - |
| 16 | VIN | 3.3V输入 | - | - |
| 17 | RESET | 复位 | - | - |
| 18 | GPIO6 | 全功能路由 | - | - |
| 19 | GPIO11 | 全功能路由 | - | 高速 SPI_TXD |
| 20 | GPIO12 | 全功能路由 | - | 高速 SPI_RXD |
| 21 | GPIO19 | 调试串口 | - | - |
| 22 | GPIO20 | 调试串口 | - | - |
| 23 | GPIO9 | 全功能路由 | NFC1 | - |
| 24 | GPIO10 | 全功能路由 | NFC2 | - |
| 25 | GPIO4 | 全功能路由 | AIN2 | - |
| 26 | GPIO5 | 全功能路由 | AIN3 | - |
| 27 | GPIO13 | 全功能路由 | - | 高速 SPI_CS |
| 28 | GPIO14 | 全功能路由 | - | 高速 SPI_CLK |
| 29 | GPIO15 | 全功能路由 | - | - |
| 30 | GPIO16 | 全功能路由 | - | - |
| 31 | GPIO17 | 全功能路由 | - | - |
| 32 | GPIO18 | 全功能路由 | - | - |
| 33 | GPIO21 | 全功能路由 | - | - |
| 34 | SWCLK | SWD | - | - |
| 35 | SWDIO | SWD | - | - |
| 36 | GND | 电源地 | - | - |
注:
- “全功能路由”代表该 GPIO 管脚可复用为任意功能。
- "模拟复用”,“数字复用”,代表该功能下,管脚不可更改。
- 请勿在上电之前将GPIO2、GPIO3、GPIO4、GPIO5、GPIO25、GPIO28、GPIO29、GPIO30这几个引脚上拉,否则会导致芯片无法正常启动。
项目目的
本项目旨在将NXP车规级MCU S32K312丰富的车载接口、功能安全能力与海思Hi2821E星闪SLE技术的低功耗、厘米级测距、抗多径及高安全加密特性深度融合,打造新一代“星闪数字车钥匙”参考设计。实现国产化、低成本、高性能的车钥匙方案,推动星闪生态在汽车电子领域的发展。
项目目标
本项目计划基于大联大控股世平集团WPI-NXP S32K312 DVK核心板与海思Hi2821E模组完成星闪车钥匙原型开发并完成在车端部署单一星闪锚点。可实现星闪车钥匙对车端单一锚点的秒级解锁、3米迎宾、10米身份识别的分段式无感体验。
(六)基于海思Hi2821E星闪SLE技术的星闪车钥匙设计
基于海思Hi2821E星闪SLE技术的星闪车钥匙硬件设计
BOM表
| 序号 | 器件 | 位号 | 封装 | 值 |
|---|---|---|---|---|
| 1 | BS-06-B4AA002 | BT1 | BAT-SMD_BS-06-B4BK006-1 | |
| 2 | 10uF | C1,C2 | C0805 | 10uF |
| 3 | 22uF | C3 | C0805 | 22uF |
| 4 | PZ254V-11-02P | H1 | HDR-TH_2P-P2.54-V-M | |
| 5 | BearPi EBM H21E | H2821E | BearPi EBM H21E | |
| 6 | NCD0805R1 | LED1 | LED0805-R-RD | |
| 7 | 1kΩ | R1 | R0805 | 1kΩ |
| 8 | M2螺丝 | SCREW1,SCREW2,SCREW3,SCREW4 | M2螺丝 | |
| 9 | SK-12E12-G5 | SW1 | SW-TH_SK-12E12-G5 | |
| 10 | TS665CJ | SW2,SW3,SW4 | SW-TH_4P-L6.0-W6.0-P4.50-LS6.5 | |
| 11 | AMS1117-3.3 | U1 | SOT-223-3_L6.5-W3.4-P2.30-LS7.0-BR | |
| 12 | KH-TYPE-C-2P | USB1 | USB-SMD_KH-TYPE-C-2P |
原理图

外观

基于海思Hi2821E星闪SLE技术的星闪车钥匙软件设计
软件设计结构
.├── NearLinkSLEKey
│ ├── NearLinkSLEKey.c
│ ├── sle_measure_dis_client
│ │ ├── sle_measure_dis_client.c
│ │ ├── sle_measure_dis_client.h
│ │ ├── sle_measure_dis_client_slem.c
│ │ └── sle_measure_dis_client_slem.h
│ ├── Kconfig
│ └── CMakeLists.txt
└──────────────────────────────────────────
NearLinkSLEKey.c
/**
* Copyright (c) BI1NDF 2025-2025. All rights reserved.
*
* Description: NearLink_SLE_Key. \n
*
* History: \n
* 2025-08-25, Create file. \n
*/
#include "boards.h"
#include "pinctrl.h"
#include "gpio.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"
#include "soc_osal.h"
#include "common_def.h"
#include "app_init.h"
#include "sle_measure_dis_client/sle_measure_dis_client.h"
#define TASK_PRIORITY_HADM 27
#define STACK_SIZE_BASELINE 0x200
#define BTH_HADM_SERVICE_STACK_SIZE (STACK_SIZE_BASELINE * 4 + 0x200)
extern int carkey_send_open_cmd(void);
extern int carkey_send_close_cmd(void);
extern int carkey_send_trunk_cmd(void);
static void open_callback_func(pin_t pin, uintptr_t param)
{
UNUSED(pin);
UNUSED(param);
osal_printk("OPEN BUTTON.\r\n");
carkey_send_open_cmd();
}
static void close_callback_func(pin_t pin, uintptr_t param)
{
UNUSED(pin);
UNUSED(param);
osal_printk("CLOSE BUTTON.\r\n");
carkey_send_close_cmd();
}
static void trunk_callback_func(pin_t pin, uintptr_t param)
{
UNUSED(pin);
UNUSED(param);
osal_printk("TRUNK BUTTON.\r\n");
carkey_send_trunk_cmd();
}
static void button_entry(void)
{
osal_printk("Init BUTTON.\r\n");
uapi_pin_set_mode(CONFIG_OPEN_PIN, HAL_PIO_FUNC_GPIO);
uapi_pin_set_mode(CONFIG_CLOSE_PIN, HAL_PIO_FUNC_GPIO);
uapi_pin_set_mode(CONFIG_TRUNK_PIN, HAL_PIO_FUNC_GPIO);
uapi_pin_set_pull(CONFIG_OPEN_PIN, PIN_PULL_UP);
uapi_pin_set_pull(CONFIG_CLOSE_PIN, PIN_PULL_UP);
uapi_pin_set_pull(CONFIG_TRUNK_PIN, PIN_PULL_UP);
uapi_gpio_set_dir(CONFIG_OPEN_PIN, GPIO_DIRECTION_INPUT);
uapi_gpio_set_dir(CONFIG_CLOSE_PIN, GPIO_DIRECTION_INPUT);
uapi_gpio_set_dir(CONFIG_TRUNK_PIN, GPIO_DIRECTION_INPUT);
uapi_gpio_register_isr_func(CONFIG_OPEN_PIN, GPIO_INTERRUPT_DEDGE, open_callback_func);
uapi_gpio_register_isr_func(CONFIG_CLOSE_PIN, GPIO_INTERRUPT_DEDGE, close_callback_func);
uapi_gpio_register_isr_func(CONFIG_TRUNK_PIN, GPIO_INTERRUPT_DEDGE, trunk_callback_func);
}
void sle_measure_dis_client_task(void)
{
uint32_t ret;
ret = measure_dis_client_init();
check_rc_return_rc(ret, "con sle_measure_dis_client_init");
}
static void slemeasure_entry(void)
{
osal_printk("Init SLE MEASURE.\r\n");
osal_task *task_handle = NULL;
osal_kthread_lock();
task_handle = osal_kthread_create((osal_kthread_handler)sle_measure_dis_client_task,
0, "SLEMeasureDisClient", BTH_HADM_SERVICE_STACK_SIZE);
if (task_handle != NULL) {
osal_kthread_set_priority(task_handle, TASK_PRIORITY_HADM);
osal_kfree(task_handle);
}
osal_kthread_unlock();
}
/* Run the entry. */
app_run(button_entry);
app_run(slemeasure_entry);
sle_measure_dis_client.c
/**
* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
*
* Description: SLE uart sample of client. \n
*
* History: \n
* 2023-04-03, Create file. \n
* 2025-08-27, Add Button for Key. \n
*/
#include "sle_measure_dis_client.h"
#include "sle_errcode.h"
#include "sle_common.h"
#include "sle_device_manager.h"
#include "sle_connection_manager.h"
#include "sle_device_manager.h"
#include "sle_device_discovery.h"
#include "sle_ssap_client.h"
#include "sle_hadm_manager.h"
#include "cmsis_os2.h"
#include "sle_measure_dis_client_slem.h"
uint8_t iq_msg_buff[sizeof(measure_ids_msg_t) + sizeof(measure_dis_stored_iq_data_t)];
#define BLE_SLE_TAG_TASK_DURATION_MS 10
#define ADV_TO_SERVER 2
/* UUID只支持2字节和16字节 */
#define SLEM_UUID_LEN SLE_UUID_LEN
#define KEY_CONNECT_DELAY_TIME 500
#define SLEM_IQ_DATALEN 512
static uint8_t g_stack_enable_status = 0;
uint8_t g_measure_dis_server_addr[SLE_ADDR_LEN] = { 1, 1, 1, 1, 1, 1 };
uint8_t g_measure_dis_client_addr[SLE_ADDR_LEN] = { 2, 2, 2, 2, 2, 2 };
uint8_t g_measure_dis_conn_id = SLEM_CONNET_INVAILD;
measure_dis_server_data_t g_measure_dis_server_data = {
.server_uuid = {0x11, 0x22, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
.service_uuid = {0x11, 0x33, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
.property_uuid = {0x11, 0x44, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
};
int carkey_send_open_cmd(void)
{
if (g_measure_dis_conn_id == SLEM_CONNET_INVAILD) {
osal_printk("SLE not connected, drop OPEN cmd.\r\n");
return -1;
}
return measure_dis_client_write_server(0xA1,(uint8_t *)"OPEN",strlen("OPEN"));
}
int carkey_send_close_cmd(void)
{
if (g_measure_dis_conn_id == SLEM_CONNET_INVAILD) {
osal_printk("SLE not connected, drop CLOSE cmd.\r\n");
return -1;
}
return measure_dis_client_write_server(0xA1,(uint8_t *)"CLOSE",strlen("CLOSE"));
}
int carkey_send_trunk_cmd(void)
{
if (g_measure_dis_conn_id == SLEM_CONNET_INVAILD) {
osal_printk("SLE not connected, drop TRUNK cmd.\r\n");
return -1;
}
return measure_dis_client_write_server(0xA1,(uint8_t *)"TRUNK",strlen("TRUNK"));
}
errcode_t measure_dis_slem_set_param(uint16_t conn_id)
{
sle_set_channel_sounding_param_ex_t param = {
.acb_interval = 0,
.con_anchor_num = 1,
.cs_interval = 1,
.freq_space = 0,
.is_cs_param_chg = 0,
.refresh_rate = 1,
};
errcode_t ret = sle_set_channel_sounding_param_ex(conn_id, ¶m);
if ((ret != ERRCODE_SUCC) || (conn_id == SLEM_CONNET_INVAILD)) {
osal_printk("slem set param failed, ret = %d.\n", ret);
}
osal_printk("slem set param finish. refresh_rate:%d \n", param.refresh_rate);
return ERRCODE_SUCC;
}
errcode_t measure_dis_slem_set_enable(uint16_t conn_id)
{
osal_printk("SLEM SET ENABLE conn_id:%x.\r\n", conn_id);
errcode_t ret = sle_set_channel_sounding_enable(conn_id);
/* 解决测距使能之后,马上断链导致没有底层回调 */
if ((ret != ERRCODE_SUCC) || (conn_id == SLEM_CONNET_INVAILD)) {
osal_printk("slem set enable failed, ret = %d.\n", ret);
}
return ERRCODE_SUCC;
}
static int measure_dis_client_discover_key(uint8_t type)
{
uint32_t ret = ERRCODE_SLE_FAIL;
uint8_t conn_id = g_measure_dis_conn_id;
ssapc_find_structure_param_t param = {0};
param.type = type,
param.start_hdl = 1,
param.end_hdl = 0xFFFF,
param.uuid.len = SLEM_UUID_LEN;
if (type == SSAP_FIND_TYPE_PRIMARY_SERVICE) {
if (memcpy_s(param.uuid.uuid, SLEM_UUID_LEN,
g_measure_dis_server_data.service_uuid, SLEM_UUID_LEN) != EOK) {
return ERRCODE_MEMCPY;
}
} else if (type == SSAP_FIND_TYPE_PROPERTY) {
if (memcpy_s(param.uuid.uuid, SLEM_UUID_LEN,
g_measure_dis_server_data.property_uuid, SLEM_UUID_LEN) != EOK) {
return ERRCODE_MEMCPY;
}
}
ret = ssapc_find_structure(0, conn_id, ¶m);
osal_printk("SLE START CLIENT DISCOVER SERVER. conn_id:%d, ret:%d \r\n", conn_id, ret);
return ret;
}
static void measure_dis_cm_conn_state_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)
{
unused(pair_state);
unused(addr);
unused(disc_reason);
if (conn_state == SLE_ACB_STATE_CONNECTED) {
osal_printk("Connected. conn_id:%d\r\n", conn_id);
g_measure_dis_conn_id = conn_id;
osal_msleep(MEASURE_DIS_NUM_CARRY_1000);
measure_dis_client_discover_key(SSAP_FIND_TYPE_PROPERTY);
ssap_exchange_info_t info = { 0 };
info.mtu_size = SLEM_IQ_DATALEN;
info.version = 1;
ssapc_exchange_info_req(0, conn_id, &info);
(void)osDelay(KEY_CONNECT_DELAY_TIME);
measure_dis_slem_set_param(conn_id);
(void)osDelay(KEY_CONNECT_DELAY_TIME);
measure_dis_slem_set_enable(conn_id);
} else if (conn_state == SLE_ACB_STATE_DISCONNECTED) {
osal_printk("Disconnected disc_reason:0x%x .\r\n", disc_reason);
g_measure_dis_conn_id = SLEM_CONNET_INVAILD;
measure_dis_start_scan();
}
}
errcode_t measure_dis_cm_register_cbks(void)
{
sle_connection_callbacks_t cm_cbks = { 0 };
cm_cbks.connect_state_changed_cb = measure_dis_cm_conn_state_cbk;
cm_cbks.connect_param_update_req_cb = NULL;
cm_cbks.connect_param_update_cb = NULL;
cm_cbks.auth_complete_cb = NULL;
cm_cbks.pair_complete_cb = NULL;
cm_cbks.read_rssi_cb = NULL;
return sle_connection_register_callbacks(&cm_cbks);
}
static void measure_dis_dd_enable_cbk(uint8_t status)
{
osal_printk("sle enable result statue:0x%x .\r\n", status);
g_stack_enable_status = 1;
}
static void measure_dis_dd_disenable_cbk(uint8_t status)
{
osal_printk("sle disable result statue:0x%x .\r\n", status);
g_stack_enable_status = 0;
}
static void measure_dis_dd_seek_result_cbk(sle_seek_result_info_t *seek_result_data)
{
if (seek_result_data == NULL) {
return;
}
if ((memcmp(g_measure_dis_server_addr, seek_result_data->addr.addr, SLE_ADDR_LEN) == 0)) {
sle_stop_seek();
sle_connect_remote_device(&(seek_result_data->addr));
}
}
errcode_t measure_dis_dm_register_cbks(void)
{
sle_dev_manager_callbacks_t dm_cbks = {
.sle_power_on_cb = NULL,
.sle_enable_cb = measure_dis_dd_enable_cbk,
.sle_disable_cb = measure_dis_dd_disenable_cbk,
};
return sle_dev_manager_register_callbacks(&dm_cbks);
}
errcode_t measure_dis_dd_register_cbks(void)
{
sle_announce_seek_callbacks_t dd_cbks = {
.announce_enable_cb = NULL,
.announce_disable_cb = NULL,
.announce_terminal_cb = NULL,
.seek_enable_cb = NULL,
.seek_disable_cb = NULL,
.seek_result_cb = measure_dis_dd_seek_result_cbk,
};
return sle_announce_seek_register_callbacks(&dd_cbks);
}
STATIC void measure_dis_ssapc_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 cbk start_hdl: %d end_hdl:%d \n",
service->start_hdl, service->end_hdl);
g_measure_dis_server_data.begin_hdl= service->start_hdl;
g_measure_dis_server_data.end_hdl = service->end_hdl;
}
STATIC void measure_dis_ssapc_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: %d conn_id:%d status: %d \n",
client_id, conn_id, status);
osal_printk("[ssap client] find property cbk handle: %d \n", property->handle);
g_measure_dis_server_data.property_handle = property->handle;
}
STATIC void measure_dis_ssapc_find_structure_complete_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 complete cbk client: %d conn_id:%d status: %d \n",
client_id, conn_id, status);
if (structure_result == NULL) {
return;
}
osal_printk("SERVICES DISCOVER COMPLETE. \r\n");
}
void measure_dis_client_msg_proc(uint8_t *data, uint16_t data_len)
{
unused(data_len);
uint32_t ret = ERRCODE_SLE_FAIL;
measure_ids_msg_t *slem_profile_msg = (measure_ids_msg_t *)(data);
switch (slem_profile_msg->type) {
case SLEM_PROFILE_MSG_IQ:
break;
default:
for (int i = 0; i < data_len; i++) {
osal_printk("[%d]:%d\r\n", i, data[i]);
}
break;
}
if (unlikely(ret != ERRCODE_SLE_SUCCESS)) {
osal_printk("client proc msg failed MSG_TYPE:0x%x ret:0x%x \r\n", slem_profile_msg->type, ret);
}
}
/**
* @brief 数据通知处理函数
*/
STATIC void measure_dis_ssapc_notification_cbk(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
errcode_t status)
{
unused(client_id);
unused(status);
osal_printk("[ssap client] notification info cbk client handle:%d, conn_id:0x%x, data_len:0x%x\n",
data->handle, conn_id, data->data_len);
measure_dis_client_msg_proc(data->data, data->data_len);
}
/**
* @brief 数据指示处理函数
*/
STATIC void measure_dis_ssapc_indication_cb(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
errcode_t status)
{
unused(client_id);
osal_printk("[ssap client] indication info cbk client %d,mtu_size:%d, version:0x%x, status:0x%x\n",
conn_id, data->handle, data->type, status);
}
/**
* @brief MTU信息交换响应处理函数
*/
STATIC void measure_dis_ssapc_exchange_info_cbk(uint8_t client_id, uint16_t conn_id, ssap_exchange_info_t *param,
errcode_t status)
{
unused(client_id);
osal_printk("[ssap client] exchange info cbk client %d,mtu_size:%d, version:0x%x, status:0x%x\n",
conn_id, param->mtu_size, param->version, status);
}
errcode_t measure_dis_ssapc_register_cbks(void)
{
ssapc_callbacks_t ssapc_cbks;
osal_printk("[ssap client] client register cbk\r\n");
/* 服务发现模块回调函数 */
ssapc_cbks.find_structure_cb = measure_dis_ssapc_find_structure_cbk;
ssapc_cbks.ssapc_find_property_cbk = measure_dis_ssapc_find_property_cbk;
ssapc_cbks.find_structure_cmp_cb = measure_dis_ssapc_find_structure_complete_cbk;
ssapc_cbks.read_cfm_cb = NULL;
ssapc_cbks.read_by_uuid_cmp_cb = NULL;
ssapc_cbks.write_cfm_cb = NULL;
ssapc_cbks.exchange_info_cb = measure_dis_ssapc_exchange_info_cbk;
ssapc_cbks.notification_cb = measure_dis_ssapc_notification_cbk;
ssapc_cbks.indication_cb = measure_dis_ssapc_indication_cb;
return ssapc_register_callbacks(&ssapc_cbks);
}
errcode_t measure_dis_set_local_addr(uint8_t *addr)
{
sle_addr_t sle_addr = {0};
if (memcpy_s(sle_addr.addr, SLE_ADDR_LEN, addr, SLE_ADDR_LEN) != EOK) {
return ERRCODE_MEMCPY;
};
return sle_set_local_addr(&sle_addr);
}
errcode_t measure_dis_set_local_name(uint8_t *name, uint8_t len)
{
return sle_set_local_name(name, len);
}
void measure_dis_protocol_stack_init(uint8_t *addr, uint8_t *name)
{
uint32_t ret = ERRCODE_SLE_SUCCESS;
ret |= measure_dis_dm_register_cbks();
ret |= measure_dis_cm_register_cbks();
ret |= measure_dis_dd_register_cbks();
ret = enable_sle();
while (g_stack_enable_status != 1) {
osal_msleep(BLE_SLE_TAG_TASK_DURATION_MS);
}
measure_dis_set_local_addr(addr);
measure_dis_set_local_name(name, strlen((char *)name));
}
static int measure_dis_client_write_proc(uint8_t type, uint16_t len, uint8_t *data)
{
errcode_t ret = ERRCODE_FAIL;
ssapc_write_param_t param = {0};
uint8_t conn_id = g_measure_dis_conn_id;
param.handle = g_measure_dis_server_data.property_handle;
param.type = type;
param.data_len = len;
param.data = data;
ret = ssapc_write_cmd(0, conn_id, ¶m);
if (ret != ERRCODE_SUCC) {
osal_printk("CLIENT SEND (KEY) FAIL. cid:%d, handle:%d \r\n", conn_id, param.handle);
}
return ret;
}
int measure_dis_client_write_server(uint32_t type, uint8_t *data, uint32_t data_len)
{
uint32_t ret = ERRCODE_SUCC;
uint16_t len = sizeof(measure_ids_msg_t) + data_len;
osal_printk("client send to server, len:0x%x.\r\n", len);
measure_ids_msg_t *slem_msg = (measure_ids_msg_t *)osal_kmalloc(len, 0);
if (slem_msg == NULL) {
return ERRCODE_MALLOC;
}
slem_msg->type = type;
slem_msg->len = data_len;
if (memcpy_s(slem_msg->data, data_len, data, data_len) != EOK) {
osal_kfree(slem_msg);
return ERRCODE_MEMCPY;
}
ret = measure_dis_client_write_proc(0, len, (uint8_t *)(slem_msg));
if (ret != ERRCODE_SUCC) {
osal_printk("client send to server failed.\n");
}
osal_kfree(slem_msg);
return ret;
}
errcode_t measure_dis_set_scan(void)
{
errcode_t ret;
sle_seek_param_t param = {0};
param.own_addr_type = 0;
param.filter_duplicates = 1;
param.seek_filter_policy = 1;
param.seek_phys = 1;
param.seek_type[0] = 1;
param.seek_interval[0] = 0x12c0;
param.seek_window[0] = 0x500;
ret = sle_set_seek_param(¶m);
return ret;
}
int measure_dis_start_scan(void)
{
errcode_t ret;
ret = measure_dis_set_scan();
if (ret != ERRCODE_SLE_SUCCESS) {
return ret;
}
ret = sle_start_seek();
if (ret != ERRCODE_SLE_SUCCESS) {
return ret;
}
return ERRCODE_SLE_SUCCESS;
}
int measure_dis_client_init(void)
{
uint32_t ret = ERRCODE_SLE_SUCCESS;
uint8_t measure_dis_name[SLE_NAME_MAX_LEN] = {'s', 'l', 'e', 'm', '-', 'c', '\0'};
osal_printk("START CLIENT INIT .\r\n");
measure_dis_protocol_stack_init(g_measure_dis_client_addr, measure_dis_name);
measure_dis_reg_callbacks();
ret = measure_dis_ssapc_register_cbks();
measure_dis_start_scan();
return ret;
}
/* 钥匙 */
// btc回调函数
// lm_gle_rssi_info_cb(uint16_t conn_id, int8_t rssi)
void carkey_sle_rssi_report_cbk(uint16_t conn_id, int8_t rssi)
{
osal_printk("SLE RSSI REPORT conn_id:%d, rssi:%d .\r\n", conn_id, rssi);
}
sle_measure_dis_client.h
/**
* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
*
* Description: SLE MEASURE_DIS sample of client. \n
*
* History: \n
* 2023-04-03, Create file. \n
*/
#ifndef SLE_MEASURE_DIS_CLIENT_H
#define SLE_MEASURE_DIS_CLIENT_H
#include <stdint.h>
#include <securec.h>
#include "errcode.h"
#include "std_def.h"
#include "soc_osal.h"
#include "common_def.h"
#include "sle_ssap_client.h"
#define MEASURE_DIS_NUM_CARRY_10_7 10000000
#define MEASURE_DIS_NUM_CARRY_1000 1000
#define MEASURE_DIS_NUM_CARRY_100 100
#define MEASURE_DIS_NUM_CARRY_10 10
#define MEASURE_DIS_NUM_CARRY_2 2
#define SLEM_CONNET_INVAILD 0xFF
typedef enum {
SLEM_PROFILE_MSG_IQ = 0xFFFFFFEA,
} slem_profile_msg_type_t;
typedef struct {
uint32_t type; /*!< 消息类型 */
uint32_t len; /*!< 消息类型 */
uint8_t data[0];
} measure_ids_msg_t;
typedef struct server_data {
uint8_t property_uuid[SLE_UUID_LEN];
uint8_t server_uuid[SLE_UUID_LEN];
uint8_t service_uuid[SLE_UUID_LEN];
uint16_t begin_hdl;
uint16_t end_hdl;
uint16_t property_handle;
} measure_dis_server_data_t;
#define check_rc_return_rc(rc, err) \
do { \
if ((rc) != ERRCODE_SUCC) { \
osal_printk("CARKEY ERROR: %s fail!: call %s return 0x%x!\n", err, __FUNCTION__, rc); \
} \
} while (0)
int measure_dis_client_write_server(uint32_t type, uint8_t *data, uint32_t data_len);
int measure_dis_client_init(void);
int measure_dis_start_scan(void);
#endif
sle_measure_dis_client_slem.c
/**
* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
*
* Description: SLE uart sample of client. \n
*
* History: \n
* 2023-04-03, Create file. \n
*/
#include "sle_measure_dis_client.h"
#include "sle_errcode.h"
#include "sle_common.h"
#include "sle_ssap_client.h"
#include "sle_hadm_manager.h"
#include "cmsis_os2.h"
#include "sle_measure_dis_client_slem.h"
measure_dis_stored_iq_data_t g_local_iq_data;
uint8_t g_next_idx;
uint8_t g_store_local_iq_complete;
uint8_t g_iq_debug_flag = 0;
void measure_dis_print_iq_data(uint8_t num, uint8_t role, sle_channel_sounding_iq_trans_t *report)
{
if (!g_iq_debug_flag) {
return;
}
osal_printk("[iq_data]%d,%d,%d,%d,0x%x,",
num, role, report->timestamp_sn, report->samp_cnt, report->rssi);
sle_channel_sounding_qte_trans_t *data = report->data;
uint16_t i = 0;
while (i < POSALG_DATA_NUM) {
osal_printk("[%d]:0x%x,0x%x", i, data[i].i_data, data[i].q_data);
i++;
if (i == POSALG_DATA_NUM) {
osal_printk(".\r\n");
} else {
osal_printk(";");
}
}
}
errcode_t measure_dis_store_local_iq(sle_channel_sounding_iq_report_t *report)
{
if (report->report_idx == 0) {
g_local_iq_data.samp_cnt = 0;
g_local_iq_data.rssi = report->rssi[0];
g_local_iq_data.es_sn = report->es_sn;
g_local_iq_data.timestamp_sn = report->timestamp_sn;
#if (defined(GLE_CS_MODE3_SUPPORT))
g_local_iq_data.tof_result = report->tof_result;
#endif
g_next_idx = 0;
}
if ((report->report_idx >= MEASURE_DIS_IQ_REPORT_CNT_MAX || report->timestamp_sn != g_local_iq_data.timestamp_sn) ||
(g_next_idx != report->report_idx)) {
osal_printk("SLEM STORE LOCAL IQ FAIL. report_idx:%d, timestamp:%d, g_next_idx:%d. \r\n",
report->report_idx, report->timestamp_sn, g_next_idx);
return ERRCODE_INVALID_PARAM;
}
g_local_iq_data.samp_cnt += report->samp_cnt;
uint8_t offset = report->report_idx * SLE_CS_IQ_REPORT_COUNT;
for (uint8_t i = 0; i < report->samp_cnt; i++) {
g_local_iq_data.data[offset + i].i_data = report->i_data[i];
g_local_iq_data.data[offset + i].q_data = report->q_data[i];
}
osal_printk("local iq es:%d, time_stamp:%d group:%d, num:%d \r\n",
report->es_sn, report->timestamp_sn, report->report_idx, 0);
g_next_idx = report->report_idx + 1;
#if (defined(GLE_CS_MODE3_SUPPORT))
osal_printk("local tof_result = %d.%03d \r\n", report->tof_result / MEASURE_DIS_NUM_CARRY_1000,
report->tof_result % MEASURE_DIS_NUM_CARRY_1000);
#endif
return ERRCODE_SUCC;
}
errcode_t measure_dis_recv_local_iq(uint16_t conn_id, sle_channel_sounding_iq_report_t *report)
{
osal_printk("enter slem_recv_local_iq conn_id:%d. \r\n", conn_id);
errcode_t ret = ERRCODE_SUCC;
ret = measure_dis_store_local_iq(report);
if (ret != ERRCODE_SUCC) {
return ERRCODE_INVALID_PARAM;
}
if (report->report_idx + 1 == MEASURE_DIS_IQ_REPORT_CNT_MAX) {
/* 如果是钥匙则发送给从锚点 */
measure_dis_print_iq_data(0, 0, (sle_channel_sounding_iq_trans_t *)(&g_local_iq_data));
measure_dis_client_write_server(SLEM_PROFILE_MSG_IQ,
(uint8_t *)&g_local_iq_data, sizeof(sle_channel_sounding_iq_trans_t));
}
return ret;
}
void measure_dis_read_local_cs_caps_cb(sle_channel_sounding_caps_t *caps, errcode_t status)
{
UNUSED(caps);
osal_printk("SLEM READ LOCAL CAPS. status:%d. \r\n", status);
}
void measure_dis_read_remote_cs_caps_cb(uint16_t conn_id, sle_channel_sounding_caps_t *caps, errcode_t status)
{
UNUSED(caps);
UNUSED(conn_id);
osal_printk("SLEM READ REMOTE CAPS. status:%d. \r\n", status);
}
void measure_dis_set_cs_param_cb(uint16_t conn_id, errcode_t status)
{
UNUSED(conn_id);
osal_printk("SLEM SET PARAM. status:%d. \r\n", status);
}
void measure_dis_cs_state_changed_cb(uint8_t slem_status, errcode_t status)
{
unused(slem_status);
osal_printk("SLEM STATE CHANGED. status:%d. \r\n", status);
}
void measure_dis_cs_iq_report_cb(uint16_t conn_id, sle_channel_sounding_iq_report_t *report)
{
if (report->report_idx == 0) {
osal_printk("RECEIVE LOCAL IQ. timestamp_sn:%d \r\n", report->timestamp_sn);
}
measure_dis_recv_local_iq(conn_id, report);
}
errcode_t measure_dis_reg_callbacks(void)
{
sle_hadm_callbacks_t scd_cbks = {0};
scd_cbks.read_local_cs_caps_cb = measure_dis_read_local_cs_caps_cb;
scd_cbks.read_remote_cs_caps_cb = measure_dis_read_remote_cs_caps_cb;
scd_cbks.cs_state_changed_cb = measure_dis_cs_state_changed_cb;
scd_cbks.cs_iq_report_cb = measure_dis_cs_iq_report_cb;
errcode_t ret = sle_hadm_register_callbacks(&scd_cbks);
osal_printk("SCD SET CALLBACK DONE. ret = %x.\r\n", ret);
return ret;
}
sle_measure_dis_client_slem.h
/**
* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
*
* Description: SLE MEASURE_DIS sample of client. \n
*
* History: \n
* 2023-04-03, Create file. \n
*/
#ifndef SLE_MEASURE_DIS_CLIENT_SLEM_H
#define SLE_MEASURE_DIS_CLIENT_SLEM_H
#include "sle_measure_dis_client_slem.h"
#include "sle_hadm_manager.h"
#define MEASURE_DIS_IQ_REPORT_CNT_MAX 1
#define POSALG_DATA_NUM 79
#define IQ_DATA_MAX (MEASURE_DIS_IQ_REPORT_CNT_MAX * SLE_CS_IQ_REPORT_COUNT)
typedef struct {
uint16_t i_data;
uint16_t q_data;
} measure_dis_stored_qte_trans_t;
typedef struct {
uint8_t samp_cnt;
uint8_t rssi;
uint16_t es_sn;
uint32_t timestamp_sn;
measure_dis_stored_qte_trans_t data[IQ_DATA_MAX];
#if (defined(GLE_CS_MODE3_SUPPORT))
uint32_t tof_result;
#endif
} measure_dis_stored_iq_data_t;
typedef struct {
uint16_t i_data;
uint16_t q_data;
} sle_channel_sounding_qte_trans_t;
typedef struct {
uint8_t samp_cnt;
uint8_t rssi;
uint16_t es_sn;
uint32_t timestamp_sn;
sle_channel_sounding_qte_trans_t data[IQ_DATA_MAX];
uint32_t tof_result;
} sle_channel_sounding_iq_trans_t;
errcode_t measure_dis_reg_callbacks(void);
#endif
Kconfig
#===============================================================================
# @brief Kconfig file.
# Copyright (c) BI1NDF 2025-2025. All rights reserved.
#===============================================================================
config OPEN_PIN
int
prompt "Choose OPEN pin."
depends on SAMPLE_SUPPORT_NEARLINKSLEKEY
default 15
config CLOSE_PIN
int
prompt "Choose CLOSE pin."
depends on SAMPLE_SUPPORT_NEARLINKSLEKEY
default 16
config TRUNK_PIN
int
prompt "Choose TRUNK pin."
depends on SAMPLE_SUPPORT_NEARLINKSLEKEY
default 17
CMakeLists.txt
#===============================================================================
# @brief cmake file
# Copyright (c) BI1NDF 2025-2025. All rights reserved.
#===============================================================================
set(SOURCES_LIST
${CMAKE_CURRENT_SOURCE_DIR}/sle_measure_dis_client/sle_measure_dis_client.c
${CMAKE_CURRENT_SOURCE_DIR}/sle_measure_dis_client/sle_measure_dis_client_slem.c
${CMAKE_CURRENT_SOURCE_DIR}/NearLinkSLEKey.c
)
set(HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/sle_measure_dis_client)
set(SOURCES "${SOURCES}" ${SOURCES_LIST} PARENT_SCOPE)
set(PUBLIC_HEADER "${PUBLIC_HEADER}" ${HEADER_LIST} PARENT_SCOPE)
基于海思Hi2821E星闪SLE技术的星闪车钥匙实物


更多推荐

所有评论(0)