/*---------------------------------------------------------------------------------------- Created by Phillip Burgess Modified by Brandon M. for personal preference ------------------------------------------------------------------------------------------ Bluetooth Goggles Sketch -- shows the Adafruit Bluefruit LE UART Friend can be used even with Trinket or Gemma! */ // https://www.adafruit.com/products/2479 /* Works in conjunction with Bluefruit LE Connect app on iOS or Android -- pick colors or use '1' and '2' buttons to select pinwheel or sparkle modes. You canred try adding more, but space is VERY tight...helps to use Arduino IDE 1.6.4 or later; produces slightly smaller code than the 1.0.X releases. */ // BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE #include #include #ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc. #include #endif #define RX_PIN 2 // Connect this Trinket pin to BLE 'TXO' pin #define CTS_PIN 1 // Connect this Trinket pin to BLE 'CTS' pin #define LED_PIN 0 // Connect NeoPixels to this Trinket pin #define NUM_LEDS 32 // Two 16-LED NeoPixel rings #define FPS 30 // Animation frames/second (ish) SoftwareSerial ser(RX_PIN, -1); Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN); void setup() { #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L) // MUST do this on 16 MHz Trinket for serial & NeoPixels! clock_prescale_set(clock_div_1); #endif // Stop incoming data & init software serial pinMode(CTS_PIN, OUTPUT); digitalWrite(CTS_PIN, HIGH); ser.begin(9600); pixels.begin(); // NeoPixel init /* Flash space is tight on Trinket/Gemma, so setBrightness() is avoided -- it adds ~200 bytes. Instead the color picker input is 'manually' scaled. */ } uint8_t buf[3], // Enough for RGB parse; expand if using sensors animMode = 0, // Current animation mode animPos = 0; // Current animation position uint32_t color = 0xFFFF00, // Current animation color (Yellow by default, is also brighter here than after color change) prevTime = 0L; // For animation timing void loop(void) { int c; uint32_t t; /* Animation happens at about 30 frames/sec. Rendering frames takes less than that, so the idle time is used to monitor incoming serial data. */ digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data! for(;;) { t = micros(); // Current time if((t - prevTime) >= (1000000L / FPS)) { // 1/30 sec elapsed? prevTime = t; break; // Yes, go update LEDs } // otherwise... if((c = ser.read()) == '!') { // Received UART app input? while((c = ser.read()) < 0); // Yes, wait for command byte switch(c) { case 'B': // Button (Control Pad) if(readAndCheckCRC(255-'!'-'B', buf, 2) & (buf[1] == '1')) { buttonPress(buf[0]); // Handle button-press message } break; case 'C': // Color Picker if(readAndCheckCRC(255-'!'-'C', buf, 3)) { /* As mentioned earlier, setBrightness() was avoided to save space. Instead, results from the color picker (in buf[]) are divided by 4; essentially equivalent to setBrightness(64). This is to improve battery run time (NeoPixels are still plenty bright). */ color = pixels.Color(buf[0]/4, buf[1]/4, buf[2]/4); } break; case 'Q': // Quaternion skipBytes(17); // 4 floats + CRC (see note below re: parsing) break; case 'A': // Accelerometer #if 0 /* The phone sensors are NOT used by this sketch, but this shows how they might be read. First, buf[] must be delared large enough for the expected data packet (minus header & CRC) -- that's 16 bytes for quaternions (above), or 12 bytes for most of the others. Second, the first arg to readAndCheckCRC() must be modified to match the data type (e.g. 'A' here for accelerometer). Finally, values can be directly type-converted to float by using a suitable offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this example because floating-point math uses lots of RAM and code space, not suitable for the space-constrained Trinket/Gemma, but maybe you're using a Pro Trinket, Teensy, etc. */ if(readAndCheckCRC(255-'!'-'A', buf, 12)) { float x = *(float *)(&buf[0]), y = *(float *)(&buf[4]), z = *(float *)(&buf[8]); } /* In all likelihood, updates from the buttons and color picker alone are infrequent enough that you could do without any mention of the CTS pin in this code. It's the extra sensors that really start the firehose of data. */ break; #endif case 'G': // Gyroscope case 'M': // Magnetometer case 'L': // Location skipBytes(13); // 3 floats + CRC } } } digitalWrite(CTS_PIN, HIGH); // BLE STOP! // Show pixels calculated on *prior* pass; this ensures more uniform timing pixels.show(); // Then calculate pixels for *next* frame... switch(animMode) { case 0: // Pinwheel mode for(uint8_t i=0; i