Bluetooth LE with Nordic nRF51 & nRF52 series
The easy way!
Part 3
The easy way!
Part 3
Custom service
(UART over BLE)
(UART over BLE)
We have looked at how to advertise in previous post. Now, lets see how simple it is to create a BLE custom service. For this purpose, we'll create an UART to BLE firmware that sends whatever it received on UART RX to BLE and whatever that is received from BLE to UART TX.
First thing first, lets start by initializing the UART interface. As mentioned before the concept of EHAL is very simple. Everything is initialized with a Config data first then just use.
The UART interface configuration starts by defining I/O pins to be used for the UART.
/// UART pins definitions
static IOPINCFG s_UartPins[] = {
{UART_RX_PORT, UART_RX_PIN, UART_RX_PINOP, IOPINDIR_INPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, // RX
{UART_TX_PORT, UART_TX_PIN, UART_TX_PINOP, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, // TX
{UART_CTS_PORT, UART_CTS_PIN, UART_CTS_PINOP, IOPINDIR_INPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, // CTS
{UART_RTS_PORT, UART_RTS_PIN, UART_RTS_PINOP, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, // RTS
};
Then the configuration data and the UART interface instance.
/// UART configuration
const UARTCFG g_UartCfg = {
0, // Device number zero based
s_UartPins, // UART assigned pins
sizeof(s_UartPins) / sizeof(IOPINCFG),// Total number of UART pins used
1000000, // Baudrate
8, // Data bits
UART_PARITY_NONE, // Parity
1, // Stop bit
UART_FLWCTRL_HW, // Flow control
true, // Interrupt mode
APP_IRQ_PRIORITY_LOW, // Interrupt priority
nRFUartEvthandler, // UART event handler
true, // Blocking FIFO
};
/// UART object instance
UART g_Uart;
g_Uart.Init(g_UartCfg);
Using UART :
g_Uart.printf("Hello\r\n");
Now the BLE configuration for custom service.
/// Characteristic definitions
BLESRVC_CHAR g_UartChars[] = {
{
// Read characteristic
BLUEIO_UUID_UART_RX_CHAR,
20,
BLESVC_CHAR_PROP_READ | BLESVC_CHAR_PROP_NOTIFY | BLESVC_CHAR_PROP_VARLEN,
s_RxCharDescString, // char UTF-8 description string
NULL, // Callback for write char, set to NULL for read char
NULL, // Callback on set notification
NULL, // Tx completed callback
NULL, // pointer to char default values
0, // Default value length in bytes
},
{
// Write characteristic
BLUEIO_UUID_UART_TX_CHAR,// char UUID
20, // char max data length
BLESVC_CHAR_PROP_WRITEWORESP,// char properties define by BLUEIOSVC_CHAR_PROP_...
s_TxCharDescString, // char UTF-8 description string
UartTxSrvcCallback, // Callback for write char, set to NULL for read char
NULL, // Callback on set notification
NULL, // Tx completed callback
NULL, // pointer to char default values
0 // Default value length in bytes
},
};
/// Service definition
const BLESRVC_CFG s_UartSrvcCfg = {
BLESRVC_SECTYPE_NONE, // Secure or Open service/char
BLUEIO_UUID_BASE, // Base UUID
BLUEIO_UUID_UART_SERVICE, // Service UUID
2, // Total number of characteristics for the service
g_UartChars, // Pointer a an array of characteristic
g_LWrBuffer, // pointer to user long write buffer
sizeof(g_LWrBuffer) // long write buffer size
};
BLESRVC g_UartBleSrvc;
const BLEAPP_DEVDESC s_UartBleDevDesc {
MODEL_NAME, // Model name
MANUFACTURER_NAME, // Manufacturer name
"", // Serial number string
"0.0", // Firmware version string
"0.0", // Hardware version string
};
const BLEAPP_CFG s_BleAppCfg = {
{ // Clock config nrf_clock_lf_cfg_t
#ifdef IMM_NRF51822
NRF_CLOCK_LF_SRC_RC, // Source RC
1, 1, 0
#else
NRF_CLOCK_LF_SRC_XTAL, // Source 32KHz XTAL
0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM
#endif
},
0, // Number of central link
1, // Number of peripheral link
BLEAPP_MODE_APPSCHED, // Use scheduler
DEVICE_NAME, // Device name
ISYST_BLUETOOTH_ID, // PnP Bluetooth/USB vendor id
1, // PnP Product ID
0, // Pnp prod version
true, // Enable device information service (DIS)
&s_UartBleDevDesc,
g_ManData, // Manufacture specific data to advertise
sizeof(g_ManData), // Length of manufacture specific data
BLEAPP_SECTYPE_STATICKEY_MITM,//BLEAPP_SECTYPE_NONE, // Secure connection type
BLEAPP_SECEXCHG_NONE, // Security key exchange
NULL, // Service uuids to advertise
0, // Total number of uuids
APP_ADV_INTERVAL, // Advertising interval in msec
APP_ADV_TIMEOUT_IN_SECONDS, // Advertising timeout in sec
0, // Slow advertising interval, if > 0, fallback to
// slow interval on adv timeout and advertise until connected
MIN_CONN_INTERVAL,
MAX_CONN_INTERVAL,
BLUEIO_CONNECT_LED_PORT, // Led port nuber
BLUEIO_CONNECT_LED_PIN, // Led pin number
0, // Tx power
NULL // RTOS Softdevice handler
};
In order to handle the UART receive and send it to BLE, we need to hookup the UART event handler.
void UartRxChedHandler(void * p_event_data, uint16_t event_size)
{
uint8_t buff[128];
int l = g_Uart.Rx(buff, 128);
if (l > 0)
{
BleSrvcCharNotify(&g_UartBleSrvc, 0, buff, l);
}
}
int nRFUartEvthandler(UARTDEV *pDev, UART_EVT EvtId, uint8_t *pBuffer, int BufferLen)
{
int cnt = 0;
uint8_t buff[20];
switch (EvtId)
{
case UART_EVT_RXTIMEOUT:
case UART_EVT_RXDATA:
app_sched_event_put(NULL, 0, UartRxChedHandler);
break;
case UART_EVT_TXREADY:
break;
case UART_EVT_LINESTATE:
break;
}
return cnt;
}
Handling received date from BLE and transmit to UART Tx.
void UartTxSrvcCallback(BLESRVC *pBlueIOSvc, uint8_t *pData, int Offset, int Len)
{
g_Uart.Tx(pData, Len);
}
Part 1 Part 2