mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
examples/nimble_gatt: extend application with ble characteristics
Extend this application with 2 custom BLE characteristics. One is read-only and returns a string including a random number and the second one is writable. In addition, two characteristics for device information were added (model and manufacturer). Access to the characteristics produces output on the terminal.
This commit is contained in:
parent
5b350d6b2a
commit
b5dacb6534
@ -14,13 +14,25 @@
|
||||
* @file
|
||||
* @brief BLE peripheral example using NimBLE
|
||||
*
|
||||
* Have a more detailed look at the api here:
|
||||
* https://mynewt.apache.org/latest/tutorials/ble/bleprph/bleprph.html
|
||||
*
|
||||
* More examples (not ready to run on RIOT) can be found here:
|
||||
* https://github.com/apache/mynewt-nimble/tree/master/apps
|
||||
*
|
||||
* Test this application e.g. with Nordics "nRF Connect"-App
|
||||
* iOS: https://itunes.apple.com/us/app/nrf-connect/id1054362403
|
||||
* Android: https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
|
||||
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/bluetil/ad.h"
|
||||
@ -31,11 +43,95 @@
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GATT_MODEL_NUMBER_UUID 0x2A24
|
||||
|
||||
#define STR_ANSWER_BUFFER_SIZE 100
|
||||
|
||||
/* UUID = 1bce38b3-d137-48ff-a13e-033e14c7a335 */
|
||||
static const ble_uuid128_t gatt_svr_svc_rw_demo_uuid
|
||||
= BLE_UUID128_INIT(0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
|
||||
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b);
|
||||
|
||||
/* UUID = 35f28386-3070-4f3b-ba38-27507e991762 */
|
||||
static const ble_uuid128_t gatt_svr_chr_rw_demo_write_uuid
|
||||
= BLE_UUID128_INIT(0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba, 0x3b,
|
||||
0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35);
|
||||
|
||||
/* UUID = ccdd113f-40d5-4d68-86ac-a728dd82f4aa */
|
||||
static const ble_uuid128_t gatt_svr_chr_rw_demo_readonly_uuid
|
||||
= BLE_UUID128_INIT(0xaa, 0xf4, 0x82, 0xdd, 0x28, 0xa7, 0xac, 0x86, 0x68,
|
||||
0x4d, 0xd5, 0x40, 0x3f, 0x11, 0xdd, 0xcc);
|
||||
|
||||
static const char *device_name = "NimBLE on RIOT";
|
||||
static uint8_t own_addr_type;
|
||||
|
||||
static char rm_demo_write_data[64] = "This characteristic is read- and writeable!";
|
||||
|
||||
static int gatt_svr_chr_access_device_info_manufacturer(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static int gatt_svr_chr_access_device_info_model(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static int gatt_svr_chr_access_rw_demo(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static void start_advertise(void);
|
||||
|
||||
static char str_answer[STR_ANSWER_BUFFER_SIZE];
|
||||
|
||||
/* define several bluetooth services for our device */
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
/*
|
||||
* access_cb defines a callback for read and write access events on
|
||||
* given characteristics
|
||||
*/
|
||||
{
|
||||
/* Service: Device Information */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: * Manufacturer name */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info_manufacturer,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: Model number string */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info_model,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
{
|
||||
/* Service: Read/Write Demo */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_svc_rw_demo_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: Read/Write Demo write */
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_rw_demo,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
/* Characteristic: Read/Write Demo read only */
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_rw_demo,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static void update_ad(void)
|
||||
{
|
||||
uint8_t buf[BLE_HS_ADV_MAX_SZ];
|
||||
@ -78,10 +174,158 @@ static void start_advertise(void)
|
||||
(void)rc;
|
||||
}
|
||||
|
||||
static int gatt_svr_chr_access_device_info_manufacturer(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
puts("service 'device info: manufacturer' callback triggered");
|
||||
|
||||
(void) conn_handle;
|
||||
(void) attr_handle;
|
||||
(void) arg;
|
||||
|
||||
snprintf(str_answer, STR_ANSWER_BUFFER_SIZE,
|
||||
"This is RIOT! (Version: %s)\n", RIOT_VERSION);
|
||||
puts(str_answer);
|
||||
|
||||
int rc = os_mbuf_append(ctxt->om, str_answer, strlen(str_answer));
|
||||
|
||||
puts("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gatt_svr_chr_access_device_info_model(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
puts("service 'device info: model' callback triggered");
|
||||
|
||||
(void) conn_handle;
|
||||
(void) attr_handle;
|
||||
(void) arg;
|
||||
|
||||
snprintf(str_answer, STR_ANSWER_BUFFER_SIZE,
|
||||
"You are running RIOT on a(n) %s board, "
|
||||
"which features a(n) %s MCU.", RIOT_BOARD, RIOT_MCU);
|
||||
puts(str_answer);
|
||||
|
||||
int rc = os_mbuf_append(ctxt->om, str_answer, strlen(str_answer));
|
||||
|
||||
puts("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gatt_svr_chr_access_rw_demo(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
puts("service 'rw demo' callback triggered");
|
||||
|
||||
(void) conn_handle;
|
||||
(void) attr_handle;
|
||||
(void) arg;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u;
|
||||
ble_uuid_t* readonly_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u;
|
||||
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) {
|
||||
|
||||
puts("access to characteristic 'rw demo (write)'");
|
||||
|
||||
switch (ctxt->op) {
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
puts("read from characteristic");
|
||||
printf("current value of rm_demo_write_data: '%s'\n",
|
||||
rm_demo_write_data);
|
||||
|
||||
/* send given data to the client */
|
||||
rc = os_mbuf_append(ctxt->om, &rm_demo_write_data,
|
||||
strlen(rm_demo_write_data));
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
puts("write to characteristic");
|
||||
|
||||
printf("old value of rm_demo_write_data: '%s'\n",
|
||||
rm_demo_write_data);
|
||||
|
||||
uint16_t om_len;
|
||||
om_len = OS_MBUF_PKTLEN(ctxt->om);
|
||||
|
||||
/* read sent data */
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, &rm_demo_write_data,
|
||||
sizeof rm_demo_write_data, &om_len);
|
||||
/* we need to null-terminate the received string */
|
||||
rm_demo_write_data[om_len] = '\0';
|
||||
|
||||
printf("new value of rm_demo_write_data: '%s'\n",
|
||||
rm_demo_write_data);
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
puts("read from descriptor");
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
||||
puts("write to descriptor");
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("unhandled operation!");
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
puts("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
else if (ble_uuid_cmp(ctxt->chr->uuid, readonly_uuid) == 0) {
|
||||
|
||||
puts("access to characteristic 'rw demo (read-only)'");
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
char random_digit;
|
||||
/* get random char between '0' and '9' */
|
||||
random_digit = 48 + (rand() % 10);
|
||||
|
||||
snprintf(str_answer, STR_ANSWER_BUFFER_SIZE,
|
||||
"new random number: %c", random_digit);
|
||||
puts(str_answer);
|
||||
|
||||
rc = os_mbuf_append(ctxt->om, &str_answer, strlen(str_answer));
|
||||
|
||||
puts("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("unhandled uuid!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("NimBLE GATT Server Example");
|
||||
|
||||
int rc = 0;
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
assert(rc == 0);
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
assert(rc == 0);
|
||||
|
||||
/* set the device name */
|
||||
ble_svc_gap_device_name_set(device_name);
|
||||
|
||||
@ -96,7 +340,7 @@ int main(void)
|
||||
while (!ble_hs_synced()) {}
|
||||
|
||||
/* configure device address */
|
||||
int rc = ble_hs_util_ensure_addr(0);
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
assert(rc == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user