View difference between Paste ID: cftMr5v6 and B9xbXdWP
SHOW: | | - or go back to the newest paste.
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 );
43+
  FastLED.addLeds<DOTSTAR, LED_PIN, CLOCK_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
44
  FastLED.setBrightness(  BRIGHTNESS );
45-
  currentBlending = BLEND;
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-
uint32_t color    = 0x400000, // Current animation color (red by default)
51+
         
52-
         prevTime = 0L;       // For animation timing
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-
          color = pixels.Color(buf[0]/4, buf[1]/4, buf[2]/4);
81+
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-
      uint32_t c = 0;
127+
128
      CRGB c = CRGB::Black;
129-
      leds[i](c);         // First eye
129+
130-
      leds[NUM_LEDS-1-i](c); // Second eye (flipped)
130+
      leds[i] = c;         // First eye
131
      leds[NUM_LEDS-1-i] = c; // Second eye (flipped)
132
    }
133
    animPos++;
134
    break;
135-
    leds[animPos](0);     // Erase old dot
135+
136
    leds[animPos] = CRGB::Black;     // Erase old dot
137-
    leds[animPos](color); // and light it
137+
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
}