硬件: nRF52832 DK
软件: nRF SKD Ver 15.2
官方样例:
NUS 服务端: SDK15.2\ble_peripheral\ble_app_uart
NUS Client 客户端: SDK15.2\examples\ble_central\ble_app_uart_c
DOC 文档:
Nordic UART Service, ~/nRF5_SDK_15.2.0_offline_doc/nrf5/group__ble__nus.html
Nordic UART Service Client,~/nRF5_SDK_15.2.0_offline_doc/nrf5/group__ble__nus__c.html
有用参考: https://devzone.nordicsemi.com/f/nordic-q-a/28208/when-is-nus-ready (提及 Nordic UART Service (NUS) event types)
NUS-S 服务端程序开发要点:
1. 于 sdk_config.h Configuration Wizard 中,选中 BLE_NUS_ENABLED;
2. 项目结构中,添加 文件 ble_nus.c;
3. 蓝牙服务初始化, 以及 NUS 服务初始化;
static void services_init(void)
{
uint32_t err_code;
ble_nus_init_t nus_init;
nrf_ble_qwr_init_t qwr_init = {0};
// Initialize Queued Write Module.
qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
// Initialize NUS.
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
}
4. NUS 服务对应的中断事件处理;
/**@brief Function for handling the data from the Nordic UART Service.
* @details This function will process the data received from the Nordic UART BLE Service and send
* it to the UART module.
* @param[in] p_evt Nordic UART Service event.
*/
/**@snippet [Handling the data received over BLE] */
static void nus_data_handler(ble_nus_evt_t * p_evt)
{
if (p_evt->type == BLE_NUS_EVT_RX_DATA)
{
uint32_t err_code;
NRF_LOG_INFO("Received data from BLE NUS. Writing data on UART.");
NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
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);
}
}
else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED)
{
NRF_LOG_INFO("BLE_NUS_EVT_COMM_STARTED ");
nus_data_send_to_central_welcome();
}
else if (p_evt->type == BLE_NUS_EVT_TX_RDY )
{
NRF_LOG_INFO("BLE_NUS_EVT_TX_RDY ");
}
else if (p_evt->type == BLE_NUS_EVT_COMM_STOPPED)
{
NRF_LOG_INFO("BLE_NUS_EVT_COMM_STOPPED ");
}
}
/**@snippet [Handling the data received over BLE] */
5. NUS 数据透传函数
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
uint8_t * p_data,
uint16_t * p_length,
uint16_t conn_handle
)
6. NUS 服务事件类型
/**@brief Nordic UART Service event types. */
typedef enum
{
BLE_NUS_EVT_RX_DATA, /**< Data received. */
BLE_NUS_EVT_TX_RDY, /**< Service is ready to accept new data to be transmitted. */
BLE_NUS_EVT_COMM_STARTED, /**< Notification has been enabled. */
BLE_NUS_EVT_COMM_STOPPED, /**< Notification has been disabled. */
} ble_nus_evt_type_t;
7. 重要提醒
* NUS 数据透传函数 uint32_t ble_nus_data_send() 使用前, NUS Client 客户端须使能服务通知 (Notification); 否则会导致程序出错!
* 于 NUS 服务的中断回调函数 static void nus_data_handler(ble_nus_evt_t * p_evt) {} 中,通过变量 p_evt->type 获取 NUS 服务事件类型; 即是 p_evt->type 为 BLE_NUS_EVT_COMM_STARTED 时, NUS 数据透传函数 uint32_t ble_nus_data_send() 可正常使用。
* NUS 服务与 UART 串口没有关联!可单独使用。
NUS-C 客户端程序开发要点:
1. 于 sdk_config.h Configuration Wizard 中,选中 BLE_NUS_C_ENABLED;
2. 项目结构中,添加 文件 ble_nus_c.c;
3. NUS_C 初始化;
/**@brief Function for initializing the Nordic UART Service (NUS) client. */
static void nus_c_init(void)
{
ret_code_t err_code;
ble_nus_c_init_t init;
init.evt_handler = ble_nus_c_evt_handler;
err_code = ble_nus_c_init(&m_ble_nus_c, &init);
APP_ERROR_CHECK(err_code);
}
4. NUS_C 对应的中断事件处理;
/**@brief Callback handling Nordic UART Service (NUS) client events.
* @details This function is called to notify the application of NUS client events.
* @param[in] p_ble_nus_c NUS client handle. This identifies the NUS client.
* @param[in] p_ble_nus_evt Pointer to the NUS client event.
*/
/**@snippet [Handling events from the ble_nus_c module] */
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
{
ret_code_t err_code;
switch (p_ble_nus_evt->evt_type)
{
case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
NRF_LOG_INFO("Discovery complete.");
err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
APP_ERROR_CHECK(err_code);
err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("Connected to device with Nordic UART Service.");
break;
case BLE_NUS_C_EVT_NUS_TX_EVT:
ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
break;
case BLE_NUS_C_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected.");
scan_start();
break;
}
}
/**@snippet [Handling events from the ble_nus_c module] */
5. NUS_C 数据透传函数
uint32_t ble_nus_c_string_send ( ble_nus_c_t * p_ble_nus_c,
uint8_t * p_string,
uint16_t length
)
6. NUS_C 事件类型