summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hyperion/hyperion.ino279
1 files changed, 0 insertions, 279 deletions
diff --git a/hyperion/hyperion.ino b/hyperion/hyperion.ino
deleted file mode 100644
index 75e6858..0000000
--- a/hyperion/hyperion.ino
+++ /dev/null
@@ -1,279 +0,0 @@
1// Arduino "bridge" code between host computer and WS2801-based digital
2// RGB LED pixels (e.g. Adafruit product ID #322). Intended for use
3// with USB-native boards such as Teensy or Adafruit 32u4 Breakout;
4// works on normal serial Arduinos, but throughput is severely limited.
5// LED data is streamed, not buffered, making this suitable for larger
6// installations (e.g. video wall, etc.) than could otherwise be held
7// in the Arduino's limited RAM.
8
9// Some effort is put into avoiding buffer underruns (where the output
10// side becomes starved of data). The WS2801 latch protocol, being
11// delay-based, could be inadvertently triggered if the USB bus or CPU
12// is swamped with other tasks. This code buffers incoming serial data
13// and introduces intentional pauses if there's a threat of the buffer
14// draining prematurely. The cost of this complexity is somewhat
15// reduced throughput, the gain is that most visual glitches are
16// avoided (though ultimately a function of the load on the USB bus and
17// host CPU, and out of our control).
18
19// LED data and clock lines are connected to the Arduino's SPI output.
20// On traditional Arduino boards, SPI data out is digital pin 11 and
21// clock is digital pin 13. On both Teensy and the 32u4 Breakout,
22// data out is pin B2, clock is B1. LEDs should be externally
23// powered -- trying to run any more than just a few off the Arduino's
24// 5V line is generally a Bad Idea. LED ground should also be
25// connected to Arduino ground.
26
27// --------------------------------------------------------------------
28// This file is part of Adalight.
29
30// Adalight is free software: you can redistribute it and/or modify
31// it under the terms of the GNU Lesser General Public License as
32// published by the Free Software Foundation, either version 3 of
33// the License, or (at your option) any later version.
34
35// Adalight is distributed in the hope that it will be useful,
36// but WITHOUT ANY WARRANTY; without even the implied warranty of
37// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38// GNU Lesser General Public License for more details.
39
40// You should have received a copy of the GNU Lesser General Public
41// License along with Adalight. If not, see
42// <http://www.gnu.org/licenses/>.
43// --------------------------------------------------------------------
44
45
46// --------------------------------------------------------------------
47// Note: This is a fork form the LEDstream.
48//
49// This version uses the LIB FastLED to work with the WS2812b LEDs.
50//
51// This Version works with a 150LED-Stripe with a frames/sec: 61, bytes/sec: 11524
52// tested with the programme colorswirl (see the C folder) and an Arduino UNO.
53//
54// TOOD:
55// - Cleanup: remove the SPI code
56// - Show a startup Pattern
57// - remove flicker when sending more the 63 frames/sec.
58//
59// --------------------------------------------------------------------
60
61#include <FastLED.h>
62#include <avr/sleep.h>
63#include <avr/power.h>
64
65#define NUM_LEDS 190
66#define DATA_PIN 3
67CRGB leds[NUM_LEDS];
68
69// A 'magic word' (along with LED count & checksum) precedes each block
70// of LED data; this assists the microcontroller in syncing up with the
71// host-side software and properly issuing the latch (host I/O is
72// likely buffered, making usleep() unreliable for latch). You may see
73// an initial glitchy frame or two until the two come into alignment.
74// The magic word can be whatever sequence you like, but each character
75// should be unique, and frequent pixel values like 0 and 255 are
76// avoided -- fewer false positives. The host software will need to
77// generate a compatible header: immediately following the magic word
78// are three bytes: a 16-bit count of the number of LEDs (high byte
79// first) followed by a simple checksum value (high byte XOR low byte
80// XOR 0x55). LED data follows, 3 bytes per LED, in order R, G, B,
81// where 0 = off and 255 = max brightness.
82
83static const uint8_t magic[] = {'A','d','a'};
84#define MAGICSIZE sizeof(magic)
85#define HEADERSIZE (MAGICSIZE + 3)
86
87#define MODE_HEADER 0
88#define MODE_HOLD 1
89#define MODE_DATA 2
90
91// If no serial data is received for a while, the LEDs are shut off
92// automatically. This avoids the annoying "stuck pixel" look when
93// quitting LED display programs on the host computer.
94static const unsigned long serialTimeout = 15000; // 15 seconds
95
96void setup()
97{
98 // Dirty trick: the circular buffer for serial data is 256 bytes,
99 // and the "in" and "out" indices are unsigned 8-bit types -- this
100 // much simplifies the cases where in/out need to "wrap around" the
101 // beginning/end of the buffer. Otherwise there'd be a ton of bit-
102 // masking and/or conditional code every time one of these indices
103 // needs to change, slowing things down tremendously.
104 uint8_t
105 buffer[256],
106 indexIn = 0,
107 indexOut = 0,
108 mode = MODE_HEADER,
109 hi, lo, chk, i, spiFlag,
110 r,b,g, l;
111 int16_t
112 bytesBuffered = 0,
113 hold = 0,
114 c;
115 int32_t
116 bytesRemaining;
117 unsigned long
118 startTime,
119 lastByteTime,
120 lastAckTime,
121 t;
122 uint32_t value,index = 0, ledcount;
123
124 delay(5000);
125
126#if 1
127 power_adc_disable();
128 power_usart0_disable();
129 power_usart1_disable();
130 power_spi_disable();
131 power_twi_disable();
132 power_timer1_disable();
133 power_timer2_disable();
134 power_timer3_disable();
135#endif
136
137 FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
138
139 Serial.begin(115200); // Teensy/32u4 disregards baud rate; is OK!
140
141 //set the last LED to white
142 leds[NUM_LEDS-1].setRGB(100,100,100);
143 FastLED.show();
144 //delay(1000);
145 //reset();
146 //delay(1000);
147
148 Serial.print("Ada\n"); // Send ACK string to host
149 RXLED1;
150 TXLED1;
151
152 startTime = micros();
153 lastByteTime = lastAckTime = millis();
154
155 // loop() is avoided as even that small bit of function overhead
156 // has a measurable impact on this code's overall throughput.
157
158 for(;;)
159 {
160 RXLED1;
161 TXLED1;
162
163 // Implementation is a simple finite-state machine.
164 // Regardless of mode, check for serial input each time:
165 t = millis();
166 if ((bytesBuffered < 256) && ((c = Serial.read()) >= 0))
167 {
168 buffer[indexIn++] = c;
169 bytesBuffered++;
170 lastByteTime = lastAckTime = t; // Reset timeout counters
171 }
172 else
173 {
174 // No data received. If this persists, send an ACK packet
175 // to host once every second to alert it to our presence.
176 if((t - lastAckTime) > 1000)
177 {
178 Serial.print("Ada\n"); // Send ACK string to host
179 lastAckTime = t; // Reset counter
180 }
181 // If no data received for an extended time, turn off all LEDs.
182 if((t - lastByteTime) > serialTimeout)
183 {
184 reset();
185 delay(1); // One millisecond pause = latch
186 lastByteTime = t; // Reset counter
187 }
188 }
189
190 switch(mode)
191 {
192 case MODE_HEADER:
193 // In header-seeking mode. Is there enough data to check?
194 if(bytesBuffered >= HEADERSIZE)
195 {
196 // Indeed. Check for a 'magic word' match.
197 for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
198 if(i == MAGICSIZE)
199 {
200 // Magic word matches. Now how about the checksum?
201 hi = buffer[indexOut++];
202 lo = buffer[indexOut++];
203 chk = buffer[indexOut++];
204 if(chk == (hi ^ lo ^ 0x55))
205 {
206 // Checksum looks valid. Get 16-bit LED count, add 1
207 // (# LEDs is always > 0) and multiply by 3 for R,G,B.
208 bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
209 bytesBuffered -= 3;
210 ledcount = 0;
211 mode = MODE_HOLD; // Proceed to latch wait mode
212 }
213 else
214 {
215 // Checksum didn't match; search resumes after magic word.
216 indexOut -= 3; // Rewind
217 }
218 } // else no header match. Resume at first mismatched byte.
219 bytesBuffered -= i;
220 }
221 break;
222
223 case MODE_HOLD:
224 // Ostensibly "waiting for the latch from the prior frame
225 // to complete" mode, but may also revert to this mode when
226 // underrun prevention necessitates a delay.
227
228 if((micros() - startTime) < hold) break; // Still holding; keep buffering
229
230 // Latch/delay complete. Advance to data-issuing mode...
231 //LED_PORT &= ~LED_PIN; // LED off
232 mode = MODE_DATA; // ...and fall through (no break):
233
234 case MODE_DATA:
235 if(bytesRemaining > 2)
236 {
237 if(bytesBuffered > 2)
238 {
239 //we read one LED -> 3 Bytes r.g.b
240 bytesBuffered -= 3;
241 bytesRemaining -= 3;
242 leds[ledcount++].setRGB(buffer[indexOut++], buffer[indexOut++], buffer[indexOut++]);
243 }
244 // If serial buffer is threatening to underrun, start
245 // introducing progressively longer pauses to allow more
246 // data to arrive (up to a point).
247 if((bytesBuffered < 32) && (bytesRemaining > bytesBuffered) && (mode!=MODE_HEADER))
248 {
249 startTime = micros();
250 hold = 100 + (32 - bytesBuffered) * 10;
251 mode = MODE_HOLD;
252 }
253 }
254 else
255 {
256 // End of data -- issue latch:
257 startTime = micros();
258 hold = 1000; // Latch duration = 1000 uS
259 //LED_PORT |= LED_PIN; // LED on
260 mode = MODE_HEADER; // Begin next header search
261 FastLED.show();
262 }
263 } // end switch
264 } // end for(;;)
265}
266
267void reset()
268{
269 for (uint16_t i=0; i< NUM_LEDS; i++)
270 leds[i] = CRGB::Black;
271 FastLED.show();
272}
273
274void loop()
275{
276 // Not used. See note in setup() function.
277}
278
279