strip-controller-esp8266/src/main.cpp

285 lines
6.3 KiB
C++

#include <FastLED.h>
#include "main.h"
#define WS2812B_PIN 14
#define LED_DATA_PIN 13 // D7 // Hardware-MOSI
#define LED_CLOCK_PIN 14 // D5 // Hardware-CLK
#define STATUS_LED_PIN 16
#define FIRMWARE_VERSION_MAJOR 1
#define FIRMWARE_VERSION_MINOR 3
#define MAX_LED_COUNT 10000
CRGB* leds;
uint16_t led_count;
uint8_t blink_mode = 0;
unsigned long blink_timer_ts;
unsigned long blink_mode_timeout_timer_ts;
unsigned long last_data_at = 0;
bool connected = false;
void setup() {
//Serial.setRxBufferSize(1);
Serial.begin(9600);
//send_ack();
//Serial.println("Online!");
led_count = 256;
leds = new CRGB[256];
//FastLED.addLeds<WS2812B, WS2812B_PIN, GRB>(leds, 256);
FastLED.addLeds<APA102, LED_DATA_PIN, LED_CLOCK_PIN, RGB, DATA_RATE_MHZ(1)>(leds, 256);
FastLED[0].setLeds(leds, 256);
pinMode(STATUS_LED_PIN, OUTPUT);
set_blink(0);
blink_timer_ts = blink_mode_timeout_timer_ts = millis();
/* fill(CRGB::DarkRed);
delay(250);
fill(CRGB::DarkGreen);
delay(250);
fill(CRGB::DarkBlue);
delay(250); */
fill(CRGB::Black);
// CLear the receive buffer
while (Serial.available()) { Serial.read(); }
}
void loop() {
if (connected && last_data_at + 1000 < millis()) connected=false;
byte cmd;
if (Serial.available()) {
cmd = Serial.read();
switch(cmd) {
case 'L': cmd_length(); break;
case 'F': cmd_fill(); break;
case 'R': cmd_receive(); break;
case 'O': cmd_output(); break;
case 'C': cmd_clear(); break;
case 'V': cmd_version(); break;
case 'M': cmd_get_max(); break;
case 'r': cmd_random_color(); break;
case 't': cmd_test(); break;
case '?': cmd_help(); break;
case 0: if (!connected) {
connected = true;
send_ack();
}
break;
default: send_nack(); break;
}
set_blink(1);
last_data_at = millis();
}
blink();
}
void set_blink(uint8_t mode) {
blink_mode = mode;
blink_mode_timeout_timer_ts = millis();
}
void blink() {
unsigned long now = millis();
unsigned long blink_timer = now - blink_timer_ts;
unsigned long blink_mode_timeout_timer = now - blink_mode_timeout_timer_ts;
switch(blink_mode) {
case 0: // active until first command is received
if(blink_timer < 1500) {
status_led_on();
} else if(blink_timer < 1600) {
status_led_off();
} else {
blink_timer_ts = now;
status_led_on();
}
break;
case 1: // active after receiving a command - ends after 500ms
/*if(blink_timer > 30) {
blink_timer_ts = now;
status_led_toggle();
}
if(blink_mode_timeout_timer > 500) {
set_blink(2);
}
break;
case 2: // waiting for commands
if (blink_timer < 1500) {
status_led_off();
} else if (blink_timer < 1600) {
status_led_on();
} else if (blink_timer < 1700) {
status_led_off();
} else if (blink_timer < 1800) {
status_led_on();
} else {
blink_timer_ts = now;
status_led_off();
}*/
status_led_toggle();
set_blink(2);
break;
case 2: // do nothing
break;
default: // should newer be reached
if (blink_timer > 1000) {
status_led_toggle();
blink_timer_ts = now;
}
break;
}
}
void fill(CRGB color) {
for (int i=0; i<led_count; i++) {
leds[i] = color;
}
FastLED.show();
}
void cmd_output() {
FastLED.show();
send_ack();
}
void cmd_fill() {
uint16_t first_led = receive_word();
uint16_t cmd_leds = receive_word();
CRGB color = receive_color();
if (first_led <= led_count && cmd_leds>0 && first_led + cmd_leds <= led_count) {
uint16_t end_led = first_led + cmd_leds;
for(uint16_t i=first_led; i<end_led; i++) {
leds[i] = color;
}
send_ack();
} else {
send_nack();
}
}
void cmd_receive() {
uint16_t first_led = receive_word();
uint16_t cmd_leds = receive_word();
if (first_led <= led_count && cmd_leds>0 && first_led + cmd_leds <= led_count) {
uint16_t end_led = first_led + cmd_leds;
for(uint16_t i=first_led; i<end_led; i++) {
leds[i] = receive_color();
}
send_ack();
} else {
send_nack();
}
}
void cmd_length() {
uint16_t new_len = receive_word();
if (new_len>0 && new_len<=MAX_LED_COUNT) {
delete leds;
leds = new CRGB[new_len];
led_count = new_len;
FastLED[0].setLeds(leds, led_count);
send_ack();
} else {
send_nack();
}
}
void cmd_clear() {
for(uint16_t i=0; i<led_count; i++) {
leds[i] = CRGB::Black;
}
send_ack();
}
void cmd_version() {
send(FIRMWARE_VERSION_MAJOR);
send(FIRMWARE_VERSION_MINOR);
send_ack();
}
void cmd_get_max() {
Serial.write(MAX_LED_COUNT >> 8);
send((byte)(MAX_LED_COUNT & 0xFF));
send_ack();
}
void cmd_random_color() {
for (int i=0; i<led_count; i++) {
leds[i] = CRGB(random8(), random8(), random8());
}
FastLED.show();
send_ack();
}
void cmd_test() {
for (int i=0; i<led_count; i++) {
leds[i] = CRGB::Red;
}
FastLED.show();
send_ack();
}
void cmd_help() {
Serial.println("L <length> Set new LED strip length.");
Serial.println("F <start> <count> <color> Fills the given part with color.");
Serial.println("R <start> <count> <color>[] Sets colors for the fiven area.");
Serial.println("O Shows the set colors on the strip.");
Serial.println("C Sets all LEDs to black.");
Serial.println("V Returns the firmware version as two bytes.");
Serial.println("M Returns the maximum number of LEDs.");
Serial.println("r Sets all LEDs to random colors.");
Serial.println("t Sets the whole strip to red.");
Serial.println("? Displays this help.");
send_ack();
}
void send_ack() {
send('A');
}
void send_nack() {
send('N');
}
void send(byte data) {
Serial.write(data);
//Serial.write(0x00);
Serial.flush();
}
uint8_t receive_byte() {
/*byte buffer;
Serial.setTimeout(5);
size_t count = Serial.readBytes(&buffer, 1);
if (count==1) return buffer;
else return 0;*/
while (!Serial.available()) {}
return Serial.read();
}
uint16_t receive_word() {
return (receive_byte() << 8) | receive_byte();
}
CRGB receive_color() {
return CRGB(receive_byte(), receive_byte(), receive_byte());
}
void status_led_on() {
digitalWrite(STATUS_LED_PIN, LOW);
}
void status_led_off() {
digitalWrite(STATUS_LED_PIN, HIGH);
}
void status_led_toggle() {
digitalWrite(STATUS_LED_PIN, !digitalRead(STATUS_LED_PIN));
}