SerialBLEInterface.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include "SerialBLEInterface.h"
  2. static SerialBLEInterface* instance;
  3. void SerialBLEInterface::onConnect(uint16_t connection_handle) {
  4. BLE_DEBUG_PRINTLN("SerialBLEInterface: connected");
  5. if(instance){
  6. instance->_isDeviceConnected = true;
  7. // no need to stop advertising on connect, as the ble stack does this automatically
  8. }
  9. }
  10. void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) {
  11. BLE_DEBUG_PRINTLN("SerialBLEInterface: disconnected reason=%d", reason);
  12. if(instance){
  13. instance->_isDeviceConnected = false;
  14. instance->startAdv();
  15. }
  16. }
  17. void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) {
  18. instance = this;
  19. char charpin[20];
  20. sprintf(charpin, "%d", pin_code);
  21. Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
  22. Bluefruit.configPrphConn(250, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); // increase MTU
  23. Bluefruit.setTxPower(BLE_TX_POWER);
  24. Bluefruit.begin();
  25. Bluefruit.setName(device_name);
  26. Bluefruit.Security.setMITM(true);
  27. Bluefruit.Security.setPIN(charpin);
  28. Bluefruit.Periph.setConnectCallback(onConnect);
  29. Bluefruit.Periph.setDisconnectCallback(onDisconnect);
  30. // To be consistent OTA DFU should be added first if it exists
  31. //bledfu.begin();
  32. // Configure and start the BLE Uart service
  33. bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
  34. bleuart.begin();
  35. }
  36. void SerialBLEInterface::startAdv() {
  37. BLE_DEBUG_PRINTLN("SerialBLEInterface: starting advertising");
  38. // clean restart if already advertising
  39. if(Bluefruit.Advertising.isRunning()){
  40. BLE_DEBUG_PRINTLN("SerialBLEInterface: already advertising, stopping to allow clean restart");
  41. Bluefruit.Advertising.stop();
  42. }
  43. Bluefruit.Advertising.clearData(); // clear advertising data
  44. Bluefruit.ScanResponse.clearData(); // clear scan response data
  45. // Advertising packet
  46. Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  47. Bluefruit.Advertising.addTxPower();
  48. // Include the BLE UART (AKA 'NUS') 128-bit UUID
  49. Bluefruit.Advertising.addService(bleuart);
  50. // Secondary Scan Response packet (optional)
  51. // Since there is no room for 'Name' in Advertising packet
  52. Bluefruit.ScanResponse.addName();
  53. /* Start Advertising
  54. * - Enable auto advertising if disconnected
  55. * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
  56. * - Timeout for fast mode is 30 seconds
  57. * - Start(timeout) with timeout = 0 will advertise forever (until connected)
  58. *
  59. * For recommended advertising interval
  60. * https://developer.apple.com/library/content/qa/qa1931/_index.html
  61. */
  62. Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect
  63. Bluefruit.Advertising.setInterval(32, 1600);
  64. Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
  65. Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
  66. }
  67. void SerialBLEInterface::stopAdv() {
  68. BLE_DEBUG_PRINTLN("SerialBLEInterface: stopping advertising");
  69. // we only want to stop advertising if it's running, otherwise an invalid state error is logged by ble stack
  70. if(!Bluefruit.Advertising.isRunning()){
  71. return;
  72. }
  73. // stop advertising
  74. Bluefruit.Advertising.stop();
  75. }
  76. // ---------- public methods
  77. void SerialBLEInterface::enable() {
  78. if (_isEnabled) return;
  79. _isEnabled = true;
  80. clearBuffers();
  81. // Start advertising
  82. startAdv();
  83. }
  84. void SerialBLEInterface::disable() {
  85. _isEnabled = false;
  86. BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
  87. #ifdef RAK_BOARD
  88. Bluefruit.disconnect(Bluefruit.connHandle());
  89. #else
  90. uint16_t conn_id;
  91. if (Bluefruit.getConnectedHandles(&conn_id, 1) > 0) {
  92. Bluefruit.disconnect(conn_id);
  93. }
  94. #endif
  95. Bluefruit.Advertising.restartOnDisconnect(false);
  96. Bluefruit.Advertising.stop();
  97. Bluefruit.Advertising.clearData();
  98. stopAdv();
  99. }
  100. size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) {
  101. if (len > MAX_FRAME_SIZE) {
  102. BLE_DEBUG_PRINTLN("writeFrame(), frame too big, len=%d", len);
  103. return 0;
  104. }
  105. if (_isDeviceConnected && len > 0) {
  106. if (send_queue_len >= FRAME_QUEUE_SIZE) {
  107. BLE_DEBUG_PRINTLN("writeFrame(), send_queue is full!");
  108. return 0;
  109. }
  110. send_queue[send_queue_len].len = len; // add to send queue
  111. memcpy(send_queue[send_queue_len].buf, src, len);
  112. send_queue_len++;
  113. return len;
  114. }
  115. return 0;
  116. }
  117. #define BLE_WRITE_MIN_INTERVAL 60
  118. bool SerialBLEInterface::isWriteBusy() const {
  119. return millis() < _last_write + BLE_WRITE_MIN_INTERVAL; // still too soon to start another write?
  120. }
  121. size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) {
  122. if (send_queue_len > 0 // first, check send queue
  123. && millis() >= _last_write + BLE_WRITE_MIN_INTERVAL // space the writes apart
  124. ) {
  125. _last_write = millis();
  126. bleuart.write(send_queue[0].buf, send_queue[0].len);
  127. BLE_DEBUG_PRINTLN("writeBytes: sz=%d, hdr=%d", (uint32_t)send_queue[0].len, (uint32_t) send_queue[0].buf[0]);
  128. send_queue_len--;
  129. for (int i = 0; i < send_queue_len; i++) { // delete top item from queue
  130. send_queue[i] = send_queue[i + 1];
  131. }
  132. } else {
  133. int len = bleuart.available();
  134. if (len > 0) {
  135. bleuart.readBytes(dest, len);
  136. BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]);
  137. return len;
  138. }
  139. }
  140. return 0;
  141. }
  142. bool SerialBLEInterface::isConnected() const {
  143. return _isDeviceConnected;
  144. }