jasoncoon

Bluetooth Goggles Sketch - FastLED Conversion

Aug 21st, 2015
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Bluetooth Goggles Sketch -- shows the Adafruit Bluefruit LE UART Friend
  2. // can be used even with Trinket or Gemma!
  3.  
  4. // https://www.adafruit.com/products/2479  
  5. // Works in conjunction with Bluefruit LE Connect app on iOS or Android --
  6. // pick colors or use '1' and '2' buttons to select pinwheel or sparkle modes.
  7. // You can try adding more, but space is VERY tight...helps to use Arduino IDE
  8. // 1.6.4 or later; produces slightly smaller code than the 1.0.X releases.
  9.  
  10. // BLUEFRUIT LE UART FRIEND MUST BE SWITCHED TO 'UART' MODE
  11.  
  12. #include <SPI.h>
  13. #include <SoftwareSerial.h>
  14. #include <FastLED.h>
  15. #ifdef _AVR_ATtiny85_ // Trinket, Gemma, etc.
  16.  #include <avr/power.h>
  17. #endif
  18.  
  19. #define RX_PIN    8 // Connect this Trinket pin to BLE 'TXO' pin
  20. #define CTS_PIN   6 // Connect this Trinket pin to BLE 'CTS' pin
  21. #define LED_PIN   4 // Connect NeoPixels to this Trinket pin
  22. #define CLOCK_PIN 3
  23. #define NUM_LEDS 72 // Two 16-LED NeoPixel rings
  24. #define FPS      30 // Animation frames/second (ish)
  25. #define COLOR_ORDER BGR
  26.  
  27. CRGB leds[NUM_LEDS];      //naming our LED array
  28.  
  29. SoftwareSerial    ser(RX_PIN, -1);
  30.  
  31. int BRIGHTNESS = 255;    //0-255.  Lower number saves battery life, higher number is screamingly bright
  32. TBlendType    currentBlending;
  33.  
  34. void setup() {
  35. #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  36.   // MUST do this on 16 MHz Trinket for serial & NeoPixels!
  37.   clock_prescale_set(clock_div_1);
  38. #endif
  39.   // Stop incoming data & init software serial
  40.   pinMode(CTS_PIN, OUTPUT); digitalWrite(CTS_PIN, HIGH);
  41.   ser.begin(9600);
  42.  
  43.   FastLED.addLeds<DOTSTAR, LED_PIN, CLOCK_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  44.   FastLED.setBrightness(  BRIGHTNESS );
  45.   currentBlending = LINEARBLEND;
  46. }
  47.  
  48. uint8_t  buf[3],              // Enough for RGB parse; expand if using sensors
  49.          animMode = 0,        // Current animation mode
  50.          animPos  = 0;        // Current animation position
  51.          
  52. CRGB color = CRGB::Red; // Current animation color (red by default)
  53. uint32_t prevTime = 0L; // For animation timing
  54.  
  55. void loop(void) {
  56.   int      c;
  57.   uint32_t t;
  58.  
  59.   // Animation happens at about 30 frames/sec.  Rendering frames takes less
  60.   // than that, so the idle time is used to monitor incoming serial data.
  61.   digitalWrite(CTS_PIN, LOW); // Signal to BLE, OK to send data!
  62.   for(;;) {
  63.     t = micros();                            // Current time
  64.     if((t - prevTime) >= (1000000L / FPS)) { // 1/30 sec elapsed?
  65.       prevTime = t;
  66.       break;                                 // Yes, go update LEDs
  67.     }                                        // otherwise...
  68.     if((c = ser.read()) == '!') {            // Received UART app input?
  69.       while((c = ser.read()) < 0);           // Yes, wait for command byte
  70.       switch(c) {
  71.        case 'B':       // Button (Control Pad)
  72.         if(readAndCheckCRC(255-'!'-'B', buf, 2) & (buf[1] == '1')) {
  73.           buttonPress(buf[0]); // Handle button-press message
  74.         }
  75.         break;
  76.        case 'C':       // Color Picker
  77.         if(readAndCheckCRC(255-'!'-'C', buf, 3)) {
  78.           // As mentioned earlier, setBrightness() was avoided to save space.
  79.           // Instead, results from the color picker (in buf[]) are divided
  80.           // by 4; essentially equivalent to setBrightness(64).  This is to
  81.           // improve battery run time (NeoPixels are still plenty bright).
  82.           color = CRGB(buf[0]/4, buf[1]/4, buf[2]/4);
  83.         }
  84.         break;
  85.        case 'Q':       // Quaternion
  86.         skipBytes(17); // 4 floats + CRC (see note below re: parsing)
  87.         break;
  88.        case 'A':       // Accelerometer
  89. #if 0
  90.         // The phone sensors are NOT used by this sketch, but this shows how
  91.         // they might be read.  First, buf[] must be delared large enough for
  92.         // the expected data packet (minus header & CRC) -- that's 16 bytes
  93.         // for quaternions (above), or 12 bytes for most of the others.
  94.         // Second, the first arg to readAndCheckCRC() must be modified to
  95.         // match the data type (e.g. 'A' here for accelerometer).  Finally,
  96.         // values can be directly type-converted to float by using a suitable
  97.         // offset into buf[] (e.g. 0, 4, 8, 12) ... it's not used in this
  98.         // example because floating-point math uses lots of RAM and code
  99.         // space, not suitable for the space-constrained Trinket/Gemma, but
  100.         // maybe you're using a Pro Trinket, Teensy, etc.
  101.         if(readAndCheckCRC(255-'!'-'A', buf, 12)) {
  102.           float x = *(float *)(&buf[0]),
  103.                 y = *(float *)(&buf[4]),
  104.                 z = *(float *)(&buf[8]);
  105.         }
  106.         // In all likelihood, updates from the buttons and color picker
  107.         // alone are infrequent enough that you could do without any mention
  108.         // of the CTS pin in this code.  It's the extra sensors that really
  109.         // start the firehose of data.
  110.         break;
  111. #endif
  112.        case 'G':       // Gyroscope
  113.        case 'M':       // Magnetometer
  114.        case 'L':       // Location
  115.         skipBytes(13); // 3 floats + CRC
  116.       }
  117.     }
  118.   }
  119.   digitalWrite(CTS_PIN, HIGH); // BLE STOP!
  120.  
  121.   // Show pixels calculated on prior pass; this ensures more uniform timing
  122.   FastLED.show();
  123.  
  124.   // Then calculate pixels for next frame...
  125.   switch(animMode) {
  126.    case 0: // Pinwheel mode
  127.     for(uint8_t i=0; i<NUM_LEDS/2; i++) {
  128.       CRGB c = CRGB::Black;
  129.       if(((animPos + i) & 7) < 2) c = color; // 4 pixels on...
  130.       leds[i] = c;         // First eye
  131.       leds[NUM_LEDS-1-i] = c; // Second eye (flipped)
  132.     }
  133.     animPos++;
  134.     break;
  135.    case 1: // Sparkle mode
  136.     leds[animPos] = CRGB::Black;     // Erase old dot
  137.     animPos = random(NUM_LEDS);           // Pick a new one
  138.     leds[animPos] = color; // and light it
  139.     break;
  140.   }
  141. }
  142.  
  143. boolean readAndCheckCRC(uint8_t sum, uint8_t *buf, uint8_t n) {
  144.   for(int c;;) {
  145.     while((c = ser.read()) < 0); // Wait for next byte
  146.     if(!n--) return (c == sum);  // If CRC byte, we're done
  147.     *buf++ = c;                  // Else store in buffer
  148.     sum   -= c;                  // and accumulate sum
  149.   }
  150. }
  151.  
  152. void skipBytes(uint8_t n) {
  153.   while(n--) {
  154.     while(ser.read() < 0);
  155.   }
  156. }
  157.  
  158. void buttonPress(char c) {
  159.   fill_solid(leds, NUM_LEDS, CHSV(0,0,0)); // Clear pixel data when switching modes (else residue)
  160.   switch(c) {
  161.    case '1':
  162.     animMode = 0; // Switch to pinwheel mode
  163.     break;
  164.    case '2':
  165.     animMode = 1; // Switch to sparkle mode
  166.     break;
  167.    case '3':
  168.     break;
  169.    case '4':
  170.     break;
  171.    case '5': // Up
  172.     break;
  173.    case '6': // Down
  174.     break;
  175.    case '7': // Left
  176.     break;
  177.    case '8': // Right
  178.     break;
  179.   }
  180. }
Advertisement
Add Comment
Please, Sign In to add comment