This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Adding Baud Rate Characteristic to UART example

Hello All,

I am implementing a simple UART bridge over BLE and want to add a Characteristic to update the baud rate being used. I thought I added code to support a new characteristic everywhere it needs to go, but when I scan for characteristics with the nRF connect app or another BLE scanner, it does not show up in the list.  The plan is to look for the newly defined BLE_NUS_EVT_BAUD event in the nus_data_handler and update the baud rate accordingly. Is there anything I am missing here when it comes to adding a characteristic?

I added the following lines of code to the UART example:

in ble_nus.h


struct ble_nus_s
{
uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */
uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
ble_gatts_char_handles_t baud_handles;
ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
};

in ble_nus.c

#define BLE_UUID_NUS_BAUD_CHARACTERISTIC 0x0004 /**< The UUID of the BAUD Characteristic. */
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */

#define BLE_NUS_MAX_BAUD_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the BAUD Characteristic (in bytes). */
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */

in on_write in ble_nus.c

else if ((p_evt_write->handle == p_nus->baud_handles.value_handle) &&
(p_nus->data_handler != NULL))
{
evt.type = BLE_NUS_EVT_BAUD;
evt.params.rx_data.p_data = p_evt_write->data;
evt.params.rx_data.length = p_evt_write->len;

p_nus->data_handler(&evt);
}

in ble_nus_init in ble_nus.c

// Add the BAUD Characteristic.
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_NUS_BAUD_CHARACTERISTIC;
add_char_params.uuid_type = p_nus->uuid_type;
add_char_params.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true;
add_char_params.char_props.write = 1;
add_char_params.char_props.read = 1;

add_char_params.read_access = SEC_OPEN;
add_char_params.write_access = SEC_OPEN;

err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->baud_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}

  • Thank you. 

    A couple other questions for my application. How can I set the value of the characteristic to be read from the peer side on initialization? I would want the end user to be able to read what baud rate is set in the BLE device and then allow them to change it if needed.

    Secondly, is there any memory available in this chip to be able to save settings such as device name and baud rate over a power cycle, and set them accordingly on the next power up?

  • aaron.mcneil said:
    A couple other questions for my application. How can I set the value of the characteristic to be read from the peer side on initialization? I would want the end user to be able to read what baud rate is set in the BLE device and then allow them to change it if needed.

     NRF_UARTE->BAUDRATE is a read-write register. So after the uart is initialized and all services discovered, you can send a notification to the peer with a magic prefix(command) combined with a baudrate value. There are many ways to do it and you need to consider this properly to see which way first best to your application architecture.

     

    aaron.mcneil said:
    Secondly, is there any memory available in this chip to be able to save settings such as device name and baud rate over a power cycle, and set them accordingly on the next power up?

     Save to flash (non-volatile memory) which will keep the data even after power cycles. FDS library can help you with that.

  • I tried this code but my p_ble_nus_evt does have not a member named p_data. I can use (uint32_t)*p_evt->params.rx_data.p_data, but this doesnt seem to be getting the entire int 32 I set. I can see I'm getting a 2 digit hex value, and it is the proper last 2 digits of what im trying to set there but not the whole number. For example, when i set baud to 9600 this value is 0x80, while it should be 0x2580.

    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_DEBUG("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_BAUD)
        {   
            uint32_t baud_rate;
            baud_rate = (uint32_t)*p_evt->params.rx_data.p_data;
            
            if(baud_rate == 9600){
             NRF_UARTE0->BAUDRATE = NRF_UART_BAUDRATE_9600;
            }else if(baud_rate == 57600){
              NRF_UARTE0->BAUDRATE = NRF_UART_BAUDRATE_57600;
            }else if(baud_rate == 38400){
              NRF_UARTE0->BAUDRATE = NRF_UART_BAUDRATE_38400;
            }else if(baud_rate == 115200){
              NRF_UARTE0->BAUDRATE = NRF_UART_BAUDRATE_115200;
            }
            
            NRF_LOG_DEBUG("BAUD Rate Char Written to");
        }
    
    }

  • I figured out this issue. p_data is only a uint8_t. Have to combine all 4 bytes to get the baud rate.

  • The FDS library seems like a lot of involvement just to save 2 variables to flash. Is there any super simple ways of writing to/reading from the flash?

Related