#include #include #include #include #include "Adafruit_BluefruitLE_SPI.h" #if SOFTWARE_SERIAL_AVAILABLE #include #endif #include "BluefruitConfig.h" const uint8_t PROGMEM gamma[] = GAMMA_CORRECTION; #define REQUIRE_SERIAL false #define BT_SCAN_MS 50 #define MIN_FIRMWARE "0.7.0" #define FACTORYRESET true #define SHIFTING_STOPPED 0 #define SHIFTING_FORWARD 1 #define SHIFTING_REVERSE 2 #define PATTERN_OFF 0 #define PATTERN_RAINBOW 1 #define PATTERN_RED 2 // Updated with bluetooth connection state volatile bool conn = false; const char msg_pattern_off[] PROGMEM = "pattern off"; const char msg_pattern_rainbow[] PROGMEM = "pattern rainbow"; const char msg_pattern_invalid[] PROGMEM = "pattern invalid"; const char msg_speed_out_of_range[] PROGMEM = "out of range (0,200)"; const char msg_speed_changed[] PROGMEM = "speed changed"; // 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 = NULL; 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 last){ last = now; add_offset(); } if (pattern == PATTERN_RAINBOW){ rainbow(); } else if (pattern == PATTERN_RED){ red(); } else { off(); } pixel.show(); } private: void off(void){ for(uint8_t i=0; i= num_pixels){ loc -= num_pixels; } return (uint8_t)loc; } else if (shifting == SHIFTING_REVERSE){ uint16_t loc = num_pixels - offset + index; if (loc >= num_pixels){ loc -= num_pixels; } return (uint8_t)loc; } return index; // SHIFTING_STOPPED } void set_pixel_rgb(uint8_t index, uint8_t rgb[]){ set_pixel_rgb(index, rgb[0], rgb[1], rgb[2]); } void set_pixel_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue){ pixel.setPixelColor( get_offset_loc(index), pixel.Color( pgm_read_byte(&gamma[red / dim]), pgm_read_byte(&gamma[green / dim]), pgm_read_byte(&gamma[blue / dim]) ) ); } void set_pixel_rgbw(uint8_t index, uint8_t rgb[]){ set_pixel_rgbw(index, rgb[0], rgb[1], rgb[2], rgb[3]); } void set_pixel_rgbw(uint8_t index, uint8_t red, uint8_t green, uint8_t blue, uint8_t white){ pixel.setPixelColor( get_offset_loc(index), pixel.Color( pgm_read_byte(&gamma[red / dim]), pgm_read_byte(&gamma[green / dim]), pgm_read_byte(&gamma[blue / dim]), pgm_read_byte(&gamma[white / dim]) ) ); } void rainbow(void){ uint8_t rgb[] = {255, 0, 0}; // starting RGB value uint8_t phase_len = num_pixels / 6; // how long each rainbow phase is uint8_t bump = 255 / phase_len; // how much to increase between pixels set_pixel_rgb(0, rgb); // first pixel for (uint8_t index=1; index < num_pixels; index++){ uint8_t phase = index / phase_len; // which section we're in if (phase % 2 == 0){ // even-index phases add; odd-indexed subtracts // (r,g,b) index for each phase in order is 1,0,2,1,0, rgb[(6 - phase + 1) % 3] += bump; } else { rgb[(6 - phase + 1) % 3] -= bump; } if (index % phase_len == 0) { // this is the transition between phases // max out the change from the previous phase if (phase % 2 == 0){ rgb[(6 - phase + 2) % 3] = 0; } else { rgb[(6 - phase + 2) % 3] = 255; } } set_pixel_rgb(index, rgb); } } void red(void){ float bump = 255.0 / (num_pixels / 2 + 1); uint8_t half_point = num_pixels / 2 + 1; float red = 0; set_pixel_rgb(0, 1, 0, 0); //set_pixel_rgbw(0, 0, 0, 0, 255); for (uint8_t index=1; index < num_pixels; index++){ if (index < half_point){ red += bump; } else { red -= bump; } uint8_t red_int = (uint8_t)red; //uint8_t white_int = (255 - red_int + 1) / 2; set_pixel_rgb(index, red_int, 0, 0); //set_pixel_rgbw(index, red_int, 0, 0, white_int); } } }; volatile Strip strip1 = Strip(5, 144); volatile Strip strip2 = Strip(6, 144); volatile Strip strip3 = Strip(11, 24); volatile Strip strip4 = Strip(13, 144); void set_wait(char data[], uint16_t len){ String wait = ""; for (uint16_t index=0; index= 0 && wait_int <= 200){ strip1.wait = wait_int; strip2.wait = wait_int; to_rx = msg_speed_changed; } else { to_rx = msg_speed_out_of_range; } } void set_pattern(char data[], uint16_t len){ if (len != 1){ to_rx = msg_pattern_invalid; } else if (data[0] == 'r'){ strip1.pattern = PATTERN_RED; strip2.pattern = PATTERN_RED; to_rx = msg_pattern_rainbow; } else if (data[0] == 'o') { strip1.pattern = PATTERN_OFF; strip2.pattern = PATTERN_OFF; to_rx = msg_pattern_off; } else { to_rx = msg_pattern_invalid; } } void set_amplitude(char data[], uint16_t len){ if (len == 1){ strip1.amplitude = data[0]; strip2.amplitude = data[0]; //Serial.println((uint8_t)data[0]); Serial.println(255 - (uint8_t)data[0]); } else { Serial.println(F("invalid len for amplitude")); } } void do_rx_send(void){ /* if to_rx is set to a message, try to send it over bluetooth */ if (to_rx == NULL){ return; } char* msg = flash_msg(to_rx); to_rx = NULL; if (conn){ Serial.print(F("[TX] ")); Serial.println(msg); ble.write(msg); } else { Serial.print(F("Disconnected. Couldn't TX: ")); Serial.println(msg); } free(msg); } char * flash_msg(const char* addr){ /* return a char* array from flash memory; be sure to free() it after */ uint8_t buff_size = strlen_P(addr); char * buffer = (char *) malloc (buff_size); for (uint8_t index=0; index < buff_size; index++){ buffer[index] = pgm_read_byte_near(addr + index); } return buffer; } void setup(void) { if (REQUIRE_SERIAL){ while (!Serial); Serial.begin(115200); } bluetooth_setup(); strip3.wait = 30; Serial.println(F("Ready")); } void loop(void) { ble.update(BT_SCAN_MS); do_rx_send(); strip1.update(); strip2.update(); strip3.update(); strip4.update(); }