seos_hci.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. #include "seos_hci_i.h"
  2. #define TAG "SeosHci"
  3. #define OGF_LINK_CTL 0x01
  4. #define OCF_DISCONNECT 0x0006
  5. #define OGF_HOST_CTL 0x03
  6. #define OCF_SET_EVENT_MASK 0x0001
  7. #define OCF_RESET 0x0003
  8. #define OCF_READ_LE_HOST_SUPPORTED 0x006c
  9. #define OCF_WRITE_LE_HOST_SUPPORTED 0x006d
  10. #define OGF_INFO_PARAM 0x04
  11. #define OCF_READ_LOCAL_VERSION 0x0001
  12. #define OCF_READ_BUFFER_SIZE 0x0005
  13. #define OCF_READ_BD_ADDR 0x0009
  14. #define OGF_STATUS_PARAM 0x05
  15. #define OCF_READ_RSSI 0x0005
  16. #define OGF_LE_CTL 0x08
  17. #define OCF_LE_SET_EVENT_MASK 0x0001
  18. #define OCF_LE_READ_BUFFER_SIZE 0x0002
  19. #define OCF_LE_READ_LOCAL_SUPPORTED_FEATURES 0x0003
  20. #define OCF_LE_SET_RANDOM_ADDRESS 0x0005
  21. #define OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006
  22. #define OCF_LE_SET_ADVERTISING_DATA 0x0008
  23. #define OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009
  24. #define OCF_LE_SET_ADVERTISE_ENABLE 0x000a
  25. #define OCF_LE_SET_SCAN_PARAMETERS 0x000b
  26. #define OCF_LE_SET_SCAN_ENABLE 0x000c
  27. #define OCF_LE_CREATE_CONNECTION 0x000d
  28. #define OGF_VENDOR_CTL 0x3F
  29. #define OCF_LE_LTK_NEG_REPLY 0x001B
  30. /* Obtain OGF from OpCode */
  31. #define BT_OGF(opcode) (((opcode) >> 10) & 0x3f)
  32. /* Obtain OCF from OpCode */
  33. #define BT_OCF(opcode) ((opcode) & 0x3FF)
  34. #define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10))
  35. #define BT_HCI_EVT_DISCONN_COMPLETE 0x05 // HCI_Disconnection_Complete
  36. #define BT_HCI_EVT_QOS_SETUP_COMPLETE 0x0d
  37. #define BT_HCI_EVT_CMD_COMPLETE 0x0e
  38. #define BT_HCI_EVT_CMD_STATUS 0x0f
  39. #define BT_HCI_EVT_HARDWARE_ERROR 0x10
  40. #define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13
  41. #define BT_HCI_EVT_LE_META 0x3e // HCI_LE_Connection_Complete
  42. #define HCI_LE_CONNECTION_COMPLETE 0x01
  43. #define HCI_LE_ADVERTISING_REPORT 0x02
  44. // Consider making this an enum that shifts a bit in the apropriate amount
  45. #define CAP_TWIST_AND_GO 0x02
  46. #define CAP_ALLOW_TAP 0x04
  47. #define CAP_APP_SPECIFIC 0x08
  48. #define CAP_ENHANCED_TAP 0x40
  49. static uint8_t seos_reader_service_backwards[] =
  50. {0x02, 0x00, 0x00, 0x7a, 0x17, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00};
  51. static uint8_t seos_cred_service_backwards[] =
  52. {0x02, 0x00, 0x00, 0x7a, 0x17, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00};
  53. static uint8_t empty_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  54. // Occationally scan stop's completion doesn't get caught.
  55. // Use the timer callback to call it again
  56. void seos_hci_timer(void* context) {
  57. FURI_LOG_I(TAG, "RUN TIMER");
  58. SeosHci* seos_hci = (SeosHci*)context;
  59. if(seos_hci->mode == BLE_PERIPHERAL) {
  60. seos_hci_enable_advertising(seos_hci, seos_hci->adv_status);
  61. } else if(seos_hci->mode == BLE_CENTRAL) {
  62. seos_hci_set_scan(seos_hci, seos_hci->scan_status);
  63. }
  64. }
  65. void seos_hci_clear_known_addresses(SeosHci* seos_hci) {
  66. for(size_t i = 0; i < MAX_SCANNED_ADDRESS; i++) {
  67. ScanAddress* scan_address = &seos_hci->scanned_addresses[i];
  68. scan_address->used = false;
  69. memset(scan_address->address, 0, MAC_ADDRESS_LEN);
  70. }
  71. }
  72. SeosHci* seos_hci_alloc(Seos* seos) {
  73. SeosHci* seos_hci = malloc(sizeof(SeosHci));
  74. memset(seos_hci, 0, sizeof(SeosHci));
  75. seos_hci->device_found = false;
  76. seos_hci->connection_handle = 0;
  77. seos_hci->seos = seos;
  78. seos_hci->seos_hci_h5 = seos_hci_h5_alloc();
  79. seos_hci->timer = furi_timer_alloc(seos_hci_timer, FuriTimerTypeOnce, seos_hci);
  80. seos_hci_h5_set_init_callback(seos_hci->seos_hci_h5, seos_hci_init, seos_hci);
  81. seos_hci_h5_set_receive_callback(seos_hci->seos_hci_h5, seos_hci_recv, seos_hci);
  82. seos_hci_clear_known_addresses(seos_hci);
  83. return seos_hci;
  84. }
  85. void seos_hci_free(SeosHci* seos_hci) {
  86. furi_assert(seos_hci);
  87. if(furi_timer_is_running(seos_hci->timer)) {
  88. FURI_LOG_D(TAG, "clear timer");
  89. furi_timer_stop(seos_hci->timer);
  90. }
  91. furi_timer_free(seos_hci->timer);
  92. seos_hci_h5_set_init_callback(seos_hci->seos_hci_h5, NULL, NULL);
  93. seos_hci_h5_set_receive_callback(seos_hci->seos_hci_h5, NULL, NULL);
  94. seos_hci_h5_free(seos_hci->seos_hci_h5);
  95. free(seos_hci);
  96. }
  97. void seos_hci_start(SeosHci* seos_hci, BleMode mode, FlowMode flow_mode) {
  98. seos_hci->device_found = false;
  99. seos_hci->connection_handle = 0;
  100. seos_hci->flow_mode = flow_mode;
  101. seos_hci->mode = mode;
  102. seos_hci_h5_start(seos_hci->seos_hci_h5);
  103. }
  104. void seos_hci_stop(SeosHci* seos_hci) {
  105. if(seos_hci->connection_handle > 0) {
  106. uint16_t opcode = BT_OP(OGF_LINK_CTL, OCF_DISCONNECT);
  107. BitBuffer* disconnect = bit_buffer_alloc(5);
  108. bit_buffer_append_bytes(disconnect, (uint8_t*)&opcode, sizeof(opcode));
  109. bit_buffer_append_bytes(
  110. disconnect,
  111. (uint8_t*)&seos_hci->connection_handle,
  112. sizeof(seos_hci->connection_handle));
  113. bit_buffer_append_byte(disconnect, 0x00);
  114. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, disconnect);
  115. }
  116. seos_hci->device_found = false;
  117. seos_hci->connection_handle = 0;
  118. seos_hci_h5_stop(seos_hci->seos_hci_h5);
  119. if(seos_hci->mode == BLE_PERIPHERAL) {
  120. if(seos_hci->adv_status) {
  121. seos_hci_enable_advertising(seos_hci, false);
  122. }
  123. } else if(seos_hci->mode == BLE_CENTRAL) {
  124. if(seos_hci->scan_status) {
  125. seos_hci_set_scan(seos_hci, false);
  126. }
  127. }
  128. if(furi_timer_is_running(seos_hci->timer)) {
  129. FURI_LOG_D(TAG, "clear timer");
  130. furi_timer_stop(seos_hci->timer);
  131. }
  132. seos_hci_clear_known_addresses(seos_hci);
  133. }
  134. bool seos_hci_known_address(SeosHci* seos_hci, const uint8_t Address[MAC_ADDRESS_LEN]) {
  135. // Does it exist in the list?
  136. for(size_t i = 0; i < MAX_SCANNED_ADDRESS; i++) {
  137. ScanAddress* scan_address = &seos_hci->scanned_addresses[i];
  138. if(scan_address->used) {
  139. if(memcmp(Address, scan_address->address, MAC_ADDRESS_LEN) == 0) {
  140. return true;
  141. }
  142. }
  143. }
  144. // Not in list, add
  145. for(size_t i = 0; i < MAX_SCANNED_ADDRESS; i++) {
  146. ScanAddress* scan_address = &seos_hci->scanned_addresses[i];
  147. if(!scan_address->used) {
  148. memcpy(scan_address->address, Address, MAC_ADDRESS_LEN);
  149. scan_address->used = true;
  150. // It wasn't previously known
  151. return false;
  152. }
  153. }
  154. return false;
  155. }
  156. void seos_hci_handle_event_cmd_complete_ogf_host(SeosHci* seos_hci, uint16_t OCF, BitBuffer* frame) {
  157. UNUSED(frame);
  158. BitBuffer* message = bit_buffer_alloc(128);
  159. switch(OCF) {
  160. case OCF_RESET:
  161. uint8_t le_read_local_supported_features[] = {0x03, 0x20, 0x00};
  162. bit_buffer_append_bytes(
  163. message, le_read_local_supported_features, sizeof(le_read_local_supported_features));
  164. break;
  165. case OCF_SET_EVENT_MASK:
  166. uint8_t set_le_event_mask[] = {
  167. 0x01, 0x20, 0x08, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  168. bit_buffer_append_bytes(message, set_le_event_mask, sizeof(set_le_event_mask));
  169. break;
  170. case OCF_READ_LE_HOST_SUPPORTED:
  171. FURI_LOG_D(TAG, "OCF_READ_LE_HOST_SUPPORTED");
  172. break;
  173. case OCF_WRITE_LE_HOST_SUPPORTED:
  174. FURI_LOG_D(TAG, "OCF_WRITE_LE_HOST_SUPPORTED");
  175. uint8_t read_le_host_supported[] = {0x6c, 0x0c, 0x00};
  176. bit_buffer_append_bytes(message, read_le_host_supported, sizeof(read_le_host_supported));
  177. break;
  178. default:
  179. FURI_LOG_W(TAG, "Unhandled OCF %04x", OCF);
  180. break;
  181. }
  182. if(bit_buffer_get_size_bytes(message) > 0) {
  183. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  184. }
  185. bit_buffer_free(message);
  186. }
  187. void seos_hci_handle_event_cmd_complete_ogf_info(SeosHci* seos_hci, uint16_t OCF, BitBuffer* frame) {
  188. UNUSED(frame);
  189. BitBuffer* message = bit_buffer_alloc(128);
  190. switch(OCF) {
  191. case OCF_READ_LOCAL_VERSION:
  192. FURI_LOG_D(TAG, "OCF_READ_LOCAL_VERSION");
  193. uint8_t read_bd_addr[] = {0x09, 0x10, 0x00};
  194. bit_buffer_append_bytes(message, read_bd_addr, sizeof(read_bd_addr));
  195. break;
  196. case OCF_READ_BD_ADDR:
  197. // 040e0a05091000 e2f284 dad4d4
  198. FURI_LOG_D(TAG, "OCF_READ_BD_ADDR");
  199. if(memcmp(bit_buffer_get_data(frame) + 7, empty_mac, sizeof(empty_mac)) == 0) {
  200. uint8_t vendor_set_addr[] = {0x06, 0xfc, 0x06, 0x0, 0x0, 0x1, 0x2, 0x21, 0xAD};
  201. bit_buffer_append_bytes(message, vendor_set_addr, sizeof(vendor_set_addr));
  202. } else {
  203. uint16_t opcode = BT_OP(OGF_LE_CTL, OCF_LE_READ_BUFFER_SIZE);
  204. uint8_t length = 0;
  205. bit_buffer_append_bytes(message, (uint8_t*)&opcode, sizeof(opcode));
  206. bit_buffer_append_byte(message, length);
  207. }
  208. break;
  209. default:
  210. FURI_LOG_W(TAG, "Unhandled OCF %04x", OCF);
  211. break;
  212. }
  213. if(bit_buffer_get_size_bytes(message) > 0) {
  214. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  215. }
  216. bit_buffer_free(message);
  217. }
  218. void seos_hci_handle_event_cmd_complete_ogf_le(SeosHci* seos_hci, uint16_t OCF, BitBuffer* frame) {
  219. UNUSED(frame);
  220. BitBuffer* message = bit_buffer_alloc(128);
  221. switch(OCF) {
  222. case OCF_LE_SET_EVENT_MASK:
  223. uint8_t read_local_version[] = {0x01, 0x10, 0x00};
  224. bit_buffer_append_bytes(message, read_local_version, sizeof(read_local_version));
  225. break;
  226. case OCF_LE_READ_BUFFER_SIZE:
  227. FURI_LOG_D(TAG, "OCF_LE_READ_BUFFER_SIZE");
  228. uint8_t le_set_random_address[] = {0x05, 0x20, 0x06, 0xCA, 0xFE, 0x00, 0x00, 0x00, 0x03};
  229. bit_buffer_append_bytes(message, le_set_random_address, sizeof(le_set_random_address));
  230. break;
  231. case OCF_LE_SET_ADVERTISING_DATA:
  232. seos_hci_enable_advertising(seos_hci, true);
  233. break;
  234. case OCF_LE_SET_SCAN_RESPONSE_DATA:
  235. uint8_t flow_mode_byte = seos_hci->flow_mode == FLOW_READER ? 0x00 : 0x01;
  236. // TODO: Use seos_reader_service_backwards
  237. uint8_t adv_data[] = {0x08, 0x20, 0x20, 0x15, 0x02, 0x01, 0x06, 0x11, 0x07,
  238. 0x02, 0x00, 0x00, 0x7a, 0x17, 0x00, 0x00, 0x80, 0x00,
  239. 0x10, 0x00, 0x00, flow_mode_byte, 0x98, 0x00, 0x00, 0x00, 0x00,
  240. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  241. bit_buffer_append_bytes(message, adv_data, sizeof(adv_data));
  242. break;
  243. case OCF_LE_SET_ADVERTISE_ENABLE:
  244. if(furi_timer_is_running(seos_hci->timer)) {
  245. FURI_LOG_D(TAG, "clear timer");
  246. furi_timer_stop(seos_hci->timer);
  247. }
  248. uint8_t status = bit_buffer_get_byte(frame, 6);
  249. if(status == 0) {
  250. if(seos_hci->adv_status) {
  251. FURI_LOG_I(TAG, "*** Advertising enabled ***");
  252. view_dispatcher_send_custom_event(
  253. seos_hci->seos->view_dispatcher, SeosCustomEventAdvertising);
  254. } else {
  255. FURI_LOG_I(TAG, "*** Advertising disabled ***");
  256. }
  257. } else {
  258. FURI_LOG_W(TAG, "Advertising enabled FAILED");
  259. }
  260. break;
  261. case OCF_LE_SET_SCAN_PARAMETERS:
  262. seos_hci_set_scan(seos_hci, true);
  263. break;
  264. case OCF_LE_SET_SCAN_ENABLE:
  265. if(furi_timer_is_running(seos_hci->timer)) {
  266. FURI_LOG_D(TAG, "clear timer");
  267. furi_timer_stop(seos_hci->timer);
  268. }
  269. if(seos_hci->scan_status) { // enabled
  270. FURI_LOG_I(TAG, "Scan enable complete. new state: %d", seos_hci->scan_status);
  271. view_dispatcher_send_custom_event(
  272. seos_hci->seos->view_dispatcher, SeosCustomEventScan);
  273. } else if(seos_hci->device_found) {
  274. // Scanning stopped, try to connect
  275. seos_hci_connect(seos_hci);
  276. }
  277. break;
  278. case OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:
  279. // FURI_LOG_D(TAG, "Local Supported Features");
  280. uint8_t set_event_mask[] = {
  281. 0x01, 0x0c, 0x08, 0xff, 0xff, 0xfb, 0xff, 0x07, 0xf8, 0xbf, 0x3d};
  282. bit_buffer_append_bytes(message, set_event_mask, sizeof(set_event_mask));
  283. break;
  284. case OCF_LE_SET_RANDOM_ADDRESS:
  285. // FURI_LOG_D(TAG, "opcode = %04x", BT_OP(0x3f, 0x0006)); <--- reverse this in byte array
  286. uint8_t vendor_set_addr[] = {0x06, 0xfc, 0x06, 0x0, 0x0, 0x1, 0x2, 0x21, 0xAD};
  287. bit_buffer_append_bytes(message, vendor_set_addr, sizeof(vendor_set_addr));
  288. break;
  289. case OCF_LE_SET_ADVERTISING_PARAMETERS:
  290. // TODO: make this more dynamic
  291. uint8_t capabilities = CAP_TWIST_AND_GO | CAP_ALLOW_TAP | CAP_APP_SPECIFIC |
  292. CAP_ENHANCED_TAP;
  293. int8_t tap_rssi = -75;
  294. int8_t twist_rssi = -75;
  295. int8_t seamless_rssi = -75;
  296. int8_t app_rssi = -75;
  297. uint8_t mfg_data[] = {0x14, 0xff, 0x2e, 0x01, 0x15, capabilities,
  298. tap_rssi, twist_rssi, seamless_rssi, app_rssi, 0x2a, 0x46,
  299. 0x4c, 0x30, 0x4b, 0x37, 0x5a, 0x30,
  300. 0x31, 0x55, 0x31};
  301. uint8_t device_name[] = {0x08, 0x09, 0x46, 0x6c, 0x69, 0x70, 0x70, 0x65, 0x72};
  302. uint8_t ad_len = 0;
  303. ad_len += sizeof(device_name);
  304. ad_len += sizeof(mfg_data);
  305. uint8_t header[] = {0x09, 0x20, 0x20, ad_len};
  306. bit_buffer_append_bytes(message, header, sizeof(header));
  307. bit_buffer_append_bytes(message, device_name, sizeof(device_name));
  308. bit_buffer_append_bytes(message, mfg_data, sizeof(mfg_data));
  309. for(int i = 0; i < (31 - ad_len); i++) {
  310. bit_buffer_append_byte(message, 0);
  311. }
  312. break;
  313. default:
  314. FURI_LOG_W(TAG, "Unhandled OCF %04x", OCF);
  315. break;
  316. }
  317. if(bit_buffer_get_size_bytes(message) > 0) {
  318. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  319. }
  320. bit_buffer_free(message);
  321. }
  322. void seos_hci_handle_event_cmd_complete_ogf_vendor(
  323. SeosHci* seos_hci,
  324. uint16_t OCF,
  325. BitBuffer* frame) {
  326. UNUSED(frame);
  327. BitBuffer* message = bit_buffer_alloc(128);
  328. switch(OCF) {
  329. case 0x0006:
  330. if(seos_hci->mode == BLE_PERIPHERAL) {
  331. // Flipper as Reader
  332. uint8_t adv_param[] = {
  333. 0x06,
  334. 0x20,
  335. 0x0f,
  336. 0xa0,
  337. 0x00,
  338. 0xa0,
  339. 0x00,
  340. 0x00,
  341. 0x00,
  342. 0x01,
  343. 0xDE,
  344. 0xAF,
  345. 0xBE,
  346. 0xEF,
  347. 0xCA,
  348. 0xFE,
  349. 0x07,
  350. 0x00};
  351. bit_buffer_append_bytes(message, adv_param, sizeof(adv_param));
  352. } else if(seos_hci->mode == BLE_CENTRAL) {
  353. // Flipper as device/credential
  354. seos_hci_send_scan_params(seos_hci);
  355. }
  356. break;
  357. default:
  358. FURI_LOG_W(TAG, "Unhandled OCF %04x", OCF);
  359. break;
  360. }
  361. if(bit_buffer_get_size_bytes(message) > 0) {
  362. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  363. }
  364. bit_buffer_free(message);
  365. }
  366. void seos_hci_handle_event_cmd_complete(SeosHci* seos_hci, BitBuffer* frame) {
  367. BitBuffer* message = bit_buffer_alloc(128);
  368. const uint8_t* data = bit_buffer_get_data(frame);
  369. uint8_t event_type = data[0];
  370. uint8_t sub_event_type = data[1];
  371. uint8_t ncmd = data[3];
  372. uint16_t cmd = data[5] << 8 | data[4];
  373. uint8_t status = data[6];
  374. if(status == 0) {
  375. /*
  376. FURI_LOG_D(
  377. TAG,
  378. "event %d sub event %d ncmd %d cmd %04x status %d",
  379. event_type,
  380. sub_event_type,
  381. ncmd,
  382. cmd,
  383. status);
  384. */
  385. } else {
  386. FURI_LOG_W(
  387. TAG,
  388. "event %d sub event %d ncmd %d cmd %d status %d",
  389. event_type,
  390. sub_event_type,
  391. ncmd,
  392. cmd,
  393. status);
  394. bit_buffer_free(message);
  395. return;
  396. }
  397. uint16_t OGF = BT_OGF(cmd);
  398. uint16_t OCF = BT_OCF(cmd);
  399. // FURI_LOG_D(TAG, "OGF = %04x OCF = %04x", OGF, OCF);
  400. switch(OGF) {
  401. case OGF_HOST_CTL:
  402. seos_hci_handle_event_cmd_complete_ogf_host(seos_hci, OCF, frame);
  403. break;
  404. case OGF_INFO_PARAM:
  405. seos_hci_handle_event_cmd_complete_ogf_info(seos_hci, OCF, frame);
  406. break;
  407. case OGF_LE_CTL:
  408. seos_hci_handle_event_cmd_complete_ogf_le(seos_hci, OCF, frame);
  409. break;
  410. case OGF_VENDOR_CTL:
  411. seos_hci_handle_event_cmd_complete_ogf_vendor(seos_hci, OCF, frame);
  412. break;
  413. default:
  414. FURI_LOG_W(TAG, "Unhandled OGF %04x", OGF);
  415. break;
  416. }
  417. bit_buffer_free(message);
  418. }
  419. void seos_hci_enable_advertising(SeosHci* seos_hci, bool enable) {
  420. seos_hci->adv_status = enable;
  421. FURI_LOG_I(TAG, "Enable Advertising: %s", enable ? "true" : "false");
  422. uint8_t adv_enable[] = {0x0a, 0x20, 0x01, enable ? 0x01 : 0x00};
  423. BitBuffer* message = bit_buffer_alloc(sizeof(adv_enable));
  424. bit_buffer_append_bytes(message, adv_enable, sizeof(adv_enable));
  425. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  426. bit_buffer_free(message);
  427. FURI_LOG_I(TAG, "Start timer to make sure adv change ran");
  428. size_t delay = 1000 /*ms*/ / (1000.0f / furi_kernel_get_tick_frequency());
  429. furi_check(furi_timer_start(seos_hci->timer, delay) == FuriStatusOk);
  430. }
  431. void seos_hci_send_scan_params(SeosHci* seos_hci) {
  432. uint8_t LE_Scan_Type = 0x00;
  433. uint8_t Scanning_Filter_Policy = 0x00;
  434. uint16_t opcode = BT_OP(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS);
  435. uint8_t scan_param[] = {
  436. 0xff, 0xff, 0x07, LE_Scan_Type, 0x10, 0x00, 0x10, 0x00, 0x00, Scanning_Filter_Policy};
  437. BitBuffer* message = bit_buffer_alloc(sizeof(scan_param));
  438. memcpy(scan_param, (uint8_t*)&opcode, sizeof(opcode));
  439. bit_buffer_append_bytes(message, scan_param, sizeof(scan_param));
  440. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  441. bit_buffer_free(message);
  442. }
  443. void seos_hci_set_scan(SeosHci* seos_hci, bool enable) {
  444. FURI_LOG_I(TAG, "Start Scan: %s", enable ? "true" : "false");
  445. seos_hci->scan_status = enable;
  446. uint16_t opcode = BT_OP(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE);
  447. uint8_t set_scan[] = {0xff, 0xff, 0x02, enable ? 0x01 : 0x00, 0x00};
  448. memcpy(set_scan, (uint8_t*)&opcode, sizeof(opcode));
  449. BitBuffer* message = bit_buffer_alloc(sizeof(set_scan));
  450. bit_buffer_append_bytes(message, set_scan, sizeof(set_scan));
  451. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  452. bit_buffer_free(message);
  453. FURI_LOG_I(TAG, "Start timer to make sure set scan ran");
  454. size_t delay = 100 /*ms*/ / (1000.0f / furi_kernel_get_tick_frequency());
  455. furi_check(furi_timer_start(seos_hci->timer, delay) == FuriStatusOk);
  456. }
  457. // TODO: test this: hci create le conn - writing: 010d 2019 6000 3000 00 01 2db88ee137c3 000600120000002a0004000600
  458. void seos_hci_connect(SeosHci* seos_hci) {
  459. FURI_LOG_I(TAG, "seos_hci_connect");
  460. uint16_t opcode = BT_OP(OGF_LE_CTL, OCF_LE_CREATE_CONNECTION);
  461. // Values arbitrarily copied from https://stackoverflow.com/questions/71250571/how-to-send-le-extended-create-connection-in-ble-with-raspberry-pi
  462. uint8_t connect[] = {
  463. 0xff,
  464. 0xff, //opcode
  465. 0x19, // length
  466. 0x60,
  467. 0x00, // LE_Scan_Interval
  468. 0x60,
  469. 0x00, // LE_Scan_Window
  470. 0x00, // Initiator_Filter_Policy
  471. seos_hci->address_type, // Peer_Address_Type
  472. 0xFF,
  473. 0xFF,
  474. 0xFF,
  475. 0xFF,
  476. 0xFF,
  477. 0xFF, // Peer_Address
  478. 0x01, // Own_Address_Type
  479. 0x18,
  480. 0x00, // Connection_Interval_Min
  481. 0x28,
  482. 0x00, // Connection_Interval_Max
  483. 0x00,
  484. 0x00, // Max_Latency
  485. 0x90,
  486. 0x00, // Supervision_Timeout
  487. 0x00,
  488. 0x00, // Min_CE_Length
  489. 0x00,
  490. 0x00, // Max_CE_Length
  491. };
  492. memcpy(connect, (uint8_t*)&opcode, sizeof(opcode));
  493. memcpy(connect + 9, seos_hci->address, 6);
  494. BitBuffer* message = bit_buffer_alloc(sizeof(connect));
  495. bit_buffer_append_bytes(message, connect, sizeof(connect));
  496. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  497. bit_buffer_free(message);
  498. }
  499. void seos_hci_handle_event_le_meta(SeosHci* seos_hci, BitBuffer* frame) {
  500. const uint8_t* data = bit_buffer_get_data(frame);
  501. // uint8_t length = data[2];
  502. uint8_t subevent_code = data[3];
  503. switch(subevent_code) {
  504. case HCI_LE_CONNECTION_COMPLETE:
  505. uint8_t status = data[4];
  506. if(status != 0x00) {
  507. FURI_LOG_W(TAG, "Connection complete with non-zero status");
  508. return;
  509. }
  510. seos_hci->connection_handle = data[6] << 8 | data[5];
  511. uint8_t role = data[7];
  512. uint8_t peer_address_type = data[8];
  513. // and more...
  514. FURI_LOG_D(
  515. TAG,
  516. "connection complete: handle %04x role %d peer_address_type %d",
  517. seos_hci->connection_handle,
  518. role,
  519. peer_address_type);
  520. view_dispatcher_send_custom_event(
  521. seos_hci->seos->view_dispatcher, SeosCustomEventConnected);
  522. if(role == 0x00) { // I'm a central!
  523. if(seos_hci->central_connection_callback) {
  524. seos_hci->central_connection_callback(seos_hci->central_connection_context);
  525. } else {
  526. FURI_LOG_W(TAG, "No central_connection_callback defined");
  527. }
  528. } else if(role == 0x01) { // I'm a peripheral!
  529. }
  530. break;
  531. case HCI_LE_ADVERTISING_REPORT:
  532. // Prevent interruptions to handling a device by a second advertisement
  533. if(seos_hci->device_found) {
  534. break;
  535. }
  536. // TODO: Support single packet with multiple reports
  537. uint8_t num_reports = data[4];
  538. uint8_t Event_Type = data[5];
  539. uint8_t Address_Type = data[6];
  540. const uint8_t* Address = data + 7;
  541. uint8_t Data_Length = data[13];
  542. const uint8_t* adv_data = data + 14;
  543. char name[20];
  544. memset(name, 0, sizeof(name));
  545. if(Event_Type != 0 || Data_Length < sizeof(seos_reader_service_backwards)) {
  546. break;
  547. }
  548. /*
  549. FURI_LOG_D(
  550. TAG,
  551. "Adv %d reports: event type %d address type %d data len %d",
  552. num_reports,
  553. Event_Type,
  554. Address_Type,
  555. Data_Length);
  556. */
  557. // seos_log_buffer(TAG, "ADV_IND", (uint8_t*)adv_data, Data_Length);
  558. uint8_t i = 0;
  559. do {
  560. uint8_t l = adv_data[i++];
  561. uint8_t t = adv_data[i++];
  562. const uint8_t* val = adv_data + i;
  563. i += l - 1; // subtract one so we don't overcount the type byte
  564. switch(t) {
  565. case 0x07:
  566. if(seos_hci->flow_mode == FLOW_CRED) {
  567. // You're acting like a credential, looking for readers to connect and send to
  568. if(memcmp(
  569. val,
  570. seos_reader_service_backwards,
  571. sizeof(seos_reader_service_backwards)) == 0) {
  572. seos_hci->device_found = true;
  573. }
  574. } else if(seos_hci->flow_mode == FLOW_READER) {
  575. if(memcmp(
  576. val,
  577. seos_cred_service_backwards,
  578. sizeof(seos_cred_service_backwards)) == 0) {
  579. seos_hci->device_found = true;
  580. }
  581. } else if(seos_hci->flow_mode == FLOW_READER_SCANNER) {
  582. // Reader scanner looks for readers, it doesn't act like a reader (as in FLOW_READER)
  583. if(memcmp(
  584. val,
  585. seos_reader_service_backwards,
  586. sizeof(seos_reader_service_backwards)) == 0) {
  587. if(!seos_hci_known_address(seos_hci, Address)) {
  588. notification_message(
  589. seos_hci->seos->notifications, &sequence_single_vibro);
  590. }
  591. }
  592. } else if(seos_hci->flow_mode == FLOW_CRED_SCANNER) {
  593. // Cred scanner looks for devices advertising credential service, it doesn't act like a credential (as in FLOW_CRED)
  594. if(memcmp(
  595. val,
  596. seos_cred_service_backwards,
  597. sizeof(seos_cred_service_backwards)) == 0) {
  598. if(!seos_hci_known_address(seos_hci, Address)) {
  599. notification_message(
  600. seos_hci->seos->notifications, &sequence_single_vibro);
  601. }
  602. }
  603. }
  604. break;
  605. case 0x08: // Short device name
  606. case 0x09: // full device name
  607. memcpy(name, val, l - 1);
  608. break;
  609. }
  610. } while(i < Data_Length - 1);
  611. seos_hci->adv_report_count += num_reports;
  612. if(seos_hci->device_found) {
  613. FURI_LOG_I(TAG, "Matched Seos Reader Service: %s", name);
  614. seos_hci->address_type = Address_Type;
  615. memcpy(seos_hci->address, Address, sizeof(seos_hci->address));
  616. seos_hci_set_scan(seos_hci, false);
  617. view_dispatcher_send_custom_event(
  618. seos_hci->seos->view_dispatcher, SeosCustomEventFound);
  619. }
  620. break;
  621. default:
  622. FURI_LOG_W(TAG, "LE Meta event with unknown subevent code");
  623. break;
  624. }
  625. }
  626. void seos_hci_event_handler(SeosHci* seos_hci, BitBuffer* frame) {
  627. const uint8_t* data = bit_buffer_get_data(frame);
  628. uint8_t sub_event_type = data[1];
  629. // uint8_t length = data[2];
  630. if(sub_event_type == BT_HCI_EVT_CMD_STATUS) {
  631. struct bt_hci_evt_cmd_status {
  632. uint8_t status;
  633. uint8_t ncmd;
  634. uint16_t opcode;
  635. } __packed;
  636. struct bt_hci_evt_cmd_status* status = (struct bt_hci_evt_cmd_status*)(data + 3);
  637. if(status->status == 0) {
  638. /*
  639. FURI_LOG_D(
  640. TAG,
  641. "Status: status %d ncmd 0x%02x opcode %04x",
  642. status->status,
  643. status->ncmd,
  644. status->opcode);
  645. */
  646. } else {
  647. // Unknown HCI command (0x01)
  648. FURI_LOG_W(
  649. TAG,
  650. "Status: status %d ncmd 0x%02x opcode %04x",
  651. status->status,
  652. status->ncmd,
  653. status->opcode);
  654. }
  655. } else if(sub_event_type == BT_HCI_EVT_CMD_COMPLETE) {
  656. seos_hci_handle_event_cmd_complete(seos_hci, frame);
  657. } else if(sub_event_type == BT_HCI_EVT_LE_META) {
  658. seos_hci_handle_event_le_meta(seos_hci, frame);
  659. } else if(sub_event_type == BT_HCI_EVT_DISCONN_COMPLETE) {
  660. // FURI_LOG_D(TAG, "BT_HCI_EVT_CMD_COMPLETE");
  661. seos_hci_handle_event_cmd_complete(seos_hci, frame);
  662. } else if(sub_event_type == BT_HCI_EVT_LE_META) {
  663. // FURI_LOG_D(TAG, "BT_HCI_EVT_LE_META");
  664. seos_hci_handle_event_le_meta(seos_hci, frame);
  665. } else if(sub_event_type == BT_HCI_EVT_DISCONN_COMPLETE) {
  666. // FURI_LOG_D(TAG, "BT_HCI_EVT_DISCONN_COMPLETE");
  667. seos_hci->connection_handle = 0;
  668. if(seos_hci->mode == BLE_PERIPHERAL) {
  669. if(seos_hci->adv_status) {
  670. FURI_LOG_W(TAG, "Disconnect. Restart Advertising");
  671. seos_hci_enable_advertising(seos_hci, true);
  672. }
  673. } else if(seos_hci->mode == BLE_CENTRAL) {
  674. FURI_LOG_W(TAG, "Disconnect. Scan again");
  675. seos_hci->device_found = false;
  676. seos_hci_set_scan(seos_hci, true);
  677. }
  678. } else if(sub_event_type == BT_HCI_EVT_HARDWARE_ERROR) {
  679. FURI_LOG_W(TAG, "BT_HCI_EVT_HARDWARE_ERROR");
  680. } else if(sub_event_type == BT_HCI_EVT_NUM_COMPLETED_PACKETS) {
  681. // FURI_LOG_D(TAG, "BT_HCI_EVT_NUM_COMPLETED_PACKETS");
  682. struct bt_hci_evt_num_completed_packets {
  683. uint8_t num_handles;
  684. uint16_t handle;
  685. uint16_t count;
  686. } __attribute__((packed));
  687. struct bt_hci_evt_num_completed_packets* evt =
  688. (struct bt_hci_evt_num_completed_packets*)(data + 3);
  689. if(evt->num_handles == 1) {
  690. // FURI_LOG_D(TAG, "Number of completed packets for %04x: %d", evt->handle, evt->count);
  691. } else {
  692. FURI_LOG_D(TAG, "Number of completed packets for multiple handles");
  693. }
  694. if(seos_hci->completed_packets_callback) {
  695. seos_hci->completed_packets_callback(seos_hci->completed_packets_context);
  696. }
  697. } else {
  698. FURI_LOG_W(TAG, "Unhandled event subtype %02x", sub_event_type);
  699. }
  700. }
  701. void seos_hci_acldata_send(SeosHci* seos_hci, uint8_t flags, BitBuffer* tx) {
  702. // seos_log_buffer("seos_hci_acldata_send", tx);
  703. uint16_t tx_len = bit_buffer_get_size_bytes(tx);
  704. uint16_t handle = seos_hci->connection_handle | (flags << 12);
  705. BitBuffer* response = bit_buffer_alloc(tx_len + sizeof(handle) + sizeof(tx_len));
  706. bit_buffer_append_bytes(response, (uint8_t*)&handle, sizeof(handle));
  707. bit_buffer_append_bytes(response, (uint8_t*)&tx_len, sizeof(tx_len));
  708. // tx
  709. bit_buffer_append_bytes(response, bit_buffer_get_data(tx), tx_len);
  710. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_ACLDATA_PKT, response);
  711. bit_buffer_free(response);
  712. }
  713. void seos_hci_acldata_handler(SeosHci* seos_hci, BitBuffer* frame) {
  714. const uint8_t* data = bit_buffer_get_data(frame);
  715. // 0 is 0x02 for ACL DATA
  716. uint16_t handle = (data[2] << 8 | data[1]) & 0x0FFF;
  717. uint8_t flags = data[2] >> 4;
  718. uint16_t length = data[4] << 8 | data[3];
  719. /*
  720. uint8_t Broadcast_Flag = flags >> 2;
  721. uint8_t Packet_Boundary_Flag = flags & 0x03;
  722. FURI_LOG_D(
  723. TAG,
  724. "ACLDATA handle %04x Broadcast_Flag %02x Packet_Boundary_Flag %02x length %d",
  725. handle,
  726. Broadcast_Flag,
  727. Packet_Boundary_Flag,
  728. length);
  729. */
  730. if(handle != seos_hci->connection_handle) {
  731. FURI_LOG_W(TAG, "Mismatched handle values");
  732. }
  733. BitBuffer* pdu = bit_buffer_alloc(length);
  734. bit_buffer_append_bytes(pdu, data + 1 /*ACL DATA */ + sizeof(handle) + sizeof(length), length);
  735. if(seos_hci->receive_callback) {
  736. seos_hci->receive_callback(seos_hci->receive_callback_context, handle, flags, pdu);
  737. }
  738. bit_buffer_free(pdu);
  739. }
  740. size_t seos_hci_recv(void* context, BitBuffer* frame) {
  741. SeosHci* seos_hci = (SeosHci*)context;
  742. // seos_log_buffer("HCI Frame", frame);
  743. const uint8_t* data = bit_buffer_get_data(frame);
  744. uint8_t event_type = data[0];
  745. // TODO: consider `bit_buffer_starts_with_byte`
  746. switch(event_type) {
  747. case HCI_EVENT_PKT:
  748. seos_hci_event_handler(seos_hci, frame);
  749. break;
  750. case HCI_ACLDATA_PKT:
  751. seos_hci_acldata_handler(seos_hci, frame);
  752. break;
  753. default:
  754. FURI_LOG_W(TAG, "Haven't added support for other HCI commands yet: %02x", event_type);
  755. seos_log_bitbuffer(TAG, "unhandled", frame);
  756. break;
  757. }
  758. return 0;
  759. }
  760. // TODO: Consider making this a general "when the state changes" callback which would check if H5 is active (or needs to be reset)
  761. void seos_hci_init(void* context) {
  762. SeosHci* seos_hci = (SeosHci*)context;
  763. BitBuffer* message = bit_buffer_alloc(128);
  764. uint8_t reset[] = {0x03, 0x0c, 0x00};
  765. bit_buffer_append_bytes(message, reset, sizeof(reset));
  766. seos_hci_h5_send(seos_hci->seos_hci_h5, HCI_COMMAND_PKT, message);
  767. view_dispatcher_send_custom_event(seos_hci->seos->view_dispatcher, SeosCustomEventHCIInit);
  768. bit_buffer_free(message);
  769. }
  770. void seos_hci_set_receive_callback(
  771. SeosHci* seos_hci,
  772. SeosHciReceiveCallback callback,
  773. void* context) {
  774. seos_hci->receive_callback = callback;
  775. seos_hci->receive_callback_context = context;
  776. }
  777. void seos_hci_set_completed_packets_callback(
  778. SeosHci* seos_hci,
  779. SeosHciCompletedPacketsCallback callback,
  780. void* context) {
  781. seos_hci->completed_packets_callback = callback;
  782. seos_hci->completed_packets_context = context;
  783. }
  784. void seos_hci_set_central_connection_callback(
  785. SeosHci* seos_hci,
  786. SeosHciCentralConnectionCallback callback,
  787. void* context) {
  788. seos_hci->central_connection_callback = callback;
  789. seos_hci->central_connection_context = context;
  790. }