gatt-srv.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * Copyright (C) 2019 Freie Universität Berlin
  3. *
  4. * This file is subject to the terms and conditions of the GNU Lesser
  5. * General Public License v2.1. See the file LICENSE in the top level
  6. * directory for more details.
  7. */
  8. /**
  9. * @ingroup examples
  10. * @{
  11. *
  12. * @file
  13. * @brief (Mock-up) BLE heart rate sensor example
  14. *
  15. * @author Hauke Petersen <hauke.petersen@fu-berlin.de>
  16. *
  17. * @}
  18. */
  19. #include <stdio.h>
  20. #include <stdint.h>
  21. #include "assert.h"
  22. #include "event/timeout.h"
  23. #include "nimble_riot.h"
  24. #include "net/bluetil/ad.h"
  25. #include "periph/gpio.h"
  26. #include "timex.h"
  27. #include "roomba.h"
  28. #include "board.h"
  29. #include "host/ble_hs.h"
  30. #include "host/ble_gatt.h"
  31. #include "services/gap/ble_svc_gap.h"
  32. #include "services/gatt/ble_svc_gatt.h"
  33. #define BLE_GATT_SVC_IPS 0x1821
  34. #define BLE_GATT_CHAR_IPS_CONFIG 0x2AAD
  35. #define BLE_GATT_CHAR_LATITUDE 0x2AAE
  36. #define BLE_GATT_CHAR_LONGITUDE 0x2AAF
  37. #define BLE_GATT_CHAR_LOCAL_NORTH 0x2AB0
  38. #define BLE_GATT_CHAR_LOCAL_EAST 0x2AB1
  39. #define BLE_GATT_CHAR_FLOOR_N 0x2AB2
  40. #define BLE_GATT_CHAR_ALTITUDE 0x2AB3
  41. #define BLE_GATT_CHAR_UNCERTAIN 0x2AB4
  42. #define BLE_GATT_CHAR_LOC_NAME 0x2AB4
  43. #define IPS_CONFIG_COORD_PRESENT (1 << 0)
  44. #define IPS_CONFIG_COORD_IN_ADV (1 << 1)
  45. #define IPS_CONFIG_TXP_IN_ADV (1 << 2)
  46. #define IPS_CONFIG_ALT_IN_ADV (1 << 3)
  47. #define IPS_CONFIG_FLOOR_IN_ADV (1 << 4)
  48. #define IPS_CONFIG_UNCE_IN_ADV (1 << 5)
  49. #define IPS_CONFIG_LOC_NAME_AVAIL (1 << 6)
  50. static const char *_device_name = "ROOMBAHAHAHACKED";
  51. static const char *_manufacturer_name = "Insane adding machines";
  52. static const char *_model_number = "2X";
  53. static const char *_serial_number = "a8b302c7f3-29183-x8";
  54. static const char *_fw_ver = "1.0.0";
  55. static const char *_hw_ver = "1.0";
  56. static event_queue_t _eq;
  57. static event_t _update_evt;
  58. static event_timeout_t _update_timeout_evt;
  59. static uint16_t _conn_handle;
  60. static uint16_t _ips_val_handle;
  61. static uint16_t _sensors_val_handle;
  62. static int _ips_handler(uint16_t conn_handle, uint16_t attr_handle,
  63. struct ble_gatt_access_ctxt *ctxt, void *arg);
  64. static int _devinfo_handler(uint16_t conn_handle, uint16_t attr_handle,
  65. struct ble_gatt_access_ctxt *ctxt, void *arg);
  66. static int _roomba_ctrl_handler(uint16_t conn_handle, uint16_t attr_handle,
  67. struct ble_gatt_access_ctxt *ctxt, void *arg);
  68. static int _roomba_sensors_handler(uint16_t conn_handle, uint16_t attr_handle,
  69. struct ble_gatt_access_ctxt *ctxt, void *arg);
  70. static int _bas_handler(uint16_t conn_handle, uint16_t attr_handle,
  71. struct ble_gatt_access_ctxt *ctxt, void *arg);
  72. static void _start_advertising(void);
  73. /* UUID = 35f28386-3070-4f3b-ba38-27507e991760 */
  74. static const ble_uuid128_t gatt_svr_svc_roomba = BLE_UUID128_INIT(
  75. 0x60, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
  76. 0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35
  77. );
  78. /* UUID = 35f28386-3070-4f3b-ba38-27507e991762 */
  79. static const ble_uuid128_t gatt_svr_chr_roomba_ctl = BLE_UUID128_INIT(
  80. 0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
  81. 0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35
  82. );
  83. /* UUID = 35f28386-3070-4f3b-ba38-27507e991764 */
  84. static const ble_uuid128_t gatt_svr_chr_roomba_sensors = BLE_UUID128_INIT(
  85. 0x64, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
  86. 0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35
  87. );
  88. /* UUID = 35f28386-3070-4f3b-ba38-27507e991766 */
  89. static const ble_uuid128_t gatt_svr_chr_roomba_sensors_notify = BLE_UUID128_INIT(
  90. 0x66, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
  91. 0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35
  92. );
  93. /* GATT service definitions */
  94. static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
  95. {
  96. /* Indoor positioning service */
  97. .type = BLE_GATT_SVC_TYPE_PRIMARY,
  98. .uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_IPS),
  99. .characteristics = (struct ble_gatt_chr_def[]) { {
  100. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_IPS_CONFIG),
  101. .access_cb = _ips_handler,
  102. .val_handle = &_ips_val_handle,
  103. .flags = BLE_GATT_CHR_F_NOTIFY,
  104. }, {
  105. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_LATITUDE),
  106. .access_cb = _ips_handler,
  107. .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
  108. }, {
  109. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_LONGITUDE),
  110. .access_cb = _ips_handler,
  111. .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
  112. }, {
  113. 0, /* no more characteristics in this service */
  114. }, }
  115. },
  116. {
  117. /* Roomba controls */
  118. .type = BLE_GATT_SVC_TYPE_PRIMARY,
  119. .uuid = (ble_uuid_t*) &gatt_svr_svc_roomba.u,
  120. .characteristics = (struct ble_gatt_chr_def[]) { {
  121. /* Characteristic: ROOMBA CTRL */
  122. .uuid = (ble_uuid_t*) &gatt_svr_chr_roomba_ctl.u,
  123. .access_cb = _roomba_ctrl_handler,
  124. .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
  125. }, {
  126. /* Characteristic: ROOMBA sensors read/notify */
  127. .uuid = (ble_uuid_t*) &gatt_svr_chr_roomba_sensors.u,
  128. .access_cb = _roomba_sensors_handler,
  129. .flags = BLE_GATT_CHR_F_READ,
  130. }, {
  131. .uuid = (ble_uuid_t*) &gatt_svr_chr_roomba_sensors_notify.u,
  132. .access_cb = _roomba_sensors_handler,
  133. .val_handle = &_sensors_val_handle,
  134. .flags = BLE_GATT_CHR_F_NOTIFY,
  135. }, {
  136. 0, /* no more characteristics in this service */
  137. }, }
  138. },
  139. {
  140. /* Device Information Service */
  141. .type = BLE_GATT_SVC_TYPE_PRIMARY,
  142. .uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_DEVINFO),
  143. .characteristics = (struct ble_gatt_chr_def[]) { {
  144. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_MANUFACTURER_NAME),
  145. .access_cb = _devinfo_handler,
  146. .flags = BLE_GATT_CHR_F_READ,
  147. }, {
  148. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_MODEL_NUMBER_STR),
  149. .access_cb = _devinfo_handler,
  150. .flags = BLE_GATT_CHR_F_READ,
  151. }, {
  152. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_SERIAL_NUMBER_STR),
  153. .access_cb = _devinfo_handler,
  154. .flags = BLE_GATT_CHR_F_READ,
  155. }, {
  156. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_FW_REV_STR),
  157. .access_cb = _devinfo_handler,
  158. .flags = BLE_GATT_CHR_F_READ,
  159. }, {
  160. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_HW_REV_STR),
  161. .access_cb = _devinfo_handler,
  162. .flags = BLE_GATT_CHR_F_READ,
  163. }, {
  164. 0, /* no more characteristics in this service */
  165. }, }
  166. },
  167. {
  168. /* Battery Level Service */
  169. .type = BLE_GATT_SVC_TYPE_PRIMARY,
  170. .uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_BAS),
  171. .characteristics = (struct ble_gatt_chr_def[]) { {
  172. .uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_BATTERY_LEVEL),
  173. .access_cb = _bas_handler,
  174. .flags = BLE_GATT_CHR_F_READ,
  175. }, {
  176. 0, /* no more characteristics in this service */
  177. }, }
  178. },
  179. {
  180. 0, /* no more services */
  181. },
  182. };
  183. int cmd_mode(int argc, char **argv);
  184. uint8_t get_mode(void);
  185. int switch_mode(int newmode);
  186. static uint8_t cmd_buf[20];
  187. static int cmd_buf_off = 0;
  188. void order66(void);
  189. static void parse_bt_char(uint8_t c)
  190. {
  191. uint8_t mode;
  192. cmd_buf[cmd_buf_off++] = c;
  193. if (c == 0xFF) {
  194. int len = cmd_buf_off - 1;
  195. cmd_buf_off = 0;
  196. if (len == 0)
  197. return;
  198. switch (cmd_buf[0]) {
  199. case 'M':
  200. mode = cmd_buf[1];
  201. if (len < 1)
  202. return;
  203. printf("Mode switch: %d\n", mode);
  204. if (mode <= ROOMBA_MODE_DOCK) {
  205. switch_mode(mode);
  206. }
  207. break;
  208. case 'B':
  209. printf("Order 66\n");
  210. order66();
  211. break;
  212. default:
  213. printf("Unknown command %02x\n", cmd_buf[0]);
  214. }
  215. }
  216. }
  217. static int _roomba_sensors_handler(
  218. uint16_t conn_handle, uint16_t attr_handle,
  219. struct ble_gatt_access_ctxt *ctxt, void *arg)
  220. {
  221. int rc = 0;
  222. uint16_t om_len;
  223. ble_uuid_t* read_uuid = (ble_uuid_t*) &gatt_svr_chr_roomba_sensors.u;
  224. static uint8_t ch;
  225. struct roomba_sensors_data *bt_sensors;
  226. puts("[BT] Sensor command");
  227. (void) conn_handle;
  228. (void) attr_handle;
  229. (void) arg;
  230. bt_sensors = roomba_sensors();
  231. printf("bt_sensors.valid = %s\n", bt_sensors->valid?"yes":"no");
  232. if (ble_uuid_cmp(ctxt->chr->uuid, read_uuid) == 0) {
  233. puts("access to characteristic 'roomba sensors'");
  234. rc = os_mbuf_append(ctxt->om, bt_sensors, sizeof(struct roomba_sensors_data));
  235. puts("");
  236. return rc;
  237. }
  238. puts("unhandled uuid!");
  239. return 1;
  240. }
  241. static int _roomba_ctrl_handler(
  242. uint16_t conn_handle, uint16_t attr_handle,
  243. struct ble_gatt_access_ctxt *ctxt, void *arg)
  244. {
  245. int rc = 0;
  246. uint16_t om_len;
  247. ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_roomba_ctl.u;
  248. static uint8_t ch;
  249. puts("[BT] Command");
  250. (void) conn_handle;
  251. (void) attr_handle;
  252. (void) arg;
  253. int mode = get_mode();
  254. if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) {
  255. puts("access to characteristic 'roomba ctl'");
  256. switch (ctxt->op) {
  257. case BLE_GATT_ACCESS_OP_READ_CHR:
  258. puts("read mode");
  259. /* send given data to the client */
  260. rc = os_mbuf_append(ctxt->om, &mode, sizeof(unsigned int));
  261. break;
  262. case BLE_GATT_ACCESS_OP_WRITE_CHR:
  263. rc = ble_hs_mbuf_to_flat(ctxt->om, &ch, 1, &om_len);
  264. printf("om_len = %d, char: %02x\n", om_len, ch);
  265. parse_bt_char(ch);
  266. break;
  267. case BLE_GATT_ACCESS_OP_READ_DSC:
  268. puts("read from descriptor");
  269. break;
  270. case BLE_GATT_ACCESS_OP_WRITE_DSC:
  271. puts("write to descriptor");
  272. break;
  273. default:
  274. puts("unhandled operation!");
  275. rc = 1;
  276. break;
  277. }
  278. puts("");
  279. return rc;
  280. }
  281. puts("unhandled uuid!");
  282. return 1;
  283. }
  284. static int _ips_handler(uint16_t conn_handle, uint16_t attr_handle,
  285. struct ble_gatt_access_ctxt *ctxt, void *arg)
  286. {
  287. (void)conn_handle;
  288. (void)attr_handle;
  289. (void)arg;
  290. int res;
  291. static uint32_t lat = 0x01020304, lon = 0x05060708;
  292. puts("[ACCESS] indoor positioning value");
  293. if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
  294. printf("[READ] ");
  295. if (ble_uuid_u16(ctxt->chr->uuid) == BLE_GATT_CHAR_LATITUDE) {
  296. printf("LAT\n");
  297. res = os_mbuf_append(ctxt->om, &lat, sizeof(lat));
  298. return (res == 0)? res: BLE_ATT_ERR_INSUFFICIENT_RES;
  299. }
  300. if (ble_uuid_u16(ctxt->chr->uuid) == BLE_GATT_CHAR_LONGITUDE) {
  301. printf("LON\n");
  302. res = os_mbuf_append(ctxt->om, &lon, sizeof(lon));
  303. return (res == 0)? res: BLE_ATT_ERR_INSUFFICIENT_RES;
  304. }
  305. } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
  306. printf("[WRITE] ");
  307. if (ble_uuid_u16(ctxt->chr->uuid) == BLE_GATT_CHAR_LATITUDE) {
  308. printf("LAT\n");
  309. memcpy(&lat, ctxt->om->om_databuf, sizeof(lat));
  310. res = os_mbuf_append(ctxt->om, &lat, sizeof(lat));
  311. return (res == 0)? res: BLE_ATT_ERR_INSUFFICIENT_RES;
  312. }
  313. if (ble_uuid_u16(ctxt->chr->uuid) == BLE_GATT_CHAR_LONGITUDE) {
  314. printf("LON\n");
  315. printf("%08x\n", *((unsigned int *)(ctxt->om->om_databuf)));
  316. printf("%08x\n", *((unsigned int *)(ctxt->om->om_databuf + 4)));
  317. memcpy(&lon, ctxt->om->om_databuf, sizeof(lon));
  318. res = os_mbuf_append(ctxt->om, &lon, sizeof(lon));
  319. return (res == 0)? res: BLE_ATT_ERR_INSUFFICIENT_RES;
  320. }
  321. }
  322. return BLE_ATT_ERR_INSUFFICIENT_RES;
  323. }
  324. static int _devinfo_handler(uint16_t conn_handle, uint16_t attr_handle,
  325. struct ble_gatt_access_ctxt *ctxt, void *arg)
  326. {
  327. (void)conn_handle;
  328. (void)attr_handle;
  329. (void)arg;
  330. const char *str;
  331. switch (ble_uuid_u16(ctxt->chr->uuid)) {
  332. case BLE_GATT_CHAR_MANUFACTURER_NAME:
  333. puts("[READ] device information service: manufacturer name value");
  334. str = _manufacturer_name;
  335. break;
  336. case BLE_GATT_CHAR_MODEL_NUMBER_STR:
  337. puts("[READ] device information service: model number value");
  338. str = _model_number;
  339. break;
  340. case BLE_GATT_CHAR_SERIAL_NUMBER_STR:
  341. puts("[READ] device information service: serial number value");
  342. str = _serial_number;
  343. break;
  344. case BLE_GATT_CHAR_FW_REV_STR:
  345. puts("[READ] device information service: firmware revision value");
  346. str = _fw_ver;
  347. break;
  348. case BLE_GATT_CHAR_HW_REV_STR:
  349. puts("[READ] device information service: hardware revision value");
  350. str = _hw_ver;
  351. break;
  352. default:
  353. return BLE_ATT_ERR_UNLIKELY;
  354. }
  355. int res = os_mbuf_append(ctxt->om, str, strlen(str));
  356. return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  357. }
  358. static int _bas_handler(uint16_t conn_handle, uint16_t attr_handle,
  359. struct ble_gatt_access_ctxt *ctxt, void *arg)
  360. {
  361. (void)conn_handle;
  362. (void)attr_handle;
  363. (void)arg;
  364. puts("[READ] battery level service: battery level value");
  365. uint8_t level = 50; /* this battery will never drain :-) */
  366. int res = os_mbuf_append(ctxt->om, &level, sizeof(level));
  367. return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
  368. }
  369. static int gap_event_cb(struct ble_gap_event *event, void *arg)
  370. {
  371. (void)arg;
  372. switch (event->type) {
  373. case BLE_GAP_EVENT_CONNECT:
  374. printf("Ev: connect, Status: %d\n", event->connect.status);
  375. if (event->connect.status) {
  376. _start_advertising();
  377. LED2_OFF;
  378. return 0;
  379. }
  380. LED2_ON;
  381. _conn_handle = event->connect.conn_handle;
  382. break;
  383. case BLE_GAP_EVENT_DISCONNECT:
  384. _start_advertising();
  385. break;
  386. case BLE_GAP_EVENT_SUBSCRIBE:
  387. if (event->subscribe.attr_handle == _ips_val_handle) {
  388. if (event->subscribe.cur_notify == 1) {
  389. }
  390. else {
  391. }
  392. }
  393. break;
  394. }
  395. return 0;
  396. }
  397. static void _start_advertising(void)
  398. {
  399. struct ble_gap_adv_params advp;
  400. int res;
  401. memset(&advp, 0, sizeof advp);
  402. advp.conn_mode = BLE_GAP_CONN_MODE_UND;
  403. advp.disc_mode = BLE_GAP_DISC_MODE_GEN;
  404. advp.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
  405. advp.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX;
  406. res = ble_gap_adv_start(nimble_riot_own_addr_type, NULL, BLE_HS_FOREVER,
  407. &advp, gap_event_cb, NULL);
  408. assert(res == 0);
  409. (void)res;
  410. }
  411. static void update_sensors(void)
  412. {
  413. struct os_mbuf *om;
  414. struct roomba_sensors_data *sens;
  415. printf("[GATT] Sensor values changed\n");
  416. sens = roomba_sensors();
  417. /* send data notification to GATT client */
  418. om = ble_hs_mbuf_from_flat(sens, sizeof(struct roomba_sensors_data));
  419. if (!om) {
  420. printf("[GATT] Error incapsulating sensor data in frame \n");
  421. return;
  422. }
  423. ble_gattc_notify_custom(_conn_handle, _sensors_val_handle, om);
  424. }
  425. void *gatt_srv(void *arg)
  426. {
  427. puts("NimBLE GATT server starting");
  428. int res = 0;
  429. msg_t msg;
  430. (void)res;
  431. /* setup local event queue (for handling heart rate updates) */
  432. /* verify and add our custom services */
  433. res = ble_gatts_count_cfg(gatt_svr_svcs);
  434. assert(res == 0);
  435. res = ble_gatts_add_svcs(gatt_svr_svcs);
  436. assert(res == 0);
  437. /* set the device name */
  438. ble_svc_gap_device_name_set(_device_name);
  439. /* reload the GATT server to link our added services */
  440. ble_gatts_start();
  441. /* configure and set the advertising data */
  442. uint8_t buf[BLE_HS_ADV_MAX_SZ];
  443. bluetil_ad_t ad;
  444. bluetil_ad_init_with_flags(&ad, buf, sizeof(buf), BLUETIL_AD_FLAGS_DEFAULT);
  445. uint16_t ips_uuid = BLE_GATT_SVC_IPS;
  446. bluetil_ad_add(&ad, BLE_GAP_AD_UUID16_INCOMP, &ips_uuid, sizeof(ips_uuid));
  447. bluetil_ad_add_name(&ad, _device_name);
  448. ble_gap_adv_set_data(ad.buf, ad.pos);
  449. /* start to advertise this node */
  450. _start_advertising();
  451. while (1) {
  452. if (msg_receive(&msg) >= 0) {
  453. (void)msg;
  454. update_sensors();
  455. }
  456. }
  457. /* run an event loop for handling the heart rate update events */
  458. //event_loop(&_eq);
  459. return 0;
  460. }