1. 程式人生 > 其它 >Nordic 中心裝置新增自定義服務處理

Nordic 中心裝置新增自定義服務處理

技術標籤:nordic物聯網

Nordic 中心裝置新增自定義服務處理

照搬ble_nus_c.cble_nus_c.h內容來完成自定義服務的處理。這裡中心裝置我採用的工程例子是 ble_app_uart_c

components\ble\ble_services\ble_nus_c中的 ble_nus_c.cble_nus_c.h 拷貝到我們的工程中。

修改檔名,避免檔案重定義問題。然後就是依樣畫葫蘆,照著 ble_nus_c.cble_nus_c.h 進行修改。

這裡修改好的檔案我放在 github上。

這裡直接把所有的nus名字換成我們自定義的。

uuid 也換成自定義的,這裡的三個 uuid

需要是連續的。

#define MYSERVICE_BASE_UUID                   {{0x66, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor-specific UUID. */

#define BLE_UUID_MYSERVICE_SERVICE            0x2221                      /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_MYSERVICE_RX_CHARACTERISTIC  0X2222                      
/**< The UUID of the RX Characteristic. */ #define BLE_UUID_MYSERVICE_TX_CHARACTERISTIC 0x2223 /**< The UUID of the TX Characteristic. */

然後在 main 中對應的位置,新增我們自定義的服務處理。這裡照著 nus 服務的程式碼來進行修改。

先定義服務例項。

BLE_MYSERVICE_C_DEF(m_ble_myservice_c);

然後定義服務初始化介面。

static void myservice_c_init
(void) { ret_code_t err_code; ble_myservice_c_init_t init; init.evt_handler = ble_myservice_c_evt_handler; init.error_handler = nus_error_handler; init.p_gatt_queue = &m_ble_gatt_queue; err_code = ble_myservice_c_init(&m_ble_myservice_c, &init); if (err_code != NRF_SUCCESS) { NRF_LOG_INFO("[%s] err_code: %d", __func__, err_code); } APP_ERROR_CHECK(err_code); }

這裡的服務初始化介面可能會報錯。錯誤程式碼:0x04 ,原因:NRF_ERROR_NO_MEM

解決方案:

sdk_config.h 中為我們自定義的 uuid 分配記憶體空間。

uuid_count

執行時,根據提示RTT View列印修改 RAM 大小。

RAM

void bsp_event_handler(bsp_event_t event) 事件中新增 斷連處理。

void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;

    switch (event)
    {
    case BSP_EVENT_DISCONNECT:

        err_code = sd_ble_gap_disconnect(m_ble_nus_c.conn_handle, \
                                         BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
#if ENABLE_BLE_MYSERVICE
        err_code = sd_ble_gap_disconnect(m_ble_myservice_c.conn_handle, \
                                         BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
#endif
        if (err_code != NRF_ERROR_INVALID_STATE)
        {
            APP_ERROR_CHECK(err_code);
        }
        break;
}

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) 中新增 連線處理。

經測試,這裡不用新增也是可以的。

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ret_code_t            err_code;
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id)
    {
    case BLE_GAP_EVT_CONNECTED:
        // NRF_LOG_INFO("BLE_GAP_EVT_CONNECTED");

        err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
#if ENABLE_BLE_MYSERVICE
        err_code = ble_myservice_c_handles_assign(&m_ble_myservice_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
#endif
        APP_ERROR_CHECK(err_code);

        err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
        APP_ERROR_CHECK(err_code);

        // start discovery of services. The NUS Client waits for a discovery result
        err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
        APP_ERROR_CHECK(err_code);
        break;
}

定義自定義服務的事件處理回撥。照著 nus 服務的進行修改就好了。

static void ble_myservice_c_evt_handler(ble_myservice_c_t * p_ble_myservice_c, ble_myservice_c_evt_t const * p_ble_myservice_evt)
{
	DEBUG_INFO();
    ret_code_t err_code;

    switch (p_ble_myservice_evt->evt_type)
    {
    case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
        NRF_LOG_INFO("Myservice Discovery complete.");
        err_code = ble_myservice_c_handles_assign(p_ble_myservice_c, p_ble_myservice_evt->conn_handle, &p_ble_myservice_evt->handles);
        APP_ERROR_CHECK(err_code);

        err_code = ble_myservice_c_tx_notif_enable(p_ble_myservice_c);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("Connected to device with My Service.");
        break;

    case BLE_NUS_C_EVT_NUS_TX_EVT:
        ble_nus_chars_received_uart_print(p_ble_myservice_evt->p_data, p_ble_myservice_evt->data_len);
        break;

    case BLE_NUS_C_EVT_DISCONNECTED:
        NRF_LOG_INFO("Disconnected.");
        scan_start();
        break;
    }
}

uart_event_handle 回撥中,將收到的串列埠資料傳送到我們自定義服務的Notify 屬性中。

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint16_t index = 0;
    uint32_t ret_val;

    switch (p_event->evt_type)
    {
    /**@snippet [Handling data from UART] */
    case APP_UART_DATA_READY:
        UNUSED_VARIABLE(app_uart_get(&data_array[index]));
        index++;

        if ((data_array[index - 1] == '\n') ||
                (data_array[index - 1] == '\r') ||
                (index >= (m_ble_nus_max_data_len)))
        {
            NRF_LOG_DEBUG("Ready to send data over BLE NUS");
            NRF_LOG_HEXDUMP_DEBUG(data_array, index);

            do
            {
            /*****************自定義服務**********************/
                ret_val = ble_myservice_c_string_send(&m_ble_myservice_c, data_array, index);
				if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) )
                {
                    APP_ERROR_CHECK(ret_val);
                }
                /*******************end********************/
                ret_val = ble_nus_c_string_send(&m_ble_nus_c, data_array, index);
                if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) )
                {
                    APP_ERROR_CHECK(ret_val);
                }
            } while (ret_val == NRF_ERROR_RESOURCES);

            index = 0;
        }
        break;
}

在發現模組回撥處理中新增我們自定義服務的處理函式。

static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
    ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt);

    ble_myservice_c_on_db_disc_evt(&m_ble_myservice_c, p_evt);
}

自此。我們在中心裝置上的處理外圍裝置的自定義服務的程式碼就新增好了。

外圍裝置服務如下,都是 nus 服務基礎上進行修改的。相當於我們自己新建了另外一個 nus 服務。

Screenshot_2021-01-26-00-03-53-103_no.nordicsemi.

這裡我的自定義服務是在 Nordic 52810 上跑的。然後將 Nordic 52840 作為中心裝置來連線這個外圍裝置。UART Service 用工程中原有的。然後Unknown Service 採用我們自己的服務處理來進行連線和處理。

這裡中心裝置為Nordic Downgle ,通過串列埠連線PC, PC串列埠助手傳送資料到 Downgle,然後 Downgle 會通過 NUSMYSERVICE 兩個服務將串列埠接收到的資料傳送到外圍裝置對應的兩個服務上。

這裡DB發現模組,會在建立連線後,按照我們設定的 uuid 來依次發現我們定義的服務,並建立連線。

這裡,外圍裝置上對應服務的回資料處理回撥(nus_new_data_handlernus_data_handler)接收到了來自中心裝置的兩個服務處理的資料。

Screenshot_2021-01-26-00-03-53-103_no.nordicsemi.