接上一篇
[嵌入式框架][nrf51822][SDK12.3] BLE分层设计 集合(OTA、透传、电量、设备信息、HID)
四、 透传服务,加入队列机制
/********************************************************************************
* @file biz_ble_nus.c
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2022-03-16
* @brief [业务] ble数据透传服务(从机)
https://blog.csdn.net/weixin_41572450/article/details/84036968
********************************************************************************/
/* Private Includes ----------------------------------------------------------*/
#include "queue.h"
#include "business_function.h"
#include "log.h"
#include "biz_ble_cfg.h"
#include "biz_ble.h"
#include "biz_ble_nus.h"
/* Private Define ------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
#if BLE_NUS_ENABLED
ble_nus_t m_nus; /**< Structure to identify the Nordic UART Service. */
typedef void(*ble_rx_event_callback)(uint8_t *data, uint16_t len);
static ble_rx_event_callback g_rx_dispose_callback;
/***************消息队列定义**************/
// 用于BLE数据发送消息队列总缓存区
static uint8_t m_ble_q_buff[BLE_BUFF_Q_ITEM_CNT * BLE_BUFF_Q_ITEM_SIZE] = {0};
queue_t m_ble_buff_q =
{
.pbuff = m_ble_q_buff,
.front = 0,
.rear = 0,
.item_cnt = BLE_BUFF_Q_ITEM_CNT,
.item_size = BLE_BUFF_Q_ITEM_SIZE
};
uint8_t g_ble_single_buff_data[BLE_BUFF_Q_ITEM_SIZE] = {0}; // 用于单个BLE数据临时缓存区
// 如果发送失败,则组合上次数据一并发送。最大程度利用带宽,使数据正常发送。
uint8_t ble_send_buff[BLE_BUFF_SEND_MAX_SIZE] = {0}; // 用于组合多个BLE数据
// 记录当前发送长度
uint16_t ble_send_len = 0;
#endif
/* Private Function Prototypes -----------------------------------------------*/
#if BLE_NUS_ENABLED
/**
* @brief [透传数据服务][接收事件] 接收数据事件 [处理通过BLE接收的数据]
* @param p_nus: 透传服务结构体,包含一些回调函数。(本接收事件,没有使用)
* @param p_data: 数据包指针头
* @param length: 数据长度
*/
static void nus_data_handler(ble_nus_t * p_nus, uint8_t *p_data, uint16_t length)
{
LOG_D("<DEBUG> RX:%02x %02x %02x %02x %02x|%d\r\n", p_data[0], p_data[1], p_data[2], p_data[3], p_data[4], length);
// 将数据传给外部[业务层]处理
if (g_rx_dispose_callback)
{
g_rx_dispose_callback(p_data, length);
}
}
#endif
/* Public Function Prototypes ------------------------------------------------*/
#if BLE_NUS_ENABLED
void biz_ble_nus_init(void)
{
uint32_t err_code;
/**** NUS 串口透传服务 ****/
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
LOG_D("<DEBUG> NUS INIT:%x\r\n", err_code);
APP_ERROR_CHECK(err_code);
queue_init(&m_ble_buff_q, m_ble_q_buff, BLE_BUFF_Q_ITEM_CNT, BLE_BUFF_Q_ITEM_SIZE);
memset(m_ble_q_buff, 0, BLE_BUFF_Q_ITEM_CNT * BLE_BUFF_Q_ITEM_SIZE);
memset(g_ble_single_buff_data, 0, BLE_BUFF_Q_ITEM_SIZE);
}
/**
* @brief [串口透传服务] 注册接收回调
* @param *event: 格式 -- func(uint8_t *data, uint16_t len);
* @retval false--失败 true--成功
*/
bool biz_ble_nus_rx_reg_callback(void *event)
{
if (g_rx_dispose_callback != NULL)
{
return false;
}
else
{
g_rx_dispose_callback = (ble_rx_event_callback)event;
}
return true;
}
/**
* @brief [数据透传] 将队列数据依次发送 (本函数建议放在空闲函数使用)
* @retval 0--成功 1--失败
*/
bool ble_data_send_dispose(void)
{
static bool old_send_fail = false;
static uint8_t msg_mem_num = 0;
if (!old_send_fail)
{
msg_mem_num = queue_get_space(&m_ble_buff_q);
if (msg_mem_num != 0)
{
ble_send_len = 0;
// 将队列数据,取出进行组合。
msg_mem_num = msg_mem_num > (BLE_NUS_MAX_DATA_LEN / BLE_BUFF_Q_ITEM_SIZE) ? (BLE_NUS_MAX_DATA_LEN / BLE_BUFF_Q_ITEM_SIZE) : msg_mem_num;
for (uint8_t i = 0; i < msg_mem_num; i++)
{
if (!queue_de(&m_ble_buff_q, g_ble_single_buff_data))
{
break;
}
memcpy(ble_send_buff + ble_send_len, g_ble_single_buff_data, m_ble_buff_q.item_size);
ble_send_len += m_ble_buff_q.item_size;
}
}
}
if (ble_send_len > 0)
{
if (get_ble_conn_state())
{
ret_code_t ble_send_err_code;
#if NRF51
ble_send_err_code = ble_nus_string_send(&m_nus, ble_send_buff, ble_send_len);
#elif NRF52
ble_send_err_code = ble_nus_data_send(&m_nus, ble_send_buff, &ble_send_len, m_conn_handle);
#endif
if (ble_send_err_code == NRF_SUCCESS)
{
old_send_fail = false;
ble_send_len = 0;
}
else
{
old_send_fail = true;
}
return true;
}
else
{
// 蓝牙断开,则清除所有队列数据
queue_init(&m_ble_buff_q, m_ble_q_buff, BLE_BUFF_Q_ITEM_CNT, BLE_BUFF_Q_ITEM_SIZE);
old_send_fail = false;
ble_send_len = 0;
return false;
}
}
else
{
return false;
}
}
/**
* @brief [数据透传] 发送数据 (非实时,数据入队列)
* @param *data: 数据头指针
* @param len: 数据长度
* @retval 0--成功 1--失败
*/
bool biz_ble_data_send(uint8_t *data, uint8_t len)
{
if (get_ble_conn_state())
{
if (len > BLE_NUS_MAX_DATA_LEN)
{
LOG_E("<ERR> [biz_ble_data_send] Len > 20 , Fail\r\n");
}
if (queue_is_null(&m_ble_buff_q))
{
ret_code_t ble_send_err_code;
#if NRF51
ble_send_err_code = ble_nus_string_send(&m_nus, data, len);
#elif NRF52
ble_send_err_code = ble_nus_data_send(&m_nus, data, &len, m_conn_handle);
#endif
if (ble_send_err_code == NRF_SUCCESS)
{
return true;
}
}
if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
{
return false;
}
if (!queue_en(&m_ble_buff_q, data, len))
{
LOG_D("<DEBUG> [biz_ble_data_send] queue_en fail\r\n");
return false;
}
}
return true;
}
#else
void biz_ble_nus_init(void)
{
}
bool biz_ble_nus_rx_reg_callback(void *event)
{
return false;
}
bool ble_data_send_dispose(void)
{
return false;
}
bool biz_ble_data_send(uint8_t *data, uint8_t len)
{
return false;
}
#endif
/********************************************************************************
* @file biz_ble_nus.h
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2022-03-16
* @brief [业务] ble数据透传服务(从机)
********************************************************************************/
#ifndef __BIZ_BLE_NUS_H
#define __BIZ_BLE_NUS_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "biz_ble_cfg.h"
#include "ble_nus.h"
/* Define --------------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
#if BLE_NUS_ENABLED
extern ble_nus_t m_nus;
#endif
/* Public Function Prototypes ------------------------------------------------*/
void biz_ble_nus_init(void);
bool biz_ble_data_send(uint8_t *data, uint8_t len);
bool ble_data_send_dispose(void);
bool biz_ble_nus_rx_reg_callback(void *event);
#endif
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!