diff --git a/.travis.yml b/.travis.yml index 5e6814300..26238340d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ install: - BSP_VERSION=`eval ls $BSP_PATH` - rm -r $BSP_PATH/* - ln -s $TRAVIS_BUILD_DIR $BSP_PATH/$BSP_VERSION - - arduino --install-library "Adafruit NeoPixel","Adafruit NeoMatrix","Adafruit GFX Library","Adafruit SSD1306","MIDI Library", + - arduino --install-library "Adafruit NeoPixel","Adafruit NeoMatrix","Adafruit GFX Library","Adafruit SSD1306","MIDI Library","Adafruit ILI9341" before_script: diff --git a/cores/nRF5/Adafruit_TinyUSB_Core/Adafruit_USBD_CDC.cpp b/cores/nRF5/Adafruit_TinyUSB_Core/Adafruit_USBD_CDC.cpp index c83597dd1..0218feb1f 100644 --- a/cores/nRF5/Adafruit_TinyUSB_Core/Adafruit_USBD_CDC.cpp +++ b/cores/nRF5/Adafruit_TinyUSB_Core/Adafruit_USBD_CDC.cpp @@ -107,7 +107,7 @@ void Adafruit_USBD_CDC::flush(void) size_t Adafruit_USBD_CDC::write(uint8_t ch) { - return tud_cdc_write_char((char) ch); + return write(&ch, 1); } size_t Adafruit_USBD_CDC::write(const uint8_t *buffer, size_t size) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino b/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino index 092980627..992c9c69e 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino @@ -163,7 +163,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } /** diff --git a/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino b/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino index d3b4fa724..78aafb968 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_custom_hrm/central_custom_hrm.ino @@ -171,7 +171,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino index 68c872498..b56e2718c 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino @@ -141,7 +141,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } void loop() diff --git a/libraries/Bluefruit52Lib/examples/Central/central_throughput/central_throughput.ino b/libraries/Bluefruit52Lib/examples/Central/central_throughput/central_throughput.ino new file mode 100644 index 000000000..ff505fbb9 --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Central/central_throughput/central_throughput.ino @@ -0,0 +1,159 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* + * This sketch demonstrate the central API(). A additional bluefruit + * that has bleuart as peripheral is required for the demo. + */ +#include + +BLEClientUart clientUart; // bleuart client + +uint32_t rx_count = 0; + +void setup() +{ + Serial.begin(115200); + while ( !Serial ) delay(10); // for nrf52840 with native usb + + Serial.println("Bluefruit52 Central BLEUART Example"); + Serial.println("-----------------------------------\n"); + + // Config the connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configCentralBandwidth(BANDWIDTH_MAX); + + // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1 + // SRAM usage required by SoftDevice will increase dramatically with number of connections + Bluefruit.begin(0, 1); + + Bluefruit.setName("Bluefruit52 Central"); + + // Init BLE Central Uart Serivce + clientUart.begin(); + clientUart.setRxCallback(bleuart_rx_callback); + + // Increase Blink rate to different from PrPh advertising mode + Bluefruit.setConnLedInterval(250); + + // Callbacks for Central + Bluefruit.Central.setConnectCallback(connect_callback); + Bluefruit.Central.setDisconnectCallback(disconnect_callback); + + /* Start Central Scanning + * - Enable auto scan if disconnected + * - Interval = 100 ms, window = 80 ms + * - Don't use active scan + * - Start(timeout) with timeout = 0 will scan forever (until connected) + */ + Bluefruit.Scanner.setRxCallback(scan_callback); + Bluefruit.Scanner.restartOnDisconnect(true); + Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms + Bluefruit.Scanner.useActiveScan(false); + Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds +} + +/** + * Callback invoked when scanner pick up an advertising data + * @param report Structural advertising data + */ +void scan_callback(ble_gap_evt_adv_report_t* report) +{ + // Check if advertising contain BleUart service + if ( Bluefruit.Scanner.checkReportForService(report, clientUart) ) + { + Serial.print("BLE UART service detected. Connecting ... "); + + // Connect to device with bleuart service in advertising + Bluefruit.Central.connect(report); + }else + { + // For Softdevice v6: after received a report, scanner will be paused + // We need to call Scanner resume() to continue scanning + Bluefruit.Scanner.resume(); + } +} + +/** + * Callback invoked when an connection is established + * @param conn_handle + */ +void connect_callback(uint16_t conn_handle) +{ + Serial.println("Connected"); + + Serial.print("Discovering BLE Uart Service ... "); + if ( clientUart.discover(conn_handle) ) + { + Serial.println("Found it"); + + Serial.println("Enable TXD's notify"); + clientUart.enableTXD(); + + Serial.println("Ready to receive from peripheral"); + }else + { + Serial.println("Found NONE"); + + // disconnect since we couldn't find bleuart service + Bluefruit.disconnect(conn_handle); + } +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); +} + +/** + * Callback invoked when uart received data + * @param uart_svc Reference object to the service where the data + * arrived. In this example it is clientUart + */ +void bleuart_rx_callback(BLEClientUart& uart_svc) +{ + int count = uart_svc.available(); + uart_svc.flush(); +} + +void loop() +{ + if ( Bluefruit.Central.connected() ) + { + // Not discovered yet + if ( clientUart.discovered() ) + { + // Discovered means in working state + // Get Serial input and send to Peripheral + if ( Serial.available() ) + { + delay(2); // delay a bit for all characters to arrive + + char str[20+1] = { 0 }; + Serial.readBytes(str, 20); + + clientUart.print( str ); + } + } + } +} diff --git a/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino b/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino index 6e1850b83..2edaf8710 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_ti_sensortag_optical/central_ti_sensortag_optical.ino @@ -244,7 +244,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } /** diff --git a/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/.skip.feather52832 b/libraries/Bluefruit52Lib/examples/Hardware/Serial1_test/.skip.feather52832 new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino index 9e3bbd8ed..b30104d7e 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino @@ -210,5 +210,5 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino index 805d2ea00..b1624fa40 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino @@ -142,5 +142,5 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart_multi/bleuart_multi.ino b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart_multi/bleuart_multi.ino index 6483d4134..a870ef480 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart_multi/bleuart_multi.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart_multi/bleuart_multi.ino @@ -159,7 +159,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); connection_count--; } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino index 9e17f980b..d354c81a7 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino @@ -173,5 +173,5 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino b/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino index fdbdafe31..7b5a6132c 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino @@ -181,7 +181,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); Serial.println("Advertising!"); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino b/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino index 2a1ea11b3..5d4717ce1 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/custom_htm/custom_htm.ino @@ -171,7 +171,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) conn_handle; (void) reason; - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); Serial.println("Advertising!"); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/image_upload/image_upload.ino b/libraries/Bluefruit52Lib/examples/Peripheral/image_upload/image_upload.ino new file mode 100644 index 000000000..3ccb0c747 --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Peripheral/image_upload/image_upload.ino @@ -0,0 +1,202 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. + * FeatherWing OLED is used to display uploaded image + * - https://www.adafruit.com/product/3315 + */ + +#include +#include +#include +#include + +BLEUart bleuart; // uart over ble + +/* The Image Transfer module sends the image of your choice to Bluefruit LE over UART. + * Each image sent begins with + * - A single byte char “!” (0x21) + * - Image width (uint16 little endian, 2 bytes) + * - Image height (uint16 little endian, 2 bytes) + * - Pixel data encoded as RGB 24-bit and suffixed by a single byte CRC. + * + * Format: [ ‘!’ ] [ uint16 width ] [ uint16 height ] [ r g b ] [ r g b ] [ r g b ] … [ CRC ] + */ + +uint16_t imageWidth = 0; +uint16_t imageHeight = 0; + +// Statistics for speed testing +uint32_t rxCount = 0; +uint32_t rxStartTime = 0; +uint32_t rxLastTime = 0; + +#ifdef ARDUINO_NRF52832_FEATHER + #define TFT_DC 11 + #define TFT_CS 31 + #define STMPE_CS 30 + #define SD_CS 27 +#endif + +#ifdef ARDUINO_NRF52840_FEATHER + #define TFT_DC 10 + #define TFT_CS 9 + #define STMPE_CS 6 + #define SD_CS 5 +#endif + +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +void setup() +{ + Serial.begin(115200); + + tft.begin(); + tft.fillScreen(ILI9341_BLACK); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(1); + + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + + Bluefruit.begin(); + Bluefruit.setTxPower(4); // Check bluefruit.h for supported values + Bluefruit.setName("Bluefruit52"); + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms + + // Configure and Start BLE Uart Service + bleuart.begin(); + bleuart.setRxCallback(bleuart_rx_callback); + + // Set up and start advertising + startAdv(); + + // splash screen effect + delay(100); + + + tft.println("Advertising ... "); +} + +void startAdv(void) +{ + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_GENERIC_CLOCK); + + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(bleuart); + + // There is no room for Name in Advertising packet + // Use Scan response for Name + 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(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} + +void loop() +{ + // 3 seconds has passed and there is no data received + // then reset rx count + if ( (rxCount > 0) && (rxLastTime + 1000 < millis()) ) + { + print_speed(rxCount, rxLastTime-rxStartTime); + rxCount = 0; + } +} + +void connect_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + tft.println("Connected"); + + conn->requestPHY(); + tft.println("Switching PHY"); + + conn->requestDataLengthUpdate(); + tft.println("Updating Data Length"); + + conn->requestMtuExchange(247); + tft.println("Exchanging MTU"); + + tft.println("Ready to receive Image"); +} + +void print_speed(uint32_t count, uint32_t ms) +{ + Serial.print("Received "); + Serial.print(count); + Serial.print(" bytes in "); + Serial.print(ms / 1000.0F, 2); + Serial.println(" seconds."); + + Serial.print("Speed : "); + Serial.print( (count / 1000.0F) / (ms / 1000.0F), 2); + Serial.println(" KB/s.\r\n"); +} + +void bleuart_rx_callback(uint16_t conn_hdl) +{ + (void) conn_hdl; + + rxLastTime = millis(); + + // first packet + if ( rxCount == 0 ) + { + rxStartTime = millis(); + + // Incorrect format, possibly corrupted data + if ( bleuart.read() != '!' ) bleuart.flush(); + rxCount++; + + tft.fillScreen(ILI9341_BLACK); + tft.setCursor(0, 0); + } + + rxCount += bleuart.available(); + bleuart.flush(); // empty rx fifo +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle connection where this event happens + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) reason; + + tft.fillScreen(ILI9341_BLACK); + tft.setCursor(0, 0); + tft.println("Advertising ..."); +} diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/rssi_callback/rssi_callback.ino b/libraries/Bluefruit52Lib/examples/Peripheral/rssi_callback/rssi_callback.ino index c86f80d11..1791d1ebc 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/rssi_callback/rssi_callback.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/rssi_callback/rssi_callback.ino @@ -115,5 +115,5 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/rssi_poll/rssi_poll.ino b/libraries/Bluefruit52Lib/examples/Peripheral/rssi_poll/rssi_poll.ino index 5e2a15172..22f767a7e 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/rssi_poll/rssi_poll.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/rssi_poll/rssi_poll.ino @@ -121,5 +121,5 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino b/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino index c93e964a7..55a2f9195 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/throughput/throughput.ino @@ -14,16 +14,26 @@ #include -// String to send in the throughput test -#define TEST_STRING "01234567899876543210" -const int TEST_STRLEN = strlen(TEST_STRING); +/* Best result is + * - 8.74 KB/s with 20 ms, MTU = 23 + * - 23.62 KB/s with 7.5 ms, MTU = 23 + * - 47.85 KB/s with 15 ms, MTU = 247 + */ + +// data to send in the throughput test +char test_data[256] = { 0 }; -// Number of total data sent ( 1024 times the test string) -#define TOTAL_BYTES (1024 * strlen(TEST_STRING)) +// Number of packet to sent +// actualy number of bytes depends on the MTU of the connection +#define PACKET_NUM 1000 BLEDis bledis; BLEUart bleuart; +uint32_t rxCount = 0; +uint32_t rxStartTime = 0; +uint32_t rxLastTime = 0; + /**************************************************************************/ /*! @brief Sets up the HW an the BLE module (this function is called @@ -31,7 +41,7 @@ BLEUart bleuart; */ /**************************************************************************/ void setup(void) -{ +{ Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb @@ -43,11 +53,17 @@ void setup(void) // here in case you want to control this manually via PIN 19 Bluefruit.autoConnLed(true); + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values Bluefruit.setName("Bluefruit52"); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms // Configure and Start Device Information Service bledis.setManufacturer("Adafruit Industries"); @@ -57,6 +73,9 @@ void setup(void) // Configure and Start BLE Uart Service bleuart.begin(); + bleuart.setRxCallback(bleuart_rx_callback); + bleuart.setNotifyCallback(bleuart_notify_callback); + // Set up and start advertising startAdv(); } @@ -90,8 +109,26 @@ void startAdv(void) void connect_callback(uint16_t conn_handle) { - (void) conn_handle; + BLEConnection* conn = Bluefruit.Connection(conn_handle); Serial.println("Connected"); + + // request PHY changed to 2MB + Serial.println("Request to change PHY"); + conn->requestPHY(); + + // request to update data length + Serial.println("Request to change Data Length"); + conn->requestDataLengthUpdate(); + + // request mtu exchange + Serial.println("Request to change MTU"); + conn->requestMtuExchange(247); + + // request connection interval of 7.5 ms + //conn->requestConnectionParameter(6); // in unit of 1.25 + + // delay a bit for all the request to complete + delay(1000); } /** @@ -105,56 +142,99 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.println(); - Serial.println("Disconnected"); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); } -/**************************************************************************/ -/*! - @brief Constantly poll for new command or response data -*/ -/**************************************************************************/ -void loop(void) +void bleuart_rx_callback(uint16_t conn_hdl) +{ + (void) conn_hdl; + + rxLastTime = millis(); + + // first packet + if ( rxCount == 0 ) + { + rxStartTime = millis(); + } + + uint32_t count = bleuart.available(); + + rxCount += count; + bleuart.flush(); // empty rx fifo + + Serial.printf("RX %d bytes\n", count); +} + +void bleuart_notify_callback(uint16_t conn_hdl, bool enabled) { - uint32_t start, stop, sent; - uint32_t remaining = TOTAL_BYTES; - start = stop = sent = 0; + if ( enabled ) + { + Serial.println("Send a key and press enter to start test"); + } +} + +void print_speed(const char* text, uint32_t count, uint32_t ms) +{ + Serial.print(text); + Serial.print(count); + Serial.print(" bytes in "); + Serial.print(ms / 1000.0F, 2); + Serial.println(" seconds."); + + Serial.print("Speed : "); + Serial.print( (count / 1000.0F) / (ms / 1000.0F), 2); + Serial.println(" KB/s.\r\n"); +} + +void test_throughput(void) +{ + uint32_t start, sent; + start = sent = 0; + + const uint16_t data_mtu = Bluefruit.Connection(0)->getMtu() - 3; + memset(test_data, '1', data_mtu); + + uint32_t remaining = data_mtu*PACKET_NUM; + + Serial.print("Sending "); + Serial.print(remaining); + Serial.println(" bytes ..."); + Serial.flush(); + delay(1); + start = millis(); + while ( (remaining > 0) && Bluefruit.connected() && bleuart.notifyEnabled() ) + { + if ( !bleuart.write(test_data, data_mtu) ) break; + + sent += data_mtu; + remaining -= data_mtu; + } + + print_speed("Sent ", sent, millis() - start); +} + +void loop(void) +{ if (Bluefruit.connected() && bleuart.notifyEnabled()) { // Wait for user input before trying again - Serial.println("Connected. Send a key and press enter to start test"); - getUserInput(); + if ( Serial.available() ) + { + getUserInput(); + test_throughput(); + } - Serial.print("Sending "); - Serial.print(remaining); - Serial.println(" bytes ..."); - - start = millis(); - while ( (remaining > 0) && Bluefruit.connected() && bleuart.notifyEnabled() ) + // 3 seconds has passed and there is no data received + // then reset rx count + if ( (rxCount > 0) && (rxLastTime + 1000 < millis()) ) { - if ( !bleuart.print(TEST_STRING) ) break; - - sent += TEST_STRLEN; - remaining -= TEST_STRLEN; - - // Only print every 100th time - // if ( (sent % (100*TEST_STRLEN) ) == 0 ) - // { - // Serial.print("Sent: "); Serial.print(sent); - // Serial.print(" Remaining: "); Serial.println(remaining); - // } + print_speed("Received ", rxCount, rxLastTime-rxStartTime); + rxCount = 0; } - stop = millis() - start; - - Serial.print("Sent "); - Serial.print(sent); - Serial.print(" bytes in "); - Serial.print(stop / 1000.0F, 2); - Serial.println(" seconds."); - Serial.println("Speed "); - Serial.print( (sent / 1000.0F) / (stop / 1000.0F), 2); - Serial.println(" KB/s.\r\n"); + // Bluefruit.disconnect(0); + // delay(2000); } } diff --git a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp index 35852fb56..8cd519153 100644 --- a/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp +++ b/libraries/Bluefruit52Lib/src/BLEAdvertising.cpp @@ -340,19 +340,18 @@ bool BLEAdvertising::_start(uint16_t interval, uint16_t timeout) // ADV Params ble_gap_adv_params_t adv_para = { - .properties = { - .type = _type, - .anonymous = 0 - }, - .p_peer_addr = NULL , // Undirected advertisement - .interval = interval , // advertising interval (in units of 0.625 ms) - .duration = (uint16_t) (timeout*100), // in 10-ms unit - - .max_adv_evts = 0, // TODO can be used for fast/slow mode - .channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable - .filter_policy = BLE_GAP_ADV_FP_ANY , - - //.primary_phy, .secondary_phy, .set_id, .scan_req_notification + .properties = { .type = _type, .anonymous = 0 }, + .p_peer_addr = NULL , // Undirected advertisement + .interval = interval , // advertising interval (in units of 0.625 ms) + .duration = (uint16_t) (timeout*100) , // in 10-ms unit + + .max_adv_evts = 0 , // TODO can be used for fast/slow mode + .channel_mask = { 0, 0, 0, 0, 0 } , // 40 channel, set 1 to disable + .filter_policy = BLE_GAP_ADV_FP_ANY , + + .primary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used + .secondary_phy = BLE_GAP_PHY_AUTO , // 1 Mbps will be used + // , .set_id, .scan_req_notification }; // gap_adv long-live is required by SD v6 diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 50fade06d..269fb1c78 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -46,6 +46,8 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _connected = true; _mtu = BLE_GATT_ATT_MTU_DEFAULT; + _data_length = BLE_GATT_ATT_MTU_DEFAULT + 4; // 27 + _phy = BLE_GAP_PHY_1MBPS; _conn_interval = 0; _peer_addr = evt_connected->peer_addr; _role = evt_connected->role; @@ -94,11 +96,21 @@ uint16_t BLEConnection::getMtu (void) return _mtu; } -uint16_t BLEConnection::getConnInterval(void) +uint16_t BLEConnection::getConnectionInterval(void) { return _conn_interval; } +uint16_t BLEConnection::getDataLength(void) +{ + return _data_length; +} + +uint8_t BLEConnection::getPHY(void) +{ + return _phy; +} + ble_gap_addr_t BLEConnection::getPeerAddr (void) { return _peer_addr; @@ -132,6 +144,39 @@ bool BLEConnection::setTxPower(int8_t power) return true; } +bool BLEConnection::requestMtuExchange(uint16_t mtu) +{ + VERIFY_STATUS(sd_ble_gattc_exchange_mtu_request(_conn_hdl, mtu), false); + return true; +} + +bool BLEConnection::requestDataLengthUpdate(ble_gap_data_length_params_t const *p_dl_params, ble_gap_data_length_limitation_t *p_dl_limitation) +{ + VERIFY_STATUS(sd_ble_gap_data_length_update(_conn_hdl, p_dl_params, p_dl_limitation), false); + return true; +} + +bool BLEConnection::requestConnectionParameter(uint16_t conn_interval, uint16_t slave_latency, uint16_t sup_timeout) +{ + ble_gap_conn_params_t const conn_params = + { + .min_conn_interval = conn_interval, + .max_conn_interval = conn_interval, + .slave_latency = slave_latency, + .conn_sup_timeout = sup_timeout + }; + VERIFY_STATUS(sd_ble_gap_conn_param_update(_conn_hdl, &conn_params), false); + + return true; +} + +bool BLEConnection::requestPHY(uint8_t phy) +{ + ble_gap_phys_t gap_phy = { .tx_phys = phy, .rx_phys = phy }; + VERIFY_STATUS( sd_ble_gap_phy_update(_conn_hdl, &gap_phy), false); + return true; +} + bool BLEConnection::disconnect(void) { return ERROR_NONE == sd_ble_gap_disconnect(_conn_hdl, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); @@ -405,10 +450,11 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) ble_gap_conn_params_t* param = &evt->evt.gap_evt.params.conn_param_update.conn_params; _conn_interval = param->max_conn_interval; - LOG_LV2("GAP", "Conn Interval= %f", _conn_interval*1.25f); + LOG_LV1("GAP", "Conn Interval= %.2f ms, Latency = %d, Supervisor Timeout = %d ms", _conn_interval*1.25f, param->slave_latency, 10*param->conn_sup_timeout); } break; + //------------- MTU -------------// case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { uint16_t const max_mtu = Bluefruit.getMaxMtu(_role); @@ -420,6 +466,69 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) } break; + case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: + _mtu = evt->evt.gattc_evt.params.exchange_mtu_rsp.server_rx_mtu; + LOG_LV1("GAP", "ATT MTU is changed to %d", _mtu); + break; + + //------------- Data Length -------------// + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + { + ble_gap_data_length_params_t* param = &evt->evt.gap_evt.params.data_length_update_request.peer_params; + (void) param; + + LOG_LV1("GAP", "Data Length Request is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us", + param->max_tx_octets, param->max_rx_octets, param->max_tx_time_us, param->max_rx_time_us); + + // Let Softdevice decide the data length + VERIFY_STATUS( sd_ble_gap_data_length_update(_conn_hdl, NULL, NULL), ); + } + break; + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE: + { + ble_gap_data_length_params_t* datalen = &evt->evt.gap_evt.params.data_length_update.effective_params; + (void) datalen; + + LOG_LV1("GAP", "Data Length is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us", + datalen->max_tx_octets, datalen->max_rx_octets, datalen->max_tx_time_us, datalen->max_rx_time_us); + + _data_length = datalen->max_tx_octets; + } + break; + + //------------- PHY -------------// + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + { + ble_gap_phys_t* req_phy = &evt->evt.gap_evt.params.phy_update_request.peer_preferred_phys; + (void) req_phy; + + LOG_LV1("GAP", "PHY request tx = 0x%02X, rx = 0x%02X", req_phy->tx_phys, req_phy->rx_phys); + + // Tell SoftDevice to choose PHY automatically + ble_gap_phys_t phy = { BLE_GAP_PHY_AUTO, BLE_GAP_PHY_AUTO }; + (void) sd_ble_gap_phy_update(_conn_hdl, &phy); + } + break; + + case BLE_GAP_EVT_PHY_UPDATE: + { + ble_gap_evt_phy_update_t* active_phy = &evt->evt.gap_evt.params.phy_update; + + if ( active_phy->status != BLE_HCI_STATUS_CODE_SUCCESS ) + { + LOG_LV1("GAP", "Failed HCI status = 0x%02X", active_phy->status); + }else + { + char const *phy_str[] = { "Auto", "1 Mbps", "2 Mbps", "Coded" }; + (void) phy_str; + LOG_LV1("GAP", "PHY active tx: %s, rx: %s", phy_str[active_phy->tx_phy], phy_str[active_phy->rx_phy]); + + _phy = active_phy->tx_phy; + } + } + break; + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 165cdb79b..4be26b834 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -47,8 +47,11 @@ class BLEConnection uint16_t _conn_hdl; uint16_t _mtu; uint16_t _conn_interval; - uint16_t _ediv; + uint16_t _data_length; + uint8_t _phy; + uint8_t _role; + uint16_t _ediv; bool _connected; bool _paired; @@ -75,7 +78,9 @@ class BLEConnection uint8_t getRole(void); uint16_t getMtu (void); - uint16_t getConnInterval(void); + uint16_t getConnectionInterval(void); + uint16_t getDataLength(void); + uint8_t getPHY(void); ble_gap_addr_t getPeerAddr(void); uint16_t getPeerName(char* buf, uint16_t bufsize); @@ -84,6 +89,12 @@ class BLEConnection bool setTxPower(int8_t power); // set power for this connection + bool requestDataLengthUpdate(ble_gap_data_length_params_t const *p_dl_params = NULL, ble_gap_data_length_limitation_t *p_dl_limitation = NULL); + bool requestMtuExchange(uint16_t mtu); + bool requestPHY(uint8_t phy = BLE_GAP_PHY_AUTO); + bool requestConnectionParameter(uint16_t conn_interval, uint16_t slave_latency = BLE_GAP_CONN_SLAVE_LATENCY, uint16_t sup_timeout = BLE_GAP_CONN_SUPERVISION_TIMEOUT_MS/10); + bool requestPairing(void); + bool monitorRssi(uint8_t threshold = BLE_GAP_RSSI_THRESHOLD_INVALID); int8_t getRssi(void); void stopRssi(void); @@ -92,7 +103,6 @@ class BLEConnection bool getWriteCmdPacket(void); bool waitForIndicateConfirm(void); - bool requestPairing(void); bool storeCccd(void); bool loadKeys(bond_keys_t* bkeys); diff --git a/libraries/Bluefruit52Lib/src/BLEGatt.cpp b/libraries/Bluefruit52Lib/src/BLEGatt.cpp index e0f24d8f8..89e62bade 100644 --- a/libraries/Bluefruit52Lib/src/BLEGatt.cpp +++ b/libraries/Bluefruit52Lib/src/BLEGatt.cpp @@ -54,7 +54,7 @@ uint16_t BLEGatt::readCharByUuid(uint16_t conn_hdl, BLEUuid bleuuid, void* buffe while( _adamsg.isWaiting() ) { - delay( conn->getConnInterval() ); + delay( conn->getConnectionInterval() ); } _adamsg.begin(true); diff --git a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp index 3f8766b9a..303cf478e 100644 --- a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp @@ -158,7 +158,7 @@ void BLEPeriph::printInfo(void) Serial.println(); Serial.printf(title_fmt, "Conn Timeout"); - Serial.printf("%.2f ms", _ppcp.conn_sup_timeout*10.0f); + Serial.printf("%d ms", _ppcp.conn_sup_timeout*10); Serial.println(); } diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index fae9a09b4..a5860d06a 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -779,7 +779,7 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) uint16_t const conn_hdl = evt->evt.common_evt.conn_handle; BLEConnection* conn = this->Connection(conn_hdl); - LOG_LV1("BLE", "%s : Conn Handle = %d", dbg_ble_event_str(evt->header.evt_id), conn_hdl); + LOG_LV2("BLE", "%s : Conn Handle = %d", dbg_ble_event_str(evt->header.evt_id), conn_hdl); // GAP handler if ( conn ) conn->_eventHandler(evt); @@ -794,6 +794,9 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) ble_gap_evt_connected_t const * para = &evt->evt.gap_evt.params.connected; + LOG_LV1("GAP", "Conn Interval= %.2f ms, Latency = %d, Supervisor Timeout = %d ms", + para->conn_params.max_conn_interval*1.25f, para->conn_params.slave_latency, 10*para->conn_params.conn_sup_timeout); + if ( _connection[conn_hdl] ) { LOG_LV1("GAP", "Connection is already in used, something wrong !!"); @@ -852,60 +855,6 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) } break; - case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: - { - ble_gap_data_length_params_t* param = &evt->evt.gap_evt.params.data_length_update_request.peer_params; - (void) param; - - LOG_LV2("GAP", "Data Length Req is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us", - param->max_tx_octets, param->max_rx_octets, param->max_tx_time_us, param->max_rx_time_us); - - // Let Softdevice decide the data length - VERIFY_STATUS( sd_ble_gap_data_length_update(conn_hdl, NULL, NULL), ); - } - break; - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE: - { - ble_gap_data_length_params_t* datalen = &evt->evt.gap_evt.params.data_length_update.effective_params; - (void) datalen; - - LOG_LV2("GAP", "Data Length is (tx, rx) octets = (%d, %d), (tx, rx) time = (%d, %d) us", - datalen->max_tx_octets, datalen->max_rx_octets, datalen->max_tx_time_us, datalen->max_rx_time_us); - } - break; - - case BLE_GAP_EVT_PHY_UPDATE_REQUEST: - { - ble_gap_phys_t* req_phy = &evt->evt.gap_evt.params.phy_update_request.peer_preferred_phys; - char const *phy_str[] = { "Auto", "1 Mbps", "2 Mbps", "Coded" }; - - (void) req_phy; - (void) phy_str; - LOG_LV1("GAP", "PHY request tx: %s, rx: %s", phy_str[req_phy->tx_phys], phy_str[req_phy->rx_phys]); - - // Tell SoftDevice to choose PHY automatically - ble_gap_phys_t phy = { BLE_GAP_PHY_AUTO, BLE_GAP_PHY_AUTO }; - (void) sd_ble_gap_phy_update(conn_hdl, &phy); - } - break; - - case BLE_GAP_EVT_PHY_UPDATE: - { - ble_gap_evt_phy_update_t* active_phy = &evt->evt.gap_evt.params.phy_update; - - if ( active_phy->status != BLE_HCI_STATUS_CODE_SUCCESS ) - { - LOG_LV1("GAP", "Failed HCI status = 0x%02X", active_phy->status); - }else - { - char const *phy_str[] = { "Auto", "1 Mbps", "2 Mbps", "Coded" }; - (void) phy_str; - LOG_LV1("GAP", "PHY active tx: %s, rx: %s", phy_str[active_phy->tx_phy], phy_str[active_phy->rx_phy]); - } - } - break; - case BLE_EVT_USER_MEM_REQUEST: // We will handle Long Write sequence (RW Authorize PREP_WRITE_REQ) sd_ble_user_mem_reply(conn_hdl, NULL); diff --git a/libraries/Bluefruit52Lib/src/services/BLEUart.cpp b/libraries/Bluefruit52Lib/src/services/BLEUart.cpp index 8bad24b78..a178e48a3 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEUart.cpp +++ b/libraries/Bluefruit52Lib/src/services/BLEUart.cpp @@ -192,6 +192,24 @@ int BLEUart::read(uint8_t * buf, size_t size) return _rx_fifo->read(buf, size); } +uint8_t BLEUart::read8 (void) +{ + uint8_t num; + return read(&num, sizeof(num)) ? num : 0; +} + +uint16_t BLEUart::read16(void) +{ + uint16_t num; + return read((uint8_t*) &num, sizeof(num)) ? num : 0; +} + +uint32_t BLEUart::read32(void) +{ + uint32_t num; + return read((uint8_t*) &num, sizeof(num)) ? num : 0; +} + size_t BLEUart::write(uint8_t b) { return this->write(Bluefruit.connHandle(), &b, 1); diff --git a/libraries/Bluefruit52Lib/src/services/BLEUart.h b/libraries/Bluefruit52Lib/src/services/BLEUart.h index aa5f802dd..60e6d764b 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEUart.h +++ b/libraries/Bluefruit52Lib/src/services/BLEUart.h @@ -70,6 +70,11 @@ class BLEUart : public BLEService, public Stream bool flushTXD (void); bool flushTXD (uint16_t conn_hdl); + // Read helper + uint8_t read8 (void); + uint16_t read16(void); + uint32_t read32(void); + // Stream API virtual int read ( void ); virtual int read ( uint8_t * buf, size_t size ); diff --git a/tools/build_all.py b/tools/build_all.py index b58c5551b..64725e3f3 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -3,45 +3,71 @@ import sys import subprocess import time -from pathlib import Path - -home = str(Path.home()) - -exit_status = 0 travis = False if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true": travis = True +exit_status = 0 success_count = 0 fail_count = 0 -print("Setting board to Feather nRF52840") -subprocess.run("arduino --board adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0 --save-prefs", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +build_format = '| {:20} | {:30} | {:9} ' +build_separator = '-' * 77 + + +def build_examples(variant): + global exit_status, success_count, fail_count, build_format, build_separator + for sketch in glob.iglob('libraries/**/*.ino', recursive=True): + start_time = time.monotonic() -for sketch in glob.iglob('libraries/**/*.ino', recursive=True): - start_time = time.monotonic() - build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - build_duration = time.monotonic() - start_time + if os.path.exists(os.path.dirname(sketch) + '/.skip.' + variant): + success = "skipped" + else: + build_result = subprocess.run("arduino --verify {}".format(sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if build_result.returncode != 0: + exit_status = build_result.returncode + success = "\033[31mfailed\033[0m" + fail_count += 1 + else: + success = "\033[32msucceeded\033[0m" + success_count += 1 - if build_result.returncode != 0: - exit_status = build_result.returncode - success = "\033[31mfailed\033[0m" - fail_count += 1 - else: - success = "\033[32msucceeded\033[0m" - success_count += 1 + build_duration = time.monotonic() - start_time - if travis: - print('travis_fold:start:build-{}\\r'.format(sketch)) + if travis: + print('travis_fold:start:build-{}\\r'.format(sketch)) - print("Build {} took {:.2f}s and {}".format(sketch, build_duration, success)) - if build_result.returncode != 0: - print(build_result.stdout.decode("utf-8")) + print((build_format + '| {:.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration)) + + if build_result.returncode != 0: + print(build_result.stdout.decode("utf-8")) + + if travis: + print('travis_fold:end:build-{}\\r'.format(sketch)) + + +build_time = time.monotonic() + +print(build_separator) +print('| {:^73} |'.format('Feather nRF52840 Express')) +print(build_separator) +print((build_format + '| {:5} |').format('Library', 'Example', 'Result', 'Time')) +print(build_separator) +subprocess.run("arduino --board adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0 --save-prefs", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +build_examples('feather52840') - if travis: - print('travis_fold:end:build-{}\\r'.format(sketch)) +print('\r\n') +print(build_separator) +print('| {:^73} |'.format('Feather nRF52832')) +print((build_format + '| {:5} |').format('Library', 'Example', 'Result', 'Time')) +print(build_separator) +subprocess.run("arduino --board adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0 --save-prefs", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) +build_examples('feather52832') +print(build_separator) +build_time = time.monotonic() - build_time +print("Build Sumamary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m and took {:.2f}s".format(success_count, fail_count, build_time)) +print(build_separator) -print("Build Sumamary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m".format(success_count, fail_count)) -sys.exit(exit_status) \ No newline at end of file +sys.exit(exit_status)