diff --git a/.gitignore b/.gitignore index c564d4d..4b9629c 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ manifest.mf nbbuild.xml nbproject +*.swp +*.swo diff --git a/examples/bleuart/.bleuart.ino.swp b/examples/bleuart/.bleuart.ino.swp deleted file mode 100644 index 37e62da..0000000 Binary files a/examples/bleuart/.bleuart.ino.swp and /dev/null differ diff --git a/examples/central_bleuart/.central_bleuart.ino.swp b/examples/central_bleuart/.central_bleuart.ino.swp deleted file mode 100644 index 46e467a..0000000 Binary files a/examples/central_bleuart/.central_bleuart.ino.swp and /dev/null differ diff --git a/firmware/controller/controller.ino b/firmware/controller/controller.ino new file mode 100644 index 0000000..9e7e532 --- /dev/null +++ b/firmware/controller/controller.ino @@ -0,0 +1,189 @@ +/********************************************************************* + 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 + +#define RIGHT 2 +#define FOG 3 +#define LEFT 4 + +BLEClientDis clientDis; +BLEClientUart clientUart; + +void setup() +{ + Serial.begin(115200); + + Serial.println("Bluefruit52 Central BLEUART Example"); + Serial.println("-----------------------------------\n"); + + // 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"); + + // Configure DIS client + clientDis.begin(); + + // 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 + + // Setup buttons + pinMode(RIGHT, INPUT_PULLUP); + pinMode(FOG, INPUT_PULLUP); + pinMode(LEFT, INPUT_PULLUP); +} + +/** + * 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); + } +} + +/** + * Callback invoked when an connection is established + * @param conn_handle + */ +void connect_callback(uint16_t conn_handle) +{ + Serial.println("Connected"); + + Serial.print("Dicovering DIS ... "); + if ( clientDis.discover(conn_handle) ) + { + Serial.println("Found it"); + char buffer[32+1]; + + // read and print out Manufacturer + memset(buffer, 0, sizeof(buffer)); + if ( clientDis.getManufacturer(buffer, sizeof(buffer)) ) + { + Serial.print("Manufacturer: "); + Serial.println(buffer); + } + + // read and print out Model Number + memset(buffer, 0, sizeof(buffer)); + if ( clientDis.getModel(buffer, sizeof(buffer)) ) + { + Serial.print("Model: "); + Serial.println(buffer); + } + + Serial.println(); + } + + 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"); + + // disconect since we couldn't find bleuart service + Bluefruit.Central.disconnect(conn_handle); + } +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle + * @param reason + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.println("Disconnected"); +} + +/** + * 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) +{ + Serial.print("[RX]: "); + + while ( uart_svc.available() ) + { + Serial.print( (char) uart_svc.read() ); + } + + Serial.println(); +} + +void loop() +{ + if (Bluefruit.Central.connected()) + { + if (clientUart.discovered()) + { + if (!digitalRead(LEFT)) { + clientUart.print('L'); + } else if (!digitalRead(FOG)) { + clientUart.print('F'); + } else if (!digitalRead(RIGHT)) { + clientUart.print('R'); + } + } + } + + delay(10); +} + diff --git a/firmware/vest/vest.ino b/firmware/vest/vest.ino new file mode 100644 index 0000000..b62975f --- /dev/null +++ b/firmware/vest/vest.ino @@ -0,0 +1,265 @@ +/********************************************************************* + 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 + *********************************************************************/ +#include +#include + +#define LEFT_LED 4 +#define RIGHT_LED 5 + +#define NUM_PIXELS 16 +#define MAX_RUN_COUNT 192 + +enum stripStates { + OFF, + STRIP_START, + STRIP_RUN, + STRIP_STOP, +}; + +enum stripStates leftStripState = OFF; +enum stripStates rightStripState = OFF; + +// LED Strips +Adafruit_NeoPixel leftStrip = Adafruit_NeoPixel(NUM_PIXELS, LEFT_LED, NEO_GRB + NEO_KHZ800); +Adafruit_NeoPixel rightStrip = Adafruit_NeoPixel(NUM_PIXELS, RIGHT_LED, NEO_GRB + NEO_KHZ800); + +// BLE Service +BLEDis bledis; +BLEUart bleuart; +BLEBas blebas; + +// Software Timer for blinking RED LED +SoftwareTimer softwareTimer; + +void setup() +{ + Serial.begin(115200); + Serial.println("Bluefruit52 BLEUART Example"); + Serial.println("---------------------------\n"); + + // Initialize softwareTimer for 1000 ms and start it + //softwareTimer.begin(1000, blink_timer_callback); + softwareTimer.begin(50, run_machines_callback); + softwareTimer.start(); + + // Setup the BLE LED to be enabled on CONNECT + // Note: This is actually the default behaviour, but provided + // here in case you want to control this LED 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(); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + Bluefruit.setName("Bluefruit52"); + //Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections + Bluefruit.setConnectCallback(connect_callback); + Bluefruit.setDisconnectCallback(disconnect_callback); + + // Configure and Start Device Information Service + bledis.setManufacturer("Adafruit Industries"); + bledis.setModel("Bluefruit Feather52"); + bledis.begin(); + + // Configure and Start BLE Uart Service + bleuart.begin(); + + // Start BLE Battery Service + blebas.begin(); + blebas.write(100); + + // Set up and start advertising + startAdv(); + + Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); + Serial.println("Once connected, enter character(s) that you wish to send"); + + leftStrip.begin(); + rightStrip.begin(); +} + +void startAdv(void) +{ + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include bleuart 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(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() +{ + // Forward data from HW Serial to BLEUART + while (Serial.available()) + { + // Delay to wait for enough input, since we have a limited transmission buffer + delay(2); + + uint8_t buf[64]; + int count = Serial.readBytes(buf, sizeof(buf)); + bleuart.write( buf, count ); + } + + // Forward from BLEUART to HW Serial + while ( bleuart.available() ) + { + uint8_t ch; + ch = (uint8_t) bleuart.read(); + + switch(ch) { + case 'L': + leftStripState = STRIP_START; + rightStripState = STRIP_STOP; + break; + case 'F': + leftStripState = STRIP_START; + rightStripState = STRIP_START; + break; + case 'R': + leftStripState = STRIP_STOP; + rightStripState = STRIP_START; + break; + } + Serial.write(ch); + } + + // Request CPU to enter low-power mode until an event/interrupt occurs + waitForEvent(); +} + +void connect_callback(uint16_t conn_handle) +{ + char central_name[32] = { 0 }; + Bluefruit.Gap.getPeerName(conn_handle, central_name, sizeof(central_name)); + + Serial.print("Connected to "); + Serial.println(central_name); +} + +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.println(); + Serial.println("Disconnected"); +} + +/** + * Software Timer callback is invoked via a built-in FreeRTOS thread with + * minimal stack size. Therefore it should be as simple as possible. If + * a periodically heavy task is needed, please use Scheduler.startLoop() to + * create a dedicated task for it. + * + * More information http://www.freertos.org/RTOS-software-timer.html + */ +void blink_timer_callback(TimerHandle_t xTimerID) +{ + (void) xTimerID; + digitalToggle(LED_RED); +} + +/** + * RTOS Idle callback is automatically invoked by FreeRTOS + * when there are no active threads. E.g when loop() calls delay() and + * there is no bluetooth or hw event. This is the ideal place to handle + * background data. + * + * NOTE: FreeRTOS is configured as tickless idle mode. After this callback + * is executed, if there is time, freeRTOS kernel will go into low power mode. + * Therefore waitForEvent() should not be called in this callback. + * http://www.freertos.org/low-power-tickless-rtos.html + * + * WARNING: This function MUST NOT call any blocking FreeRTOS API + * such as delay(), xSemaphoreTake() etc ... for more information + * http://www.freertos.org/a00016.html + */ +void rtos_idle_callback(void) +{ + // Don't call any other FreeRTOS blocking API() + // Perform background task(s) here +} + +void processStripState(Adafruit_NeoPixel &strip, enum stripStates &stripState, int &count) { + switch (stripState) { + case OFF: + break; + + case STRIP_START: + count = 0; + stripState = STRIP_RUN; + break; + + case STRIP_RUN: + for (int i = 0; i < NUM_PIXELS; i++) { + if (i <= count % NUM_PIXELS) { + strip.setPixelColor(i, strip.Color(150, 60, 0)); + } else { + strip.setPixelColor(i, strip.Color(0, 0, 0)); + } + } + + count++; + if (count > MAX_RUN_COUNT) { + stripState = STRIP_STOP; + } + break; + + case STRIP_STOP: + for (int i = 0; i < NUM_PIXELS; i++) { + strip.setPixelColor(i, strip.Color(0, 0, 0)); + } + + count = 0; + stripState = OFF; + break; + } + + strip.show(); +} + +void run_machines_callback(TimerHandle_t xTimerID) +{ + (void) xTimerID; + + static int leftCount = 0; + static int rightCount = 0; + + processStripState(leftStrip, leftStripState, leftCount); + processStripState(rightStrip, rightStripState, rightCount); + +}