#include #include #include #include #include "Adafruit_BluefruitLE_SPI.h" #if SOFTWARE_SERIAL_AVAILABLE #include #endif #include "BluefruitConfig.h" #define REQUIRE_SERIAL false #define BT_SCAN_MS 100 #define MIN_FIRMWARE "0.7.0" #define FACTORYRESET true #define DIM_FACTOR 80 // Updated with bluetooth connection state volatile bool conn = false; // pgm_read_word hates having msg_0, etc passed directly, but a secondary lookup table works // so long as that table has const set twice (?) #define MSG_PATTERN_RAINBOW 0 const char msg_0[] PROGMEM = "pattern rainbow"; #define MSG_PATTERN_OFF 1 const char msg_1[] PROGMEM = "pattern off"; #define MSG_PATTERN_INVALID 2 const char msg_2[] PROGMEM = "pattern invalid"; #define MSG_SPEED_INVALID 3 const char msg_3[] PROGMEM = "out of range (0,200)"; #define MSG_SPEED_CHANGED 4 const char msg_4[] PROGMEM = "speed changed"; const char *const msg_table[] PROGMEM = {msg_0, msg_1, msg_2, msg_3, msg_4}; #define MSG_UNSET 5 // Interrupts are needed to TX without deadlocking, so instead of doing it // inside another interrupt, save the MSG_ ID here for loop() to do it volatile int to_rx = MSG_UNSET; Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST); void bluetooth_setup(void){ if ( !ble.begin(VERBOSE_MODE) ) { Serial.println(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?")); while(1); // halt } if ( FACTORYRESET ) { if ( ! ble.factoryReset() ){ Serial.println(F("Couldn't factory reset")); while(1); // halt } } if ( !ble.isVersionAtLeast(MIN_FIRMWARE) ){ Serial.print(F("Callback requires at least")); Serial.println(F(MIN_FIRMWARE)); while(1); // halt } pinMode(BLUEFRUIT_SPI_IRQ, INPUT_PULLUP); //ble.echo(false); // disable command echo //ble.verbose(false); // disable debug info ble.sendCommandCheckOK(F("AT+GAPDEVNAME=Suit LEDs")); // Change name displayed in bluetooth scans ble.sendCommandCheckOK(F("AT+HWMODELED=2")); // Show TX/RX activity on LED //ble.info(); ble.setConnectCallback(on_connect); ble.setDisconnectCallback(on_disconnect); ble.setBleUartRxCallback(BleUartRX); ble.setMode(BLUEFRUIT_MODE_DATA); } void on_connect(void){ // Status light will go solid blue because of AT+HWMODELED=2 Serial.println(F("Bluetooth Connected")); conn = true; } void on_disconnect(void){ // Blue status light will shut off because of AT+HWMODELED=2 Serial.println(F("Bluetooth Disconnected")); conn = false; } void BleUartRX(char payload[], uint16_t payload_len){ // Red status light should flicker because of AT+HWMODELED=2 if (payload_len < 3){ Serial.print("packet length "); Serial.print(payload_len); Serial.println(" is too short"); return; } // first byte is the command uint8_t cmd_byte = payload[0]; // last byte is the CRC uint8_t crc_byte = payload[payload_len-1]; // all other bytes are the data for that command uint16_t data_len = payload_len-2; uint8_t data[data_len]; uint16_t payload_index; uint16_t data_index; for (payload_index=1, data_index=0; payload_index num_pixels - 1){ loc = index + offset - num_pixels; } else { loc = offset + index; } pixel.setPixelColor( loc, pack_color(r/DIM_FACTOR, g/DIM_FACTOR, b/DIM_FACTOR) ); if (index < 24){ // red -> yellow shifting g += 10; } else if (index < 48){ // yellow -> green shifting if (index == 24){ g = 255; } r -= 10; } else if (index < 72){ // green -> cyan shifting if (index == 48){ r = 0; } b += 10; } else if (index < 96){ // cyan -> blue shifting if (index == 72){ b = 255; } g -= 10; } else if (index < 120){ // blue -> magenta shifting if (index == 96){ g = 0; } r += 10; } else { // magenta -> red shifting if (index == 120){ r = 255; } b -= 10; } } pixel.show(); } public: void update(void){ unsigned long now = millis(); if (now - wait > last){ last = now; if (pattern == 'o'){ off(); } else { rainbow(); } offset += 1; if (offset == num_pixels){ offset = 0; } } } }; volatile Strip strip = Strip(6, 144); void setWait(char data[], uint16_t len){ String wait = ""; for (uint16_t index=0; index= 0 && wait_int <= 200){ strip.wait = wait_int; to_rx = MSG_SPEED_CHANGED; } else { to_rx = MSG_SPEED_INVALID; } } void setPattern(char data[], uint16_t len){ if (len != 1){ to_rx = MSG_PATTERN_INVALID; } else if (data[0] == 'r'){ strip.pattern = 'r'; to_rx = MSG_PATTERN_RAINBOW; } else if (data[0] == 'o') { strip.pattern = 'o'; to_rx = MSG_PATTERN_OFF; } else { to_rx = MSG_PATTERN_INVALID; } } void do_rx_send(void){ if (to_rx == MSG_UNSET){ return; } char buffer[20]; strcpy_P(buffer, (char *)pgm_read_word(&(msg_table[to_rx]))); to_rx = MSG_UNSET; if (conn){ Serial.print(F("[TX] ")); Serial.print(buffer); Serial.println(); ble.write(buffer); } else { Serial.println(F("Disconnected. Couldn't TX: ")); Serial.print(buffer); Serial.println(); } } void setup(void) { if (REQUIRE_SERIAL){ while (!Serial); Serial.begin(115200); } bluetooth_setup(); Serial.println(F("Ready")); } void loop(void) { ble.update(BT_SCAN_MS); do_rx_send(); strip.update(); }