Initial import of v2 goggles that use ws2812 rings from adafruit
[goggles] / main.c
CommitLineData
5fc23db2
JM
1/******************************************************************************/
2/* Files to Include */
3/******************************************************************************/
4
5#include <stdint.h> /* For uint8_t definition */
6#include <stdbool.h> /* For true/false definition */
7
8#include "user.h" /* User funct/params, such as InitApp */
9
10#include "ws2811.h"
11#include "serial.h"
12
13
14/******************************************************************************/
15/* User Global Variable Declaration */
16/******************************************************************************/
17
18/* i.e. uint8_t <variable_name>; */
19
20
21void RGBWheel(uint16_t pos, uint8_t *r, uint8_t *g, uint8_t *b)
22{
23 switch (pos / 128)
24 {
25 case 0:
26 *r = (127 - pos % 128);
27 *g = pos % 128;
28 *b = 0;
29 break;
30 case 1:
31 *g = (127 - pos % 128);
32 *b = pos % 128;
33 *r = 0;
34 break;
35 case 2:
36 *b = 127 - pos % 128;
37 *r = pos % 128;
38 *g = 0;
39 break;
40 }
41}
42
43/* connect Fixed Voltage Reference to A2D convertor
44 * input, set Vdd as reference, read value.
45 * (val / 1024) * Vref == Vdd
46 */
47bool test_battery(void)
48{
49 uint16_t volt;
50 // read battery
51 // Read Vdd by sampling FVR
52 FVRCONbits.ADFVR = 0b10; // 2.048v // 1.024v
53 FVRCONbits.FVREN = 1; // enable
54 while (!FVRCONbits.FVRRDY) {}; // wait for it to stabilise
55
56 ADCON1bits.ADCS = 0b110; // slowest sample clock
57 ADCON1bits.ADFM = 1; // right justify
58 ADCON0bits.CHS = 0b11111; // FVR input
59 ADCON1bits.ADPREF = 0b00; // +ve ref Vdd
60 ADCON0bits.ADON = 1; // enable ADC
61
62 ADCON0bits.GO = 1; // start conversion
63 while (ADCON0bits.GO) {}; // wait til finished
64
65 volt = (ADRESH << 8) | ADRESL;
66
67 // 3.0 V is >= 0x02BB
68 if (volt >= 0x02BB) {
69 unsigned char i;
70 unsigned char *p;
71
72 // first pixel faint red, rest black
73 // battery below 3.0v
74 p = rgbdata;
75 for (i=0; i<RGB_COUNT; i++) *p++=0;
76 p = rgbdata;
77 p++;
78 *p = 0x08;
79
80 ws2811_transmit();
81 return true;
82 }
83 return false;
84}
85
86#ifdef SMALL_RAND
87static uint8_t random_byte = 0xB4;
88
89/* generate a random number */
90uint8_t dorand(void)
91{
92 asm("BCF STATUS,0");
93 asm("RRF _random_byte,W");
94 asm("BTFSC STATUS,0");
95 asm("XORLW 0xB4");
96 asm("MOVWF _random_byte");
97
98 return random_byte;
99}
100#else
101uint16_t dorand(void)
102{
103 static uint16_t lfsr = 0xACE1u;
104 lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB400u);
105
106 return lfsr;
107}
108
109#endif
110
111#define CHECK_MSEC 5 // sample key every 5 mS
112#define PRESS_MSEC 10 // stable before presses
113#define RELEASE_MSEC 100 // stable before released
114
115
116/* test to see if the button has been pressed */
117bool test_button(void)
118{
119 static bool down = false;
120 static uint8_t count = PRESS_MSEC / CHECK_MSEC;
121
122 // button was up
123 if (!down) {
124 if (PORTAbits.RA1 == 0)
125 count--;
126 else
127 count = PRESS_MSEC / CHECK_MSEC;
128 // has been down for the count, flip state
129 if (count <= 0) {
130 down = true;
131 count = RELEASE_MSEC / CHECK_MSEC;
132 }
133 } else {
134 if (PORTAbits.RA1 == 1)
135 count--;
136 else
137 count = RELEASE_MSEC / CHECK_MSEC;
138 // has been back up for the count
139 // flip state, and say we saw one cycle
140 if (count <= 0) {
141 down = false;
142 count = PRESS_MSEC / CHECK_MSEC;
143 return true;
144 }
145 }
146 return false;
147}
148
149
150void clear_all(void)
151{
152 unsigned char i;
153 /* blank everything */
154 for (i=0; i<RGB_COUNT; i++) rgbdata[i]=0;
155}
156
157/* how much rainbow to show 0-384 */
158static const uint32_t quant = 384; //200;
159
160bool rainbow_draw(void)
161{
162 unsigned char r,g,b;
163 unsigned char *p;
164 unsigned char i;
165
166 /* draw a rainbow */
167 p = rgbdata;
168 for (i=0; i<16; i++) {
169 RGBWheel((i * quant / 16) % 384, &r, &g, &b);
170 *(p++) = g/4;
171 *(p++) = r/4;
172 *(p++) = b/4;
173 }
174 for (i=16; i>0; i--) {
175 RGBWheel(((i-1) * quant / 16) % 384, &r, &g, &b);
176 *(p++) = g/4;
177 *(p++) = r/4;
178 *(p++) = b/4;
179 }
180 return true;
181}
182
183#define RAIN_UNIT 5
184unsigned char rain_delay = RAIN_UNIT;
185
186bool rainbow_rotate(void)
187{
188 static unsigned char delay = 0;
189
190 unsigned char r,g,b;
191 unsigned char *p;
192 unsigned char i;
193 unsigned char t;
194
195 if ((delay--) > 0) return false;
196
197 // rotate the colours
198 p = rgbdata;
199
200 g = p[0];
201 r = p[1];
202 b = p[2];
203
204 for (i=0; i<15*3; i++) {
205 *p = *(p+3);
206 p++;
207 }
208 *(p++) = g;
209 *(p++) = r;
210 *(p++) = b;
211
212 // left eye, other direction
213
214 p += 15 * 3;
215 g = p[0];
216 r = p[1];
217 b = p[2];
218 p += 2;
219 for (i=0; i<15*3; i++) {
220 *p = *(p-3);
221 p--;
222 }
223 *(p--) = b;
224 *(p--) = r;
225 *(p--) = g;
226
227 delay = rain_delay;
228 return true;
229}
230
231
232/******
233 colour bouncing blobs mode
234 */
235
236int8_t rspeed, gspeed, bspeed;
237#define MAX_SPEED 30;
238#define MAX_LEN 8
239#define MAX_BRIGHT 32
240
241bool bouncer_draw(void)
242{
243 clear_all();
244
245 rspeed = dorand() % MAX_SPEED;
246 gspeed = dorand() % MAX_SPEED;
247 bspeed = dorand() % MAX_SPEED;
248
249 unsigned char i;
250 // draw rand len red
251 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
252 rgbdata[(3*i)+1] = MAX_BRIGHT;
253 }
254 // draw rand len green
255 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
256 rgbdata[(3*i)] = MAX_BRIGHT;
257 }
258 // draw rand len blue
259 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
260 rgbdata[(3*i)+2] = MAX_BRIGHT;
261 }
262
263 return true;
264}
265
266bool bouncer_rotate(uint8_t loop)
267{
268 unsigned char * p;
269 unsigned char i;
270
271 if (loop % rspeed == 0) {
272 if (rspeed > 0 ) {
273 // moving up
274 if (rgbdata[ (LED_COUNT-1)*3+1 ] == 0) {
275 // still space to move up
276 p = rgbdata + RGB_COUNT - 5;
277 for (i=LED_COUNT-1; i > 0; i--) {
278 p[3] = *p;
279 p-=3;
280 }
281 rgbdata[1] = 0;
282 } else {
283 rspeed = -rspeed;
284 }
285 } else {
286 // moving down
287 if (rgbdata[1] == 0 || (rgbdata[1]!=0 && rgbdata[4]!=0)) {
288 // still space to move down
289 p = rgbdata + 1;
290 for (i=LED_COUNT-1; i>0; i++) {
291 *p = p[3];
292 p+=3;
293 }
294 rgbdata[RGB_COUNT-2] = 0;
295 } else {
296 rspeed = dorand() % MAX_SPEED;
297 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
298 rgbdata[(3*i)+1] = MAX_BRIGHT;
299 }
300 }
301 }
302 }
303 if (loop % gspeed == 0) {
304 if (gspeed > 0 ) {
305 // moving up
306 if (rgbdata[ (LED_COUNT-1)*3 ] == 0) {
307 // still space to move up
308 p = rgbdata + RGB_COUNT - 6;
309 for (i=LED_COUNT-1; i > 0; i--) {
310 p[3] = *p;
311 p-=3;
312 }
313 rgbdata[0] = 0;
314 } else {
315 gspeed = -gspeed;
316 }
317 } else {
318 // moving down
319 if (rgbdata[0] == 0 || (rgbdata[0]!=0 && rgbdata[3]!=0)) {
320 // still space to move down
321 p = rgbdata;
322 for (i=LED_COUNT-1; i>0; i++) {
323 *p = p[3];
324 p+=3;
325 }
326 rgbdata[RGB_COUNT-3] = 0;
327 } else {
328 gspeed = dorand() % MAX_SPEED;
329 // draw rand len green
330 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
331 rgbdata[(3*i)] = MAX_BRIGHT;
332 }
333 }
334 }
335 }
336 if (loop % bspeed == 0) {
337 if (bspeed > 0 ) {
338 // moving up
339 if (rgbdata[ (LED_COUNT-1)*3+2 ] == 0) {
340 // still space to move up
341 p = rgbdata + RGB_COUNT - 4;
342 for (i=LED_COUNT-1; i > 0; i--) {
343 p[3] = *p;
344 p-=3;
345 }
346 rgbdata[2] = 0;
347 } else {
348 bspeed = -bspeed;
349 }
350 } else {
351 // moving down
352 if (rgbdata[2] == 0 || (rgbdata[2]!=0 && rgbdata[5]!=0)) {
353 // still space to move down
354 p = rgbdata + 2;
355 for (i=LED_COUNT-1; i>0; i++) {
356 *p = p[3];
357 p+=3;
358 }
359 rgbdata[RGB_COUNT-1] = 0;
360 } else {
361 bspeed = dorand() % MAX_SPEED;
362 // draw rand len blue
363 for (i=(dorand() % MAX_LEN)+1; i>0; i--) {
364 rgbdata[(3*i)+2] = MAX_BRIGHT;
365 }
366 }
367 }
368 }
369
370 return true;
371}
372
373/* fade in and out mode */
374bool glow_draw(uint8_t r, uint8_t g, uint8_t b)
375{
376 rspeed = r / 8;
377 gspeed = g / 8;
378 bspeed = b / 8;
379
380 return false;
381}
382
383bool glow_rotate(uint8_t loop)
384{
385 unsigned char *p;
386 unsigned char i;
387
388 uint8_t val = loop & 0x7F;
389
390 if (loop >= 128)
391 val = 128 - val;
392
393 val /= 2; /* range is now 0-63 */
394
395 uint8_t r,g,b;
396 g = (uint16_t)gspeed * val / 64;
397 r = (uint16_t)rspeed * val / 64;
398 b = (uint16_t)bspeed * val / 64;
399
400 /* draw a rainbow */
401 p = rgbdata;
402 for (i=0; i<LED_COUNT; i++) {
403 *(p++) = g;
404 *(p++) = r;
405 *(p++) = b;
406 }
407
408 return true;
409}
410
411bool dot_draw(uint8_t r, uint8_t g, uint8_t b)
412{
413 uint8_t i;
414 uint8_t *p = rgbdata;
415 for (i=0; i<RGB_COUNT;i++) *(p++)=0;
416
417 rgbdata[0] = g / 8;
418 rgbdata[1] = r / 8;
419 rgbdata[2] = b / 8;
420 rgbdata[48+0] = g / 8;
421 rgbdata[48+1] = r / 8;
422 rgbdata[48+2] = b / 8;
423
424 return false;
425}
426
427/******************************************************************************/
428/* Main Program */
429/******************************************************************************/
430
431#define MAX_MODE 8
432
433
434
435
436void main(void)
437{
438 unsigned char mode = 2;
439 bool changed = false;
440 uint8_t loop = 0;
441
442 /* Initialize I/O and Peripherals for application */
443 InitApp();
444 ws2811_init();
445
446 /* initial pattern */
447 rainbow_draw();
448 ws2811_transmit();
449
450 glow_draw(0,255,0);
451
452 /* main loop */
453 while(1)
454 {
455 CLRWDT(); // tell watchdog we are still awake
456
457 /* test if the battery is dead, stop if it is */
458 if (test_battery()) {
459 SLEEP();
460 }
461
462 /* if button is pressed, change mode */
463 if (test_button()) {
464 mode = (mode + 1) % MAX_MODE;
465 loop = 0;
466
467 // initialise the new mode
468 switch (mode) {
469 case 0:
470 rain_delay = RAIN_UNIT;
471 changed = rainbow_draw();
472 break;
473 case 1:
474 changed = bouncer_draw();
475 break;
476 case 2:
477 changed = glow_draw(0,255,0);
478 break;
479 case 3:
480 changed = glow_draw(255,0,0);
481 break;
482 case 4:
483 changed = glow_draw(0,0,255);
484 break;
485 case 5:
486 changed = glow_draw(255,0,255);
487 break;
488 case 6:
489 changed = dot_draw(255,255,255);
490 break;
491 case 7:
492 changed = dot_draw(0,8,0);
493 break;
494 }
495 } else {
496 /* otherwise run mode maintenance */
497 switch (mode) {
498 case 0:
499 changed = rainbow_rotate();
500 break;
501 case 1:
502 changed = bouncer_rotate(loop);
503 break;
504 case 2:
505 case 3:
506 case 4:
507 changed = glow_rotate(loop);
508 break;
509 case 5:
510 if (loop == 0) {
511 uint16_t n = dorand() % quant;
512 uint8_t r,g,b;
513 RGBWheel(n, &r, &g, &b);
514 changed = glow_draw(r, g, b);
515 }
516 changed = glow_rotate(loop);
517 break;
518 case 6:
519 changed = rainbow_rotate();
520 break;
521 case 7:
522 if (loop==0) changed = rainbow_rotate();
523 break;
524 }
525 }
526
527 /* transmit the latest data set */
528 if (changed) ws2811_transmit();
529
530 /* wait a bit */
531 __delay_ms(5);
532
533 loop++;
534 }
535}
536