nRF51 SDK: UART/Serial Port Emulation over BLE

| nRF51 SDK

- Home
- Related Pages
- API Reference
- Data Structures

All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
UART/Serial Port Emulation over BLE

# Introduction.

Nordic UART Service(NUS) Application is a firmware example that emulates a serial port over BLE using the Nordic nRF51822 evaluation board (PCA10001). 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 source code and project file can be found in the `<InstallFolder>\Nordic\nrf51822\Board\pca10001\s110\experimental\ble_app_uart` folder.

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 nRF51822 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):

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.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&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_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
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));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
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 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 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]);
}
simple_uart_put('\n');
}

## Handling of data received over UART

The data received from the UART though undergoes certain checks before getting relayed to the BLE peer using the Nordic UART Service. The following code is inside the UART Interrupt handler which 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, i.e 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 0: Advertising. Device name as seen by the peer in Advertisement Data is 'Nordic_UART'
- LED 1: Connected.

Buttons assignments:

- Button 0: In System-Off mode: Wake-up from system-off and start advertising.

# Testing

## Setting Up UART based Console/Terminal

- Connect the evaluation board to the PC 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 evaluation board. Set the baud rate as 38400. Enable Hardware Flow Control.
- Connect to the COM port.

## Test steps

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

It can also be tested using the Master Control Panel as follows:

1. Setup the Terminal emulator as mentioned in setting_up_serial_terminal section.
2. Compile and program the application.
3. The LED 0 will be lit on start up indicating it is advertising with device name is '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 PC. This indicates that the communication between the PC and the application running on the evaluation board is up and running.
5. While the LED0 is lit, connect to the device from Master Control Panel, then perform service discovery. Observe that the LED0 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 (LED0 will be lit).