打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  337 随笔 :: 0 文章 :: 2 评论 :: 70667 阅读

接上一篇
[嵌入式框架][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

posted on   xuejianqiang  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033
点击右上角即可分享
微信分享提示