Skip to content

Commit ef46994

Browse files
authored
Merge pull request #36 from dmadison/groups
LED Indices / Groups
2 parents 4214adb + db311e1 commit ef46994

File tree

1 file changed

+86
-33
lines changed

1 file changed

+86
-33
lines changed

Arduino/LEDstream_FastLED/LEDstream_FastLED.ino

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ const unsigned long
3939
const uint16_t
4040
SerialTimeout = 60; // time before LEDs are shut off if no data (in seconds), 0 to disable
4141

42+
// --- Group Settings (uncomment to add)
43+
// Grouping will set a group of LEDs to the data received for a single one. This
44+
// lets you send less data to the device, increasing throughput and therefore
45+
// framerate - at the cost of resolution. Grouping only works if your strip is
46+
// evenly divisible by the amount of data sent.
47+
// #define GROUPING // enable the automatic grouping feature
48+
4249
// --- Optional Settings (uncomment to add)
4350
#define SERIAL_FLUSH // Serial buffer cleared on LED latch
4451
// #define CLEAR_ON_START // LEDs are cleared on reset
@@ -52,7 +59,6 @@ const uint16_t
5259
#include <FastLED.h>
5360

5461
CRGB leds[Num_Leds];
55-
uint8_t * ledsRaw = (uint8_t *)leds;
5662

5763
// A 'magic word' (along with LED count & checksum) precedes each block
5864
// of LED data; this assists the microcontroller in syncing up with the
@@ -79,13 +85,18 @@ const uint8_t magic[] = {
7985

8086
enum processModes_t {Header, Data} mode = Header;
8187

82-
int16_t c; // current byte, must support -1 if no data available
83-
uint16_t outPos; // current byte index in the LED array
84-
uint32_t bytesRemaining; // count of bytes yet received, set by checksum
85-
unsigned long t, lastByteTime, lastAckTime; // millisecond timestamps
88+
uint32_t ledIndex; // current index in the LED array
89+
uint32_t ledsRemaining; // count of LEDs still to write, set by checksum (u16 + 1)
90+
91+
unsigned long lastByteTime; // ms timestamp, last byte received
92+
unsigned long lastAckTime; // ms timestamp, lask acknowledge to the host
93+
94+
unsigned long (*const now)(void) = millis; // timing function
95+
const unsigned long Timebase = 1000; // time units per second
8696

87-
void headerMode();
88-
void dataMode();
97+
void headerMode(uint8_t c);
98+
void dataMode(uint8_t c);
99+
void groupProcessing();
89100
void timeouts();
90101

91102
// Macros initialized
@@ -97,9 +108,6 @@ void timeouts();
97108
#endif
98109

99110
#ifdef DEBUG_LED
100-
#define ON 1
101-
#define OFF 0
102-
103111
#define D_LED(x) do {digitalWrite(DEBUG_LED, x);} while(0)
104112
#else
105113
#define D_LED(x)
@@ -142,18 +150,18 @@ void setup(){
142150
}
143151

144152
void loop(){
145-
t = millis(); // Save current time
153+
const int c = Serial.read(); // read one byte
146154

147-
// If there is new serial data
148-
if((c = Serial.read()) >= 0){
149-
lastByteTime = lastAckTime = t; // Reset timeout counters
155+
// if there is data available
156+
if(c >= 0){
157+
lastByteTime = lastAckTime = now(); // Reset timeout counters
150158

151159
switch(mode) {
152160
case Header:
153-
headerMode();
161+
headerMode(c);
154162
break;
155163
case Data:
156-
dataMode();
164+
dataMode(c);
157165
break;
158166
}
159167
}
@@ -163,7 +171,7 @@ void loop(){
163171
}
164172
}
165173

166-
void headerMode(){
174+
void headerMode(uint8_t c){
167175
static uint8_t
168176
headPos,
169177
hi, lo, chk;
@@ -188,10 +196,10 @@ void headerMode(){
188196
chk = c;
189197
if(chk == (hi ^ lo ^ 0x55)) {
190198
// Checksum looks valid. Get 16-bit LED count, add 1
191-
// (# LEDs is always > 0) and multiply by 3 for R,G,B.
192-
D_LED(ON);
193-
bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
194-
outPos = 0;
199+
// (# of LEDs is always > 0), save and reset data
200+
D_LED(HIGH);
201+
ledIndex = 0;
202+
ledsRemaining = (256UL * (uint32_t)hi + (uint32_t)lo + 1UL);
195203
memset(leds, 0, Num_Leds * sizeof(struct CRGB));
196204
mode = Data; // Proceed to latch wait mode
197205
}
@@ -201,32 +209,77 @@ void headerMode(){
201209
}
202210
}
203211

204-
void dataMode(){
205-
// If LED data is not full
206-
if (outPos < sizeof(leds)){
207-
ledsRaw[outPos++] = c; // Issue next byte
212+
void dataMode(uint8_t c){
213+
static uint8_t channelIndex = 0;
214+
215+
// if LED data is not full, save the byte
216+
if (ledIndex < Num_Leds) {
217+
leds[ledIndex].raw[channelIndex] = c;
208218
}
209-
bytesRemaining--;
210-
211-
if(bytesRemaining == 0) {
212-
// End of data -- issue latch:
213-
mode = Header; // Begin next header search
219+
channelIndex++; // increment regardless, for oversized data
220+
221+
// if we've filled this LED, move to the next
222+
if (channelIndex >= 3) {
223+
// reset the channel index so we can get ready to write
224+
// the next LED, starting on the first channel (R/G/B)
225+
channelIndex = 0;
226+
227+
// allow this to max out at Num_Leds, so that it represents which
228+
// LEDs have data in them when the strip is ready to write
229+
if (ledIndex < Num_Leds) ledIndex++;
230+
231+
// finished writing one LED, decrement the counter
232+
ledsRemaining--;
233+
}
234+
235+
// if all data has been read, write the output
236+
if (ledsRemaining == 0) {
237+
#if defined(GROUPING)
238+
groupProcessing();
239+
#endif
240+
214241
FastLED.show();
242+
channelIndex = 0; // reset channel tracking
243+
mode = Header; // begin next header search
244+
215245
D_FPS;
216-
D_LED(OFF);
246+
D_LED(LOW);
217247
SERIAL_FLUSH;
218248
}
219249
}
220250

251+
void groupProcessing() {
252+
// if we've received the same amount of data as there
253+
// are LEDs in the strip, don't do any group processing
254+
if (Num_Leds == ledIndex) return;
255+
256+
const uint16_t GroupSize = Num_Leds / ledIndex;
257+
const uint16_t GroupRemainder = Num_Leds - (ledIndex * GroupSize);
258+
259+
// if the value isn't evenly divisible, don't bother trying to group
260+
// (it won't look right without significant processing, i.e. overhead)
261+
if (GroupRemainder != 0) return;
262+
263+
// otherwise, iterate backwards through the array, copying each LED color
264+
// forwards to the rest of its group
265+
for (uint16_t group = 1; group <= ledIndex; ++group) {
266+
const CRGB GroupColor = leds[ledIndex - group];
267+
const uint16_t GroupStart = Num_Leds - (group * GroupSize);
268+
fill_solid(&leds[GroupStart], GroupSize, GroupColor);
269+
}
270+
}
271+
221272
void timeouts(){
273+
const unsigned long t = now();
274+
222275
// No data received. If this persists, send an ACK packet
223276
// to host once every second to alert it to our presence.
224-
if((t - lastAckTime) >= 1000) {
277+
if((t - lastAckTime) >= Timebase) {
225278
Serial.print("Ada\n"); // Send ACK string to host
226279
lastAckTime = t; // Reset counter
227280

228281
// If no data received for an extended time, turn off all LEDs.
229-
if(SerialTimeout != 0 && (t - lastByteTime) >= (uint32_t) SerialTimeout * 1000) {
282+
if(SerialTimeout != 0 && (t - lastByteTime) >= (uint32_t) SerialTimeout * Timebase) {
230283
memset(leds, 0, Num_Leds * sizeof(struct CRGB)); //filling Led array by zeroes
231284
FastLED.show();
232285
mode = Header;

0 commit comments

Comments
 (0)