app_main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /* main.c - Application main entry point */
  2. /*
  3. * Copyright (c) 2015-2016 Intel Corporation
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include "services/bas.h"
  8. #include "services/dis.h"
  9. #include <errno.h>
  10. #include <stddef.h>
  11. #include <string.h>
  12. #include "base/byteorder.h"
  13. #include "base/types.h"
  14. #include <bluetooth/bluetooth.h>
  15. #include <bluetooth/conn.h>
  16. #include <bluetooth/gatt.h>
  17. #include <bluetooth/hci.h>
  18. #include <bluetooth/uuid.h>
  19. #include <logging/bt_log_impl.h>
  20. #include "common\timer.h"
  21. /* Idle timer */
  22. struct k_timer idle_work;
  23. #define CSC_SUPPORTED_LOCATIONS \
  24. { \
  25. CSC_LOC_OTHER, CSC_LOC_FRONT_WHEEL, CSC_LOC_REAR_WHEEL, CSC_LOC_LEFT_CRANK, \
  26. CSC_LOC_RIGHT_CRANK \
  27. }
  28. #define CSC_FEATURE (CSC_FEAT_WHEEL_REV | CSC_FEAT_CRANK_REV | CSC_FEAT_MULTI_SENSORS)
  29. /* CSC Sensor Locations */
  30. #define CSC_LOC_OTHER 0x00
  31. #define CSC_LOC_TOP_OF_SHOE 0x01
  32. #define CSC_LOC_IN_SHOE 0x02
  33. #define CSC_LOC_HIP 0x03
  34. #define CSC_LOC_FRONT_WHEEL 0x04
  35. #define CSC_LOC_LEFT_CRANK 0x05
  36. #define CSC_LOC_RIGHT_CRANK 0x06
  37. #define CSC_LOC_LEFT_PEDAL 0x07
  38. #define CSC_LOC_RIGHT_PEDAL 0x08
  39. #define CSC_LOC_FRONT_HUB 0x09
  40. #define CSC_LOC_REAR_DROPOUT 0x0a
  41. #define CSC_LOC_CHAINSTAY 0x0b
  42. #define CSC_LOC_REAR_WHEEL 0x0c
  43. #define CSC_LOC_REAR_HUB 0x0d
  44. #define CSC_LOC_CHEST 0x0e
  45. /* CSC Application error codes */
  46. #define CSC_ERR_IN_PROGRESS 0x80
  47. #define CSC_ERR_CCC_CONFIG 0x81
  48. /* SC Control Point Opcodes */
  49. #define SC_CP_OP_SET_CWR 0x01
  50. #define SC_CP_OP_CALIBRATION 0x02
  51. #define SC_CP_OP_UPDATE_LOC 0x03
  52. #define SC_CP_OP_REQ_SUPP_LOC 0x04
  53. #define SC_CP_OP_RESPONSE 0x10
  54. /* SC Control Point Response Values */
  55. #define SC_CP_RSP_SUCCESS 0x01
  56. #define SC_CP_RSP_OP_NOT_SUPP 0x02
  57. #define SC_CP_RSP_INVAL_PARAM 0x03
  58. #define SC_CP_RSP_FAILED 0x04
  59. /* CSC Feature */
  60. #define CSC_FEAT_WHEEL_REV BIT(0)
  61. #define CSC_FEAT_CRANK_REV BIT(1)
  62. #define CSC_FEAT_MULTI_SENSORS BIT(2)
  63. /* CSC Measurement Flags */
  64. #define CSC_WHEEL_REV_DATA_PRESENT BIT(0)
  65. #define CSC_CRANK_REV_DATA_PRESENT BIT(1)
  66. /* Cycling Speed and Cadence Service declaration */
  67. static uint32_t cwr; /* Cumulative Wheel Revolutions */
  68. static uint8_t supported_locations[] = CSC_SUPPORTED_LOCATIONS;
  69. static uint8_t sensor_location; /* Current Sensor Location */
  70. static bool csc_simulate;
  71. static bool ctrl_point_configured;
  72. static void csc_meas_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
  73. {
  74. csc_simulate = value == BT_GATT_CCC_NOTIFY;
  75. }
  76. static void ctrl_point_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
  77. {
  78. ctrl_point_configured = value == BT_GATT_CCC_INDICATE;
  79. }
  80. static ssize_t read_location(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
  81. uint16_t len, uint16_t offset)
  82. {
  83. uint8_t *value = attr->user_data;
  84. return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(*value));
  85. }
  86. static ssize_t read_csc_feature(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
  87. uint16_t len, uint16_t offset)
  88. {
  89. uint16_t csc_feature = CSC_FEATURE;
  90. return bt_gatt_attr_read(conn, attr, buf, len, offset, &csc_feature, sizeof(csc_feature));
  91. }
  92. static void ctrl_point_ind(struct bt_conn *conn, uint8_t req_op, uint8_t status, const void *data,
  93. uint16_t data_len);
  94. struct write_sc_ctrl_point_req
  95. {
  96. uint8_t op;
  97. union
  98. {
  99. uint32_t cwr;
  100. uint8_t location;
  101. };
  102. } __packed;
  103. static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
  104. const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
  105. {
  106. const struct write_sc_ctrl_point_req *req = buf;
  107. uint8_t status;
  108. int i;
  109. if (!ctrl_point_configured)
  110. {
  111. return BT_GATT_ERR(CSC_ERR_CCC_CONFIG);
  112. }
  113. if (!len)
  114. {
  115. return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
  116. }
  117. switch (req->op)
  118. {
  119. case SC_CP_OP_SET_CWR:
  120. if (len != sizeof(req->op) + sizeof(req->cwr))
  121. {
  122. status = SC_CP_RSP_INVAL_PARAM;
  123. break;
  124. }
  125. cwr = sys_le32_to_cpu(req->cwr);
  126. status = SC_CP_RSP_SUCCESS;
  127. break;
  128. case SC_CP_OP_UPDATE_LOC:
  129. if (len != sizeof(req->op) + sizeof(req->location))
  130. {
  131. status = SC_CP_RSP_INVAL_PARAM;
  132. break;
  133. }
  134. /* Break if the requested location is the same as current one */
  135. if (req->location == sensor_location)
  136. {
  137. status = SC_CP_RSP_SUCCESS;
  138. break;
  139. }
  140. /* Pre-set status */
  141. status = SC_CP_RSP_INVAL_PARAM;
  142. /* Check if requested location is supported */
  143. for (i = 0; i < ARRAY_SIZE(supported_locations); i++)
  144. {
  145. if (supported_locations[i] == req->location)
  146. {
  147. sensor_location = req->location;
  148. status = SC_CP_RSP_SUCCESS;
  149. break;
  150. }
  151. }
  152. break;
  153. case SC_CP_OP_REQ_SUPP_LOC:
  154. if (len != sizeof(req->op))
  155. {
  156. status = SC_CP_RSP_INVAL_PARAM;
  157. break;
  158. }
  159. /* Indicate supported locations and return */
  160. ctrl_point_ind(conn, req->op, SC_CP_RSP_SUCCESS, &supported_locations,
  161. sizeof(supported_locations));
  162. return len;
  163. default:
  164. status = SC_CP_RSP_OP_NOT_SUPP;
  165. }
  166. ctrl_point_ind(conn, req->op, status, NULL, 0);
  167. return len;
  168. }
  169. BT_GATT_SERVICE_DEFINE(
  170. csc_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_CSC),
  171. BT_GATT_CHARACTERISTIC(BT_UUID_CSC_MEASUREMENT, BT_GATT_CHRC_NOTIFY, 0x00, NULL, NULL,
  172. NULL),
  173. BT_GATT_CCC(csc_meas_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
  174. BT_GATT_CHARACTERISTIC(BT_UUID_SENSOR_LOCATION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
  175. read_location, NULL, &sensor_location),
  176. BT_GATT_CHARACTERISTIC(BT_UUID_CSC_FEATURE, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
  177. read_csc_feature, NULL, NULL),
  178. BT_GATT_CHARACTERISTIC(BT_UUID_SC_CONTROL_POINT, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE,
  179. BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &sensor_location),
  180. BT_GATT_CCC(ctrl_point_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), );
  181. struct sc_ctrl_point_ind
  182. {
  183. uint8_t op;
  184. uint8_t req_op;
  185. uint8_t status;
  186. uint8_t data[];
  187. } __packed;
  188. static void ctrl_point_ind(struct bt_conn *conn, uint8_t req_op, uint8_t status, const void *data,
  189. uint16_t data_len)
  190. {
  191. struct sc_ctrl_point_ind *ind;
  192. uint8_t buf[sizeof(*ind) + data_len];
  193. ind = (void *)buf;
  194. ind->op = SC_CP_OP_RESPONSE;
  195. ind->req_op = req_op;
  196. ind->status = status;
  197. /* Send data (supported locations) if present */
  198. if (data && data_len)
  199. {
  200. memcpy(ind->data, data, data_len);
  201. }
  202. bt_gatt_notify(conn, &csc_svc.attrs[8], buf, sizeof(buf));
  203. }
  204. struct csc_measurement_nfy
  205. {
  206. uint8_t flags;
  207. uint8_t data[];
  208. } __packed;
  209. struct wheel_rev_data_nfy
  210. {
  211. uint32_t cwr;
  212. uint16_t lwet;
  213. } __packed;
  214. struct crank_rev_data_nfy
  215. {
  216. uint16_t ccr;
  217. uint16_t lcet;
  218. } __packed;
  219. static void measurement_nfy(struct bt_conn *conn, uint32_t tmp_cwr, uint16_t lwet, uint16_t ccr,
  220. uint16_t lcet)
  221. {
  222. struct csc_measurement_nfy *nfy;
  223. uint8_t buf[sizeof(*nfy) + (tmp_cwr ? sizeof(struct wheel_rev_data_nfy) : 0) +
  224. (ccr ? sizeof(struct crank_rev_data_nfy) : 0)];
  225. uint16_t len = 0U;
  226. nfy = (void *)buf;
  227. nfy->flags = 0U;
  228. /* Send Wheel Revolution data is present */
  229. if (tmp_cwr)
  230. {
  231. struct wheel_rev_data_nfy data;
  232. nfy->flags |= CSC_WHEEL_REV_DATA_PRESENT;
  233. data.cwr = sys_cpu_to_le32(tmp_cwr);
  234. data.lwet = sys_cpu_to_le16(lwet);
  235. memcpy(nfy->data, &data, sizeof(data));
  236. len += sizeof(data);
  237. }
  238. /* Send Crank Revolution data is present */
  239. if (ccr)
  240. {
  241. struct crank_rev_data_nfy data;
  242. nfy->flags |= CSC_CRANK_REV_DATA_PRESENT;
  243. data.ccr = sys_cpu_to_le16(ccr);
  244. data.lcet = sys_cpu_to_le16(lcet);
  245. memcpy(nfy->data + len, &data, sizeof(data));
  246. }
  247. bt_gatt_notify(NULL, &csc_svc.attrs[1], buf, sizeof(buf));
  248. }
  249. static uint16_t lwet; /* Last Wheel Event Time */
  250. static uint16_t ccr; /* Cumulative Crank Revolutions */
  251. static uint16_t lcet; /* Last Crank Event Time */
  252. static void csc_simulation(void)
  253. {
  254. static uint8_t i;
  255. uint32_t rand = 0x11223344; // sys_rand32_get();
  256. bool nfy_crank = false, nfy_wheel = false;
  257. /* Measurements don't have to be updated every second */
  258. if (!(i % 2))
  259. {
  260. lwet += 1050 + rand % 50;
  261. cwr += 2U;
  262. nfy_wheel = true;
  263. }
  264. if (!(i % 3))
  265. {
  266. lcet += 1000 + rand % 50;
  267. ccr += 1U;
  268. nfy_crank = true;
  269. }
  270. /*
  271. * In typical applications, the CSC Measurement characteristic is
  272. * notified approximately once per second. This interval may vary
  273. * and is determined by the Server and not required to be configurable
  274. * by the Client.
  275. */
  276. measurement_nfy(NULL, nfy_wheel ? cwr : 0, nfy_wheel ? lwet : 0, nfy_crank ? ccr : 0,
  277. nfy_crank ? lcet : 0);
  278. /*
  279. * The Last Crank Event Time value and Last Wheel Event Time roll over
  280. * every 64 seconds.
  281. */
  282. if (!(i % 64))
  283. {
  284. lcet = 0U;
  285. lwet = 0U;
  286. i = 0U;
  287. }
  288. i++;
  289. }
  290. static void connected(struct bt_conn *conn, uint8_t err)
  291. {
  292. if (err)
  293. {
  294. printk("Connection failed (err 0x%02x)\n", err);
  295. }
  296. else
  297. {
  298. printk("Connected\n");
  299. }
  300. }
  301. static void disconnected(struct bt_conn *conn, uint8_t reason)
  302. {
  303. printk("Disconnected (reason 0x%02x)\n", reason);
  304. }
  305. static struct bt_conn_cb conn_callbacks = {
  306. .connected = connected,
  307. .disconnected = disconnected,
  308. };
  309. static const struct bt_data ad[] = {
  310. BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
  311. BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_CSC_VAL),
  312. BT_UUID_16_ENCODE(BT_UUID_BAS_VAL))};
  313. static void bas_notify(void)
  314. {
  315. uint8_t battery_level = bt_bas_get_battery_level();
  316. battery_level--;
  317. if (!battery_level)
  318. {
  319. battery_level = 100U;
  320. }
  321. bt_bas_set_battery_level(battery_level);
  322. }
  323. static void idle_timeout(struct k_timer *work)
  324. {
  325. /* CSC simulation */
  326. if (csc_simulate)
  327. {
  328. csc_simulation();
  329. }
  330. /* Battery level simulation */
  331. bas_notify();
  332. }
  333. void bt_ready(int err)
  334. {
  335. if (err)
  336. {
  337. printk("Bluetooth init failed (err %d)\n", err);
  338. return;
  339. }
  340. printk("Bluetooth initialized\n");
  341. extern struct bt_gatt_service_static _1_gatt_svc;
  342. extern struct bt_gatt_service_static _2_gap_svc;
  343. bt_gatt_service_init(5, _1_gatt_svc, _2_gap_svc, dis_svc, bas_svc, csc_svc);
  344. bt_conn_cb_register(&conn_callbacks);
  345. #if defined(CONFIG_BT_FIXED_PASSKEY)
  346. bt_passkey_set(1234);
  347. #endif
  348. k_timer_init(&idle_work, idle_timeout, NULL);
  349. k_timer_start(&idle_work, K_SECONDS(1), K_SECONDS(1));
  350. err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
  351. if (err)
  352. {
  353. printk("Advertising failed to start (err %d)\n", err);
  354. return;
  355. }
  356. printk("Advertising successfully started\n");
  357. }
  358. void app_polling_work(void)
  359. {
  360. }