蓝牙透传的profile的构建

蓝牙透传的profile的构建

在nordic提供的空白模板的基础上

1.初始化片上串口模块

2.构建蓝牙串口透传服务

3.串口穿透服务初始化这个函数非常重要

蓝牙服务的初始化

  • services_init(),这里头包含了应用程序的初始化(黑色点击可以跳转)

    在以下代码中注册服务的流程如下

    1.初始化服务结构体,结构体中包含:一个回调函数的句柄(可以是多个吗?)

    • ble_uarts_init_t结构体

      typedef struct
      {
          ble_uarts_data_handler_t data_handler; //处理接收数据的事件句柄,这个句柄的类型如下个代码块
      } ble_uarts_init_t;
      
      typedef void (* ble_uarts_data_handler_t) (ble_uarts_evt_t * p_evt);
      

      由于括号()的优先级大于*所以(*p)首先是一个指针,指向函数p,这里用了typedef,所以如果定义

      ble_uarts_data_handler_t data_handler //那么data_handler本身就是一个以(ble_uarts_evt_t * p_evt);为输入的回调函数的句柄,在句柄调用的地方直接输入 参数data_handler,即可调用这个函数。

      定义了一个函数指针,同时这个函数指针的参数是一个结构体指针:形式就是(*p)(type * a) 。

    2.用memset清空初始化结构体

    3.设置该服务的回调函数

    4.初始化该服务两个参数(实例化服务,初始化结构体)

    • ble_uarts_init(ble_uarts_t * p_uarts, ble_uarts_init_t const * p_uarts_init)

      //初始化串口透传服务
      uint32_t ble_uarts_init(ble_uarts_t * p_uarts, ble_uarts_init_t const * p_uarts_init)
      {
          ret_code_t            err_code;
      	  //定义16位UUID结构体变量
          ble_uuid_t            ble_uuid;
      	  //定义128位UUID结构体变量,并初始化为串口透传服务UUID基数
          ble_uuid128_t         nus_base_uuid = UARTS_BASE_UUID;
      	  //定义特征参数结构体变量
          ble_add_char_params_t add_char_params;
          //检查指针是否为NULL
          VERIFY_PARAM_NOT_NULL(p_uarts);
          VERIFY_PARAM_NOT_NULL(p_uarts_init);
      
      	  //拷贝串口透传服务初始化结构体中的事件句柄
          p_uarts->data_handler = p_uarts_init->data_handler;
      
          //将自定义UUID基数添加到SoftDevice
          err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_uarts->uuid_type);
          VERIFY_SUCCESS(err_code);
          //UUID类型和数值赋值给ble_uuid变量
          ble_uuid.type = p_uarts->uuid_type;
          ble_uuid.uuid = BLE_UUID_UARTS_SERVICE;
      
          //添加串口透传服务
          err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                              &ble_uuid,
                                              &p_uarts->service_handle);
          VERIFY_SUCCESS(err_code);
          /*---------------------以下代码添加RX特征--------------------*/
          //添加RX特征
      		//配置参数之前先清零add_char_params
          memset(&add_char_params, 0, sizeof(add_char_params));
      		//RX特征的UUID
          add_char_params.uuid                     = BLE_UUID_UARTS_RX_CHARACTERISTIC;
      		//RX特征的UUID类型
          add_char_params.uuid_type                = p_uarts->uuid_type;
      		//设置RX特征值的最大长度
          add_char_params.max_len                  = BLE_UARTS_MAX_RX_CHAR_LEN;
      		//设置RX特征值的初始长度
          add_char_params.init_len                 = sizeof(uint8_t);
      		//设置RX的特征值长度为可变长度
          add_char_params.is_var_len               = true;
      		//设置RX特征的性质支持写
          add_char_params.char_props.write         = 1;
      		//设置RX特征的性质支持无响应写
          add_char_params.char_props.write_wo_resp = 1;
          //设置读/写RX特征值的安全需求:无安全性
          add_char_params.read_access  = SEC_OPEN;
          add_char_params.write_access = SEC_OPEN;
          //为串口透传服务添加RX特征
          err_code = characteristic_add(p_uarts->service_handle, &add_char_params, &p_uarts->rx_handles);
      		//检查返回的错误代码
          if (err_code != NRF_SUCCESS)
          {
              return err_code;
          }
      		/*---------------------添加RX特征-END------------------------*/
      		
          /*---------------------以下代码添加TX特征--------------------*/
          //添加TX特征
      		//配置参数之前先清零add_char_params
          memset(&add_char_params, 0, sizeof(add_char_params));
      		//TX特征的UUID
          add_char_params.uuid              = BLE_UUID_UARTS_TX_CHARACTERISTIC;
      		//TX特征的UUID类型
          add_char_params.uuid_type         = p_uarts->uuid_type;
      		//设置TX特征值的最大长度
          add_char_params.max_len           = BLE_UARTS_MAX_TX_CHAR_LEN;
      		//设置TX特征值的初始长度
          add_char_params.init_len          = sizeof(uint8_t);
      		//设置TX的特征值长度为可变长度
          add_char_params.is_var_len        = true;
      		//设置TX特征的性质:支持通知
          add_char_params.char_props.notify = 1;
          //设置读/写RX特征值的安全需求:无安全性
          add_char_params.read_access       = SEC_OPEN;
          add_char_params.write_access      = SEC_OPEN;
          add_char_params.cccd_write_access = SEC_OPEN;
          //为串口透传服务添加TX特征
          return characteristic_add(p_uarts->service_handle, &add_char_params, &p_uarts->tx_handles);
      		/*---------------------添加TX特征-END------------------------*/
      }
      
      //初始化串口透传服务
      uint32_t ble_uarts_init(ble_uarts_t * p_uarts, ble_uarts_init_t const * p_uarts_init)
      {
          ret_code_t            err_code;
      	  //定义16位UUID结构体变量
          ble_uuid_t            ble_uuid;
      	  //定义128位UUID结构体变量,并初始化为串口透传服务UUID基数
          ble_uuid128_t         nus_base_uuid = UARTS_BASE_UUID;
      	  //定义特征参数结构体变量
          ble_add_char_params_t add_char_params;
          //检查指针是否为NULL
          VERIFY_PARAM_NOT_NULL(p_uarts);
          VERIFY_PARAM_NOT_NULL(p_uarts_init);
      
      	  //拷贝串口透传服务初始化结构体中的事件句柄
          p_uarts->data_handler = p_uarts_init->data_handler;
      
          //将自定义UUID基数添加到SoftDevice
          err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_uarts->uuid_type);
          VERIFY_SUCCESS(err_code);
          //UUID类型和数值赋值给ble_uuid变量
          ble_uuid.type = p_uarts->uuid_type;
          ble_uuid.uuid = BLE_UUID_UARTS_SERVICE;
      
          //添加串口透传服务
          err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                              &ble_uuid,
                                              &p_uarts->service_handle);
          VERIFY_SUCCESS(err_code);
          /*---------------------以下代码添加RX特征--------------------*/
          //添加RX特征
      		//配置参数之前先清零add_char_params
          memset(&add_char_params, 0, sizeof(add_char_params));
      		//RX特征的UUID
          add_char_params.uuid                     = BLE_UUID_UARTS_RX_CHARACTERISTIC;
      		//RX特征的UUID类型
          add_char_params.uuid_type                = p_uarts->uuid_type;
      		//设置RX特征值的最大长度
          add_char_params.max_len                  = BLE_UARTS_MAX_RX_CHAR_LEN;
      		//设置RX特征值的初始长度
          add_char_params.init_len                 = sizeof(uint8_t);
      		//设置RX的特征值长度为可变长度
          add_char_params.is_var_len               = true;
      		//设置RX特征的性质支持写
          add_char_params.char_props.write         = 1;
      		//设置RX特征的性质支持无响应写
          add_char_params.char_props.write_wo_resp = 1;
          //设置读/写RX特征值的安全需求:无安全性
          add_char_params.read_access  = SEC_OPEN;
          add_char_params.write_access = SEC_OPEN;
          //为串口透传服务添加RX特征
          err_code = characteristic_add(p_uarts->service_handle, &add_char_params, &p_uarts->rx_handles);
      		//检查返回的错误代码
          if (err_code != NRF_SUCCESS)
          {
              return err_code;
          }
      		/*---------------------添加RX特征-END------------------------*/
      		
          /*---------------------以下代码添加TX特征--------------------*/
          //添加TX特征
      		//配置参数之前先清零add_char_params
          memset(&add_char_params, 0, sizeof(add_char_params));
      		//TX特征的UUID
          add_char_params.uuid              = BLE_UUID_UARTS_TX_CHARACTERISTIC;
      		//TX特征的UUID类型
          add_char_params.uuid_type         = p_uarts->uuid_type;
      		//设置TX特征值的最大长度
          add_char_params.max_len           = BLE_UARTS_MAX_TX_CHAR_LEN;
      		//设置TX特征值的初始长度
          add_char_params.init_len          = sizeof(uint8_t);
      		//设置TX的特征值长度为可变长度
          add_char_params.is_var_len        = true;
      		//设置TX特征的性质:支持通知
          add_char_params.char_props.notify = 1;
          //设置读/写RX特征值的安全需求:无安全性
          add_char_params.read_access       = SEC_OPEN;
          add_char_params.write_access      = SEC_OPEN;
          add_char_params.cccd_write_access = SEC_OPEN;
          //为串口透传服务添加TX特征
          return characteristic_add(p_uarts->service_handle, &add_char_params, &p_uarts->tx_handles);
      		/*---------------------添加TX特征-END------------------------*/
      }
      
    static void services_init(void)
    {
        ret_code_t         err_code;
    	  //定义串口透传初始化结构体
    	  [ble_uarts_init_t](https://www.notion.so/profile-d789da71b5b4457abf8b7bd76b989633)     uarts_init;//这个结构体中只包含了一个事件句柄data_handler
    	  //定义排队写入初始化结构体变量
        nrf_ble_qwr_init_t qwr_init = {0};
    
        //排队写入事件处理函数
        qwr_init.error_handler = nrf_qwr_error_handler;
        //初始化排队写入模块
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
    		//检查函数返回值
        APP_ERROR_CHECK(err_code);
        
    		
    		/*------------------以下代码初始化串口透传服务-------------*/
    		//清零串口透传服务初始化结构体
    		memset(&uarts_init, 0, sizeof(uarts_init));
    		//设置串口透传事件回调函数
        uarts_init.data_handler = uarts_data_handler;
        //初始化串口透传服务
        err_code = ble_uarts_init(&m_uarts, &uarts_init);
        APP_ERROR_CHECK(err_code);
    		/*------------------初始化串口透传服务-END-----------------*/
    }
    

串口透传事件的回调

传入的参数ble_uarts_evt_t * p_evt

  • ble_uarts_evt_t结构体:

    // 串口透传事件需要的的所有参数
    typedef struct
    {
        ble_uarts_evt_type_t       type;        //事件类型
        ble_uarts_t                * p_uarts;   //指向串口透传实例的指针
        uint16_t                   conn_handle; //连接句柄
        union
        {
            ble_uarts_evt_rx_data_t rx_data; //BLE_NUS_EVT_RX_DATA事件数据
        } params;
    } ble_uarts_evt_t;
    
    //串口事件的枚举默认第一个为0,第二个为1-------type成员
    typedef enum
    {
        BLE_UARTS_EVT_RX_DATA,      //接收到新的数据-----0
        BLE_UARTS_EVT_TX_RDY,       //准备就绪,可以发送新数据-------1
    } ble_uarts_evt_type_t;
    
    // 这个结构体的成员有数据缓存和数据长度。-------rx_data 
    typedef struct
    {
        uint8_t const * p_data; //指向存放接收数据的缓存
        uint16_t        length; //接收的数据长度
    } ble_uarts_evt_rx_data_t;
    
    typedef struct ble_uarts_s ble_uarts_t;//把ble_uarts_s 重命名为 ble_uarts_t,分别有以下5个成员
    struct ble_uarts_s
    {
        uint8_t                         uuid_type;          //UUID类型
        uint16_t                        service_handle;     //串口透传服务句柄(由协议栈提供)
        ble_gatts_char_handles_t        tx_handles;         //TX特征句柄
        ble_gatts_char_handles_t        rx_handles;         //RX特征句柄
        ble_uarts_data_handler_t        data_handler;       //处理接收数据的事件句柄
    };
    
    

代码整体结构讲解

  • 整体结构

    很显然,在串口打印中涉及到两方面————收和发,使用一个for循环在串口打印数据,打印方法为调用app_uart_put()这个API。使用一个for循环嵌套do— -while(err_code == NRF_ERROR_BUSY)这个结束条件是,忙等待+ app_uart_put()。完成串口打印。做一个判断,如果不是正忙(NRF_ERROR_BUSY)和发送成功(NRF_SUCCESS),就要日志打印NRF_LOG_ERROR()错误信息。

    static void uarts_data_handler(ble_uarts_evt_t * p_evt)
    {
    	//========================此下是接收BLE事件,并打印到串口事件========
    	//判断事件类型:接收到新数据事件
        if (p_evt->type == BLE_UARTS_EVT_RX_DATA)
        {
            uint32_t err_code;
            //串口打印出接收的数据
            for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
            {
                do
                {
                    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                    if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                    {
                        NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);
            }
    //判断结束指令
            if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
            {
                while (app_uart_put('\n') == NRF_ERROR_BUSY);
            }
        }
    
    		//========================此下是发送就绪事件========
    		//判断事件类型:发送就绪事件,该事件在后面的试验会用到,当前我们在该事件中翻转指示灯D4的状态,指示该事件的产生
        if (p_evt->type == BLE_UARTS_EVT_TX_RDY)
        {
    			nrf_gpio_pin_toggle(LED_4);
    		}
    }
    

adhjaohof

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值