Initial import of v2 goggles that use ws2812 rings from adafruit
[goggles] / main.c
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
21 void 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  */
47 bool 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
87 static uint8_t random_byte = 0xB4;
88
89 /* generate a random number */
90 uint8_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
101 uint16_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 */
117 bool 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
150 void 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 */
158 static const uint32_t quant = 384; //200;
159
160 bool 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
184 unsigned char rain_delay = RAIN_UNIT;
185
186 bool 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
236 int8_t rspeed, gspeed, bspeed;
237 #define MAX_SPEED 30;
238 #define MAX_LEN 8
239 #define MAX_BRIGHT 32
240
241 bool 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
266 bool 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 */
374 bool 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
383 bool 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
411 bool 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
436 void 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