diff options
Diffstat (limited to 'src/app/ws2812b_uart')
-rw-r--r-- | src/app/ws2812b_uart/Makefile.inc | 2 | ||||
-rw-r--r-- | src/app/ws2812b_uart/main.cc | 202 |
2 files changed, 204 insertions, 0 deletions
diff --git a/src/app/ws2812b_uart/Makefile.inc b/src/app/ws2812b_uart/Makefile.inc new file mode 100644 index 0000000..ce0a386 --- /dev/null +++ b/src/app/ws2812b_uart/Makefile.inc @@ -0,0 +1,2 @@ +loop ?= 1 +arch_drivers += ,stdin,neopixel diff --git a/src/app/ws2812b_uart/main.cc b/src/app/ws2812b_uart/main.cc new file mode 100644 index 0000000..0becbf9 --- /dev/null +++ b/src/app/ws2812b_uart/main.cc @@ -0,0 +1,202 @@ +#include "arch.h" +#include "driver/neopixel.h" +#include "driver/stdin.h" +#include "driver/stdout.h" +#include <util/delay.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/wdt.h> + +#define NUM_PIXELS 66 + +Adafruit_NeoPixel np(NUM_PIXELS, GPIO::pb0, NEO_GRB+NEO_KHZ800); + +class Blinkencat { + public: + enum Mode : uint8_t { + OFF = 0, + RGBWHEEL_FAST, + RGBWHEEL_SLOW, + RGBFADE_FAST, + RGBFADE_SLOW, + BRIGHTRGBWHEEL_FAST, + BRIGHTRGBWHEEL_SLOW, + BRIGHTRGBFADE_FAST, + BRIGHTRGBFADE_SLOW, + COLD_WHITE, + STROBE, + COLOR_STROBE, + MODE_ENUM_MAX + }; + + Mode mode; + + void setup(void); + void next_mode(void); + void idle(void); + void loop(void); + + Blinkencat() : mode(RGBWHEEL_SLOW) {} +}; + +void Blinkencat::setup(void) +{ + np.setup(); + gpio.input(GPIO::pb1, 0); + gpio.input(GPIO::pd3, 1); + gpio.enable_int(GPIO::pd3); + + // One ADC conversion per four seconds + TCCR1A = 0; + TCCR1B = _BV(CS12) | _BV(CS10); + + // Measure internal 1.1V bandgap using VCC as reference on each Timer 1 overflow + ADMUX = _BV(REFS0) | 0x0e; + ADCSRB = _BV(ADTS2) | _BV(ADTS1); + ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADPS2) | _BV(ADPS1); +} + +void Blinkencat::idle(void) +{ + SMCR = _BV(SE); + asm("sleep"); + SMCR = 0; +} + +void Blinkencat::next_mode(void) +{ + mode = (Mode)((mode + 1) % MODE_ENUM_MAX); +} + +void Blinkencat::loop(void) +{ + static uint16_t rgbwheel_offset = 0; + static uint16_t rgbfade_hsv = 0; + static uint8_t strobe_on = 0; + + /* + // not working due to bad logic levels + if (gpio.read(GPIO::pb1)) { + // Arduino and WS2812 strip are connected in parallel with the battery, + // which will significantly confuse the charging circuit when the + // strip is active while charging. So we make sure that it isn't. + mode = OFF; + } + */ + + switch (mode) { + case OFF: + // the mode may have been set by an ISR, which may in turn have + // been handled immediately after an np.show() call. So we must + // observe the 300us idle time mandated by WS2812. + _delay_ms(1); + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + np.setPixelColor(i, np.Color(0, 0, 0)); + } + np.show(); + idle(); + break; + case RGBWHEEL_FAST: + case RGBWHEEL_SLOW: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t hsv = (i * 252 + rgbwheel_offset) % 6553; + np.setPixelColor((NUM_PIXELS-1) - i, np.gamma32(np.ColorHSV(hsv * 10, 255, 127))); + } + rgbwheel_offset = (rgbwheel_offset + 10) % 6553; + np.show(); + _delay_ms(1); + if (mode == RGBWHEEL_SLOW) { + _delay_ms(9); + } + break; + case RGBFADE_FAST: + case RGBFADE_SLOW: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + np.setPixelColor(i, np.ColorHSV(rgbfade_hsv * 10, 255, 63)); + } + rgbfade_hsv = (rgbfade_hsv + 10) % 6553; + np.show(); + _delay_ms(1); + if (mode == RGBFADE_SLOW) { + _delay_ms(99); + } + break; + case BRIGHTRGBWHEEL_FAST: + case BRIGHTRGBWHEEL_SLOW: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t hsv = (i * 252 + rgbwheel_offset) % 6553; + np.setPixelColor((NUM_PIXELS-1) - i, np.gamma32(np.ColorHSV(hsv * 10))); + } + rgbwheel_offset = (rgbwheel_offset + 10) % 6553; + np.show(); + _delay_ms(1); + if (mode == BRIGHTRGBWHEEL_SLOW) { + _delay_ms(9); + } + break; + case BRIGHTRGBFADE_FAST: + case BRIGHTRGBFADE_SLOW: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + np.setPixelColor(i, np.ColorHSV(rgbfade_hsv * 10)); + } + rgbfade_hsv = (rgbfade_hsv + 10) % 6553; + np.show(); + _delay_ms(1); + if (mode == BRIGHTRGBFADE_SLOW) { + _delay_ms(99); + } + break; + case COLD_WHITE: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + np.setPixelColor(i, np.Color(127, 127, 127)); + } + np.show(); + idle(); + break; + case STROBE: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + np.setPixelColor(i, np.Color(strobe_on, strobe_on, strobe_on)); + } + np.show(); + strobe_on = 127 - strobe_on; + _delay_ms(40); + break; + case COLOR_STROBE: + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + if (strobe_on) { + np.setPixelColor(i, np.ColorHSV(rgbfade_hsv * 10)); + } else { + np.setPixelColor(i, np.Color(0, 0, 0)); + } + } + rgbfade_hsv = (rgbfade_hsv + 50) % 6553; + np.show(); + strobe_on = 127 - strobe_on; + _delay_ms(40); + break; + } +} + +Blinkencat blinkencat; + +int main(void) +{ + arch.setup(); + gpio.setup(); + kout.setup(); + kin.setup(); + + blinkencat.setup(); + + while (1) { + blinkencat.loop(); + while (kin.hasKey()) { + char key = kin.getKey(); + if ((key >= '0') && (key < '0' + blinkencat.MODE_ENUM_MAX)) { + blinkencat.mode = (Blinkencat::Mode)(key - '0'); + } + } + } + + return 0; +} |