nRF51 SDK - S110 SoftDevice
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Experimental: UART/Serial Port Emulation over BLE

Nordic UART Service(NUS) Application is an example that emulates a serial port over BLE using the Nordic nRF51422 evaluation board (PCA10028). This is intended to serve as a peer to the phone application 'nRF UART' (available for iOS on Apple Store and for Android on Google Play Store) and also to demonstrate the usage of proprietary (vendor specific) service and characteristics with the S110 SoftDevice.

The name of the example is experimental_ble_app_uart_s110_pca10028. If you are not using the Keil Pack Installer, you can find the source code and project file of the example in the following folder: <InstallFolder>\Nordic\nrf51\examples\ble_peripheral\experimental_ble_app_uart

The application includes one service, namely the Nordic UART Service (UUID: 0x0001). The UUID of the Nordic UART Service is 6E400001-B5A3-F393-E0A9-E50E24DCCA9E.

This service exposes two characteristics - one for receiving and and another for transmitting, as seen from the nRF51422 application.

TX Characteristic (UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E):

When the peer has enabled notification for the TX Characteristic, the application can send data to the peer as notifications. The application will transmit all data received over UART as notifications.

RX Characteristic (UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E):

The peer can start sending data to the device by writing to the RX Characteristic of the service. ATT Write Request or ATT Write Command can be used. The data received is sent on the UART interface.

Brief description of important code lines

Adding proprietary service and characteristic

The initialization of the proprietary service and its characteristics are done in ble_nus.c.

The Nordic UART Service is added to the S110 SoftDevice as follows:

// Add custom base UUID.
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
// Add service.
&ble_uuid,
&p_nus->service_handle);

The RX characteristic is added to the SoftDevice as follows. Notice that the read and write permissions of the characteristic and its CCCD are set as 'open' - which means there are no security restrictions on this characteristic. Also note that the type of the UUID (ble_uuid.type) is the value that was returned in the call to sd_ble_uuid_vs_add(). The TX characteristic is also added in a similar way.

ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
memset(&cccd_md, 0, sizeof(cccd_md));
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
memset(&attr_md, 0, sizeof(attr_md));
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
&char_md,
&attr_char_value,
&p_nus->rx_handles);

UART initialization

All application initialization and handling of data sent and received through BLE and UART are done in main.c.

The UART initialization is done as shown in the code below. This code segment uses the UART driver provided in the SDK to perform the UART configuration. Note that the last parameter to the simple_uart_config function indicates that the application intends to use Hardware Flow Control. This means that the RTS_PIN_NUMBER and CTS_PIN_NUMBER will be used as Ready-to-Send and Clear-to-Send pins respectively. The code below then enables the UART interrupt.

simple_uart_config(RTS_PIN_NUMBER, TX_PIN_NUMBER, CTS_PIN_NUMBER, RX_PIN_NUMBER, HWFC);
NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
NVIC_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
NVIC_EnableIRQ(UART0_IRQn);

Handling of data received over BLE

When initializing the service in the services_init() function, the application passes nus_data_handler to be used for handling the received data. When the Nordic UART Service indicates that there has been some data received over BLE from the peer, the same data is relayed to the UART. This function consists of the following piece of code:

void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length)
{
for (int i = 0; i < length; i++)
{
simple_uart_put(p_data[i]);
}
}

Handling of data received over UART

The data received from the UART undergoes certain checks before getting relayed to the BLE peer using the Nordic UART Service. The following code is inside the UART Interrupt handler that will be called each time a character is received over the UART. Each of these characters is buffered up into a string until a 'new line' character is received OR the size of the string exceeds the limit indicated by NUS_MAX_DATA_LENGTH. Once one of these two conditions is met, the string is sent over BLE using ble_nus_send_string function.

Note
By default, the macro NUS_MAX_DATA_LENGTH is set to its maximum possible value, which is the maximum size of a notification packet (BLE_ATT_MTU - 3), and should not be increased further.
data_array[index] = simple_uart_get();
index++;
if ((data_array[index - 1] == '\n') || (index >= (BLE_NUS_MAX_DATA_LEN - 1)))
{
err_code = ble_nus_send_string(&m_nus, data_array, index + 1);
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
index = 0;
}

Button and LED Assignments

LED assignments:

  • LED 1: Advertising. Device name as seen by the peer in Advertisement Data is 'Nordic_UART'.
  • LED 2: Connected.

Button assignments in system-off mode:

  • Button 1: Wake up from system-off and start advertising.

Testing

Setting up UART-based console/terminal

  • Connect the board to the computer using a USB cable. The board is assigned a COM port (that is visible in the Device Manager).
  • Open a terminal emulator application.
  • Select the COM port assigned to the board. Set the baud rate as 38400. Enable Hardware Flow Control.
  • Connect to the COM port.

Testing steps

The UART Application can be tested using the application 'nRF UART', which is available for iOS and Android. It is listed as 'nRF UART' on Apple Store and on Google Play Store.

You can also test the application with the Master Control Panel by performing the following steps:

  1. Setup the terminal emulator as mentioned in Setting up UART-based console/terminal.
  2. Compile and program the application.
  3. The LED1 will be lit on start-up, indicating it is advertising with device name 'Nordic_UART'. Note: If no peer connects to this application within 180 seconds (APP_ADV_TIMEOUT_IN_SECONDS), the application will put the chip back in System-OFF mode.
  4. Observe that the text 'Start...' is printed on the terminal emulator running on the computer. This indicates that the communication between the computer and the application running on the board is up and running.
  5. While the LED1 is lit, connect to the device from Master Control Panel, then perform service discovery. Observe that the LED1 is off.
  6. Click the 'Enable services' button on the Master Control Panel.
  7. Select UART RX characteristic value on the Master Control Panel window.
  8. Choose "text" option in the attribute value section.
  9. Write 123456789 and click 'Send Update'. Verify that the text 123456789 is displayed on the console connected to the device.
  10. For sending data from the device to the Master Control Panel, enter any text, for example, 'Hello' on the console. Observe a notification with corresponding ASCII values notified to the peer on handle 0x000E. In this case, the notification will be '48656C6C6F0D'.
  11. Press the Disconnect button in the Master Control Panel. Observe that the application is advertising (LED1 will be lit).