| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- #include "SerialBLEInterface.h"
- static SerialBLEInterface* instance;
- void SerialBLEInterface::onConnect(uint16_t connection_handle) {
- BLE_DEBUG_PRINTLN("SerialBLEInterface: connected");
- if(instance){
- instance->_isDeviceConnected = true;
- // no need to stop advertising on connect, as the ble stack does this automatically
- }
- }
- void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) {
- BLE_DEBUG_PRINTLN("SerialBLEInterface: disconnected reason=%d", reason);
- if(instance){
- instance->_isDeviceConnected = false;
- instance->startAdv();
- }
- }
- void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) {
- instance = this;
- char charpin[20];
- sprintf(charpin, "%d", pin_code);
- Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
- Bluefruit.configPrphConn(250, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); // increase MTU
- Bluefruit.setTxPower(BLE_TX_POWER);
- Bluefruit.begin();
- Bluefruit.setName(device_name);
- Bluefruit.Security.setMITM(true);
- Bluefruit.Security.setPIN(charpin);
- Bluefruit.Periph.setConnectCallback(onConnect);
- Bluefruit.Periph.setDisconnectCallback(onDisconnect);
- // To be consistent OTA DFU should be added first if it exists
- //bledfu.begin();
- // Configure and start the BLE Uart service
- bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
- bleuart.begin();
-
- }
- void SerialBLEInterface::startAdv() {
- BLE_DEBUG_PRINTLN("SerialBLEInterface: starting advertising");
-
- // clean restart if already advertising
- if(Bluefruit.Advertising.isRunning()){
- BLE_DEBUG_PRINTLN("SerialBLEInterface: already advertising, stopping to allow clean restart");
- Bluefruit.Advertising.stop();
- }
- Bluefruit.Advertising.clearData(); // clear advertising data
- Bluefruit.ScanResponse.clearData(); // clear scan response data
-
- // Advertising packet
- Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
- Bluefruit.Advertising.addTxPower();
-
- // Include the BLE UART (AKA 'NUS') 128-bit UUID
- Bluefruit.Advertising.addService(bleuart);
- // Secondary Scan Response packet (optional)
- // Since there is no room for 'Name' in Advertising packet
- Bluefruit.ScanResponse.addName();
- /* Start Advertising
- * - Enable auto advertising if disconnected
- * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
- * - Timeout for fast mode is 30 seconds
- * - Start(timeout) with timeout = 0 will advertise forever (until connected)
- *
- * For recommended advertising interval
- * https://developer.apple.com/library/content/qa/qa1931/_index.html
- */
- Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect
- Bluefruit.Advertising.setInterval(32, 1600);
- Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
- Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
- }
- void SerialBLEInterface::stopAdv() {
- BLE_DEBUG_PRINTLN("SerialBLEInterface: stopping advertising");
-
- // we only want to stop advertising if it's running, otherwise an invalid state error is logged by ble stack
- if(!Bluefruit.Advertising.isRunning()){
- return;
- }
- // stop advertising
- Bluefruit.Advertising.stop();
- }
- // ---------- public methods
- void SerialBLEInterface::enable() {
- if (_isEnabled) return;
- _isEnabled = true;
- clearBuffers();
- // Start advertising
- startAdv();
- }
- void SerialBLEInterface::disable() {
- _isEnabled = false;
- BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
- #ifdef RAK_BOARD
- Bluefruit.disconnect(Bluefruit.connHandle());
- #else
- uint16_t conn_id;
- if (Bluefruit.getConnectedHandles(&conn_id, 1) > 0) {
- Bluefruit.disconnect(conn_id);
- }
- #endif
- Bluefruit.Advertising.restartOnDisconnect(false);
- Bluefruit.Advertising.stop();
- Bluefruit.Advertising.clearData();
- stopAdv();
- }
- size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) {
- if (len > MAX_FRAME_SIZE) {
- BLE_DEBUG_PRINTLN("writeFrame(), frame too big, len=%d", len);
- return 0;
- }
- if (_isDeviceConnected && len > 0) {
- if (send_queue_len >= FRAME_QUEUE_SIZE) {
- BLE_DEBUG_PRINTLN("writeFrame(), send_queue is full!");
- return 0;
- }
- send_queue[send_queue_len].len = len; // add to send queue
- memcpy(send_queue[send_queue_len].buf, src, len);
- send_queue_len++;
- return len;
- }
- return 0;
- }
- #define BLE_WRITE_MIN_INTERVAL 60
- bool SerialBLEInterface::isWriteBusy() const {
- return millis() < _last_write + BLE_WRITE_MIN_INTERVAL; // still too soon to start another write?
- }
- size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) {
- if (send_queue_len > 0 // first, check send queue
- && millis() >= _last_write + BLE_WRITE_MIN_INTERVAL // space the writes apart
- ) {
- _last_write = millis();
- bleuart.write(send_queue[0].buf, send_queue[0].len);
- BLE_DEBUG_PRINTLN("writeBytes: sz=%d, hdr=%d", (uint32_t)send_queue[0].len, (uint32_t) send_queue[0].buf[0]);
- send_queue_len--;
- for (int i = 0; i < send_queue_len; i++) { // delete top item from queue
- send_queue[i] = send_queue[i + 1];
- }
- } else {
- int len = bleuart.available();
- if (len > 0) {
- bleuart.readBytes(dest, len);
- BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]);
- return len;
- }
- }
- return 0;
- }
- bool SerialBLEInterface::isConnected() const {
- return _isDeviceConnected;
- }
|