PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

484 line
15KB

  1. /*********************************************************************
  2. This is a library for our nRF8001 Bluetooth Low Energy Breakout
  3. Pick one up today in the adafruit shop!
  4. ------> http://www.adafruit.com/products/1697
  5. These displays use SPI to communicate, 4 or 5 pins are required to
  6. interface
  7. Adafruit invests time and resources providing this open source code,
  8. please support Adafruit and open-source hardware by purchasing
  9. products from Adafruit!
  10. Written by Kevin Townsend/KTOWN for Adafruit Industries.
  11. MIT license, check LICENSE for more information
  12. All text above, and the splash screen below must be included in any redistribution
  13. *********************************************************************/
  14. #include <SPI.h>
  15. #include <avr/pgmspace.h>
  16. #include <util/delay.h>
  17. #include <stdlib.h>
  18. #include <ble_system.h>
  19. #include <lib_aci.h>
  20. #include <aci_setup.h>
  21. #include "uart/services.h"
  22. #include "Adafruit_BLE_UART.h"
  23. /* Get the service pipe data created in nRFGo Studio */
  24. #ifdef SERVICES_PIPE_TYPE_MAPPING_CONTENT
  25. static services_pipe_type_mapping_t
  26. services_pipe_type_mapping[NUMBER_OF_PIPES] = SERVICES_PIPE_TYPE_MAPPING_CONTENT;
  27. #else
  28. #define NUMBER_OF_PIPES 0
  29. static services_pipe_type_mapping_t * services_pipe_type_mapping = NULL;
  30. #endif
  31. /* Length of the buffer used to store flash strings temporarily when printing. */
  32. #define PRINT_BUFFER_SIZE 20
  33. /* Store the setup for the nRF8001 in the flash of the AVR to save on RAM */
  34. static const hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM = SETUP_MESSAGES_CONTENT;
  35. static struct aci_state_t aci_state; /* ACI state data */
  36. static hal_aci_evt_t aci_data; /* Command buffer */
  37. static bool timing_change_done = false;
  38. // This is the Uart RX buffer, which we manage internally when data is available!
  39. #define ADAFRUIT_BLE_UART_RXBUFFER_SIZE 64
  40. uint8_t adafruit_ble_rx_buffer[ADAFRUIT_BLE_UART_RXBUFFER_SIZE];
  41. volatile uint16_t adafruit_ble_rx_head;
  42. volatile uint16_t adafruit_ble_rx_tail;
  43. int8_t HAL_IO_RADIO_RESET, HAL_IO_RADIO_REQN, HAL_IO_RADIO_RDY, HAL_IO_RADIO_IRQ;
  44. /**************************************************************************/
  45. /*!
  46. Constructor for the UART service
  47. */
  48. /**************************************************************************/
  49. // default RX callback!
  50. void Adafruit_BLE_UART::defaultRX(uint8_t *buffer, uint8_t len)
  51. {
  52. for(int i=0; i<len; i++)
  53. {
  54. uint16_t new_head = (uint16_t)(adafruit_ble_rx_head + 1) % ADAFRUIT_BLE_UART_RXBUFFER_SIZE;
  55. // if we should be storing the received character into the location
  56. // just before the tail (meaning that the head would advance to the
  57. // current location of the tail), we're about to overflow the buffer
  58. // and so we don't write the character or advance the head.
  59. if (new_head != adafruit_ble_rx_tail) {
  60. adafruit_ble_rx_buffer[adafruit_ble_rx_head] = buffer[i];
  61. // debug echo print
  62. // Serial.print((char)buffer[i]);
  63. adafruit_ble_rx_head = new_head;
  64. }
  65. }
  66. /*
  67. Serial.print("Buffer: ");
  68. for(int i=0; i<adafruit_ble_rx_head; i++)
  69. {
  70. Serial.print(" 0x"); Serial.print((char)adafruit_ble_rx_buffer[i], HEX);
  71. }
  72. Serial.println();
  73. */
  74. }
  75. /* Stream stuff */
  76. int Adafruit_BLE_UART::available(void)
  77. {
  78. return (uint16_t)(ADAFRUIT_BLE_UART_RXBUFFER_SIZE + adafruit_ble_rx_head - adafruit_ble_rx_tail)
  79. % ADAFRUIT_BLE_UART_RXBUFFER_SIZE;
  80. }
  81. int Adafruit_BLE_UART::read(void)
  82. {
  83. // if the head isn't ahead of the tail, we don't have any characters
  84. if (adafruit_ble_rx_head == adafruit_ble_rx_tail) {
  85. return -1;
  86. } else {
  87. unsigned char c = adafruit_ble_rx_buffer[adafruit_ble_rx_tail];
  88. adafruit_ble_rx_tail ++;
  89. adafruit_ble_rx_tail %= ADAFRUIT_BLE_UART_RXBUFFER_SIZE;
  90. return c;
  91. }
  92. }
  93. int Adafruit_BLE_UART::peek(void)
  94. {
  95. if (adafruit_ble_rx_head == adafruit_ble_rx_tail) {
  96. return -1;
  97. } else {
  98. return adafruit_ble_rx_buffer[adafruit_ble_rx_tail];
  99. }
  100. }
  101. void Adafruit_BLE_UART::flush(void)
  102. {
  103. // MEME: KTOWN what do we do here?
  104. }
  105. //// more callbacks
  106. void Adafruit_BLE_UART::defaultACICallback(aci_evt_opcode_t event)
  107. {
  108. currentStatus = event;
  109. }
  110. aci_evt_opcode_t Adafruit_BLE_UART::getState(void) {
  111. return currentStatus;
  112. }
  113. /**************************************************************************/
  114. /*!
  115. Constructor for the UART service
  116. */
  117. /**************************************************************************/
  118. Adafruit_BLE_UART::Adafruit_BLE_UART(int8_t req, int8_t rdy, int8_t rst)
  119. {
  120. debugMode = true;
  121. HAL_IO_RADIO_REQN = req;
  122. HAL_IO_RADIO_RDY = rdy;
  123. HAL_IO_RADIO_RESET = rst;
  124. rx_event = NULL;
  125. aci_event = NULL;
  126. memset(device_name, 0x00, 8);
  127. adafruit_ble_rx_head = adafruit_ble_rx_tail = 0;
  128. currentStatus = ACI_EVT_DISCONNECTED;
  129. }
  130. void Adafruit_BLE_UART::setACIcallback(aci_callback aciEvent) {
  131. aci_event = aciEvent;
  132. }
  133. void Adafruit_BLE_UART::setRXcallback(rx_callback rxEvent) {
  134. rx_event = rxEvent;
  135. }
  136. /**************************************************************************/
  137. /*!
  138. Transmits data out via the TX characteristic (when available)
  139. */
  140. /**************************************************************************/
  141. size_t Adafruit_BLE_UART::println(const char * thestr)
  142. {
  143. uint8_t len = strlen(thestr),
  144. written = len ? write((uint8_t *)thestr, len) : 0;
  145. if(written == len) written += write((uint8_t *)"\r\n", 2);
  146. return written;
  147. }
  148. size_t Adafruit_BLE_UART::print(const char * thestr)
  149. {
  150. return write((uint8_t *)thestr, strlen(thestr));
  151. }
  152. size_t Adafruit_BLE_UART::print(String thestr)
  153. {
  154. return write((uint8_t *)thestr.c_str(), thestr.length());
  155. }
  156. size_t Adafruit_BLE_UART::print(int theint)
  157. {
  158. char message[4*sizeof(int)+1] = {0};
  159. itoa(theint, message, 10);
  160. return write((uint8_t *)message, strlen(message));
  161. }
  162. size_t Adafruit_BLE_UART::print(const __FlashStringHelper *ifsh)
  163. {
  164. // Copy bytes from flash string into RAM, then send them a buffer at a time.
  165. char buffer[PRINT_BUFFER_SIZE] = {0};
  166. const char PROGMEM *p = (const char PROGMEM *)ifsh;
  167. size_t written = 0;
  168. int i = 0;
  169. unsigned char c = pgm_read_byte(p++);
  170. // Read data from flash until a null terminator is found.
  171. while (c != 0) {
  172. // Copy data to RAM and increase buffer index.
  173. buffer[i] = c;
  174. i++;
  175. if (i >= PRINT_BUFFER_SIZE) {
  176. // Send buffer when it's full and reset buffer index.
  177. written += write((uint8_t *)buffer, PRINT_BUFFER_SIZE);
  178. i = 0;
  179. }
  180. // Grab a new byte from flash.
  181. c = pgm_read_byte(p++);
  182. }
  183. if (i > 0) {
  184. // Send any remaining data in the buffer.
  185. written += write((uint8_t *)buffer, i);
  186. }
  187. return written;
  188. }
  189. size_t Adafruit_BLE_UART::write(uint8_t * buffer, uint8_t len)
  190. {
  191. uint8_t bytesThisPass, sent = 0;
  192. #ifdef BLE_RW_DEBUG
  193. Serial.print(F("\tWriting out to BTLE:"));
  194. for (uint8_t i=0; i<len; i++) {
  195. Serial.print(F(" 0x")); Serial.print(buffer[i], HEX);
  196. }
  197. Serial.println();
  198. #endif
  199. while(len) { // Parcelize into chunks
  200. bytesThisPass = len;
  201. if(bytesThisPass > ACI_PIPE_TX_DATA_MAX_LEN)
  202. bytesThisPass = ACI_PIPE_TX_DATA_MAX_LEN;
  203. if(!lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX))
  204. {
  205. pollACI();
  206. continue;
  207. }
  208. lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer[sent],
  209. bytesThisPass);
  210. aci_state.data_credit_available--;
  211. delay(35); // required delay between sends
  212. if(!(len -= bytesThisPass)) break;
  213. sent += bytesThisPass;
  214. }
  215. return sent;
  216. }
  217. size_t Adafruit_BLE_UART::write(uint8_t buffer)
  218. {
  219. #ifdef BLE_RW_DEBUG
  220. Serial.print(F("\tWriting one byte 0x")); Serial.println(buffer, HEX);
  221. #endif
  222. if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX))
  223. {
  224. lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer, 1);
  225. aci_state.data_credit_available--;
  226. delay(35); // required delay between sends
  227. return 1;
  228. }
  229. pollACI();
  230. return 0;
  231. }
  232. /**************************************************************************/
  233. /*!
  234. Update the device name (7 characters or less!)
  235. */
  236. /**************************************************************************/
  237. void Adafruit_BLE_UART::setDeviceName(const char * deviceName)
  238. {
  239. if (strlen(deviceName) > 7)
  240. {
  241. /* String too long! */
  242. return;
  243. }
  244. else
  245. {
  246. memcpy(device_name, deviceName, strlen(deviceName));
  247. }
  248. }
  249. /**************************************************************************/
  250. /*!
  251. Handles low level ACI events, and passes them up to an application
  252. level callback when appropriate
  253. */
  254. /**************************************************************************/
  255. void Adafruit_BLE_UART::pollACI()
  256. {
  257. // We enter the if statement only when there is a ACI event available to be processed
  258. if (lib_aci_event_get(&aci_state, &aci_data))
  259. {
  260. aci_evt_t * aci_evt;
  261. aci_evt = &aci_data.evt;
  262. switch(aci_evt->evt_opcode)
  263. {
  264. /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */
  265. case ACI_EVT_DEVICE_STARTED:
  266. {
  267. aci_state.data_credit_total = aci_evt->params.device_started.credit_available;
  268. switch(aci_evt->params.device_started.device_mode)
  269. {
  270. case ACI_DEVICE_SETUP:
  271. /* Device is in setup mode! */
  272. if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&aci_state))
  273. {
  274. if (debugMode) {
  275. Serial.println(F("Error in ACI Setup"));
  276. }
  277. }
  278. break;
  279. case ACI_DEVICE_STANDBY:
  280. /* Start advertising ... first value is advertising time in seconds, the */
  281. /* second value is the advertising interval in 0.625ms units */
  282. if (device_name[0] != 0x00)
  283. {
  284. /* Update the device name */
  285. lib_aci_set_local_data(&aci_state, PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name, strlen(device_name));
  286. }
  287. lib_aci_connect(adv_timeout, adv_interval);
  288. defaultACICallback(ACI_EVT_DEVICE_STARTED);
  289. if (aci_event)
  290. aci_event(ACI_EVT_DEVICE_STARTED);
  291. }
  292. }
  293. break;
  294. case ACI_EVT_CMD_RSP:
  295. /* If an ACI command response event comes with an error -> stop */
  296. if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status)
  297. {
  298. // ACI ReadDynamicData and ACI WriteDynamicData will have status codes of
  299. // TRANSACTION_CONTINUE and TRANSACTION_COMPLETE
  300. // all other ACI commands will have status code of ACI_STATUS_SUCCESS for a successful command
  301. if (debugMode) {
  302. Serial.print(F("ACI Command "));
  303. Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX);
  304. Serial.println(F("Evt Cmd respone: Error. Arduino is in an while(1); loop"));
  305. }
  306. while (1);
  307. }
  308. if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode)
  309. {
  310. // Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic
  311. lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET,
  312. (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t));
  313. }
  314. break;
  315. case ACI_EVT_CONNECTED:
  316. aci_state.data_credit_available = aci_state.data_credit_total;
  317. /* Get the device version of the nRF8001 and store it in the Hardware Revision String */
  318. lib_aci_device_version();
  319. defaultACICallback(ACI_EVT_CONNECTED);
  320. if (aci_event)
  321. aci_event(ACI_EVT_CONNECTED);
  322. case ACI_EVT_PIPE_STATUS:
  323. if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done))
  324. {
  325. lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP.
  326. // Used to increase or decrease bandwidth
  327. timing_change_done = true;
  328. }
  329. break;
  330. case ACI_EVT_TIMING:
  331. /* Link connection interval changed */
  332. break;
  333. case ACI_EVT_DISCONNECTED:
  334. /* Restart advertising ... first value is advertising time in seconds, the */
  335. /* second value is the advertising interval in 0.625ms units */
  336. defaultACICallback(ACI_EVT_DISCONNECTED);
  337. if (aci_event)
  338. aci_event(ACI_EVT_DISCONNECTED);
  339. lib_aci_connect(adv_timeout, adv_interval);
  340. defaultACICallback(ACI_EVT_DEVICE_STARTED);
  341. if (aci_event)
  342. aci_event(ACI_EVT_DEVICE_STARTED);
  343. break;
  344. case ACI_EVT_DATA_RECEIVED:
  345. defaultRX(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2);
  346. if (rx_event)
  347. rx_event(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2);
  348. break;
  349. case ACI_EVT_DATA_CREDIT:
  350. aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit;
  351. break;
  352. case ACI_EVT_PIPE_ERROR:
  353. /* See the appendix in the nRF8001 Product Specication for details on the error codes */
  354. if (debugMode) {
  355. Serial.print(F("ACI Evt Pipe Error: Pipe #:"));
  356. Serial.print(aci_evt->params.pipe_error.pipe_number, DEC);
  357. Serial.print(F(" Pipe Error Code: 0x"));
  358. Serial.println(aci_evt->params.pipe_error.error_code, HEX);
  359. }
  360. /* Increment the credit available as the data packet was not sent */
  361. aci_state.data_credit_available++;
  362. break;
  363. }
  364. }
  365. else
  366. {
  367. // Serial.println(F("No ACI Events available"));
  368. // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep
  369. // Arduino can go to sleep now
  370. // Wakeup from sleep from the RDYN line
  371. }
  372. }
  373. /**************************************************************************/
  374. /*!
  375. Configures the nRF8001 and starts advertising the UART Service
  376. @param[in] advTimeout
  377. The advertising timeout in seconds (0 = infinite advertising)
  378. @param[in] advInterval
  379. The delay between advertising packets in 0.625ms units
  380. */
  381. /**************************************************************************/
  382. bool Adafruit_BLE_UART::begin(uint16_t advTimeout, uint16_t advInterval)
  383. {
  384. /* Store the advertising timeout and interval */
  385. adv_timeout = advTimeout; /* ToDo: Check range! */
  386. adv_interval = advInterval; /* ToDo: Check range! */
  387. /* Setup the service data from nRFGo Studio (services.h) */
  388. if (NULL != services_pipe_type_mapping)
  389. {
  390. aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0];
  391. }
  392. else
  393. {
  394. aci_state.aci_setup_info.services_pipe_type_mapping = NULL;
  395. }
  396. aci_state.aci_setup_info.number_of_pipes = NUMBER_OF_PIPES;
  397. aci_state.aci_setup_info.setup_msgs = (hal_aci_data_t*)setup_msgs;
  398. aci_state.aci_setup_info.num_setup_msgs = NB_SETUP_MESSAGES;
  399. /* Pass the service data into the appropriate struct in the ACI */
  400. lib_aci_init(&aci_state);
  401. /* ToDo: Check for chip ID to make sure we're connected! */
  402. return true;
  403. }