hyperion.ng/assets/firmware/arduino/tpm2/tpm2.ino
redPanther 170ad4f5db improve serial hotplug (#389)
* - disable device when error indecates that the problem is not solvable on reconnect
- introduce a preOpenDelay of 2 seconds (currently value is hardcoded)

* rs232:
- make preOpenDelay available via webui
- fix preOpenDelay
- add basic usb serial detection

* - revert 3819ae7
- fix schema files

* make json checks compat with utf8+bom

* make shutdown effect a bit more flexible
2017-02-09 20:10:57 +01:00

448 lines
12 KiB
C++

#include <pt.h>
#include "FastLED.h"
#define ANALOG_MODE_AVERAGE 0
#define ANALOG_MODE_LAST_LED 1
/*==============================================================================*/
/* LED und Arduino Variablen */
/*==============================================================================*/
#define INITIAL_LED_TEST_ENABLED true
#define INITIAL_LED_TEST_BRIGHTNESS 32 // 0..255
#define INITIAL_LED_TEST_TIME_MS 500 // 0..255
#define MAX_LEDS 400 // Number of LEDs
#define MAX_ARGS 10 // Max Number of command arguments
#define BAUDRATE 460800 // Baudrate
#define SERIAL Serial // Serial port for communication
#define NUM_LEDS_PER_STRIP 20
// type of your led controller, possible values, see below
#define LED_TYPE WS2812B
// 3 wire (pwm): NEOPIXEL BTM1829 TM1812 TM1809 TM1804 TM1803 UCS1903 UCS1903B UCS1904 UCS2903 WS2812 WS2852
// S2812B SK6812 SK6822 APA106 PL9823 WS2811 WS2813 APA104 WS2811_40 GW6205 GW6205_40 LPD1886 LPD1886_8BIT
// 4 wire (spi): LPD8806 WS2801 WS2803 SM16716 P9813 APA102 SK9822 DOTSTAR
// For 3 wire led stripes line Neopixel/Ws2812, which have a data line, ground, and power, you just need to define DATA_PIN.
// For led chipsets that are SPI based (four wires - data, clock, ground, and power), both defines DATA_PIN and CLOCK_PIN are needed
// DATA_PIN, or DATA_PIN, CLOCK_PIN
#define LED_PINS 6 // 3 wire leds
//#define LED_PINS 6, 13 // 4 wire leds
#define COLOR_ORDER GRB // colororder of the stripe, set RGB in hyperion
#define OFF_TIMEOUT 15000 // ms to switch off after no data was received, set 0 to deactivate
// analog rgb uni color led stripe - using of hyperion smoothing is recommended
// ATTENTION this pin config is default for atmega328 based arduinos, others might work to
// if you have flickering analog leds this might be caused by unsynced pwm signals
// try other pins is more or less the only thing that helps
#define ANALOG_OUTPUT_ENABLED false
#define ANALOG_MODE ANALOG_MODE_LAST_LED // use ANALOG_MODE_AVERAGE or ANALOG_MODE_LAST_LED
#define ANALOG_GROUND_PIN 8 // additional ground pin to make wiring a bit easier
#define ANALOG_RED_PIN 9
#define ANALOG_GREEN_PIN 10
#define ANALOG_BLUE_PIN 11
// overall color adjustments
#define ANALOG_BRIGHTNESS_RED 255 // maximum brightness for analog 0-255
#define ANALOG_BRIGHTNESS_GREEN 255 // maximum brightness for analog 0-255
#define ANALOG_BRIGHTNESS_BLUE 255 // maximum brightness for analog 0-255
#define BRIGHTNESS 255 // maximum brightness 0-255
#define DITHER_MODE BINARY_DITHER // BINARY_DITHER or DISABLE_DITHER
#define COLOR_TEMPERATURE CRGB(255,255,255) // RGB value describing the color temperature
#define COLOR_CORRECTION TypicalLEDStrip // predefined fastled color correction
//#define COLOR_CORRECTION CRGB(255,255,255) // or RGB value describing the color correction
// Baudrate, higher rate allows faster refresh rate and more LEDs
//#define serialRate 460800 // use 115200 for ftdi based boards
#define serialRate 115200 // use 115200 for ftdi based boards
//#define serialRate 500000 // use 115200 for ftdi based boards
/*==============================================================================*/
/* TPM2 Variablen */
/*==============================================================================*/
enum Protocol
{
// positions
posStart = 0,
posType = 1,
posFsHigh = 2,
posFsLow = 3,
posData = 4,
// bytes
tpm2Start = 0xc9,
tpm2DataFrame = 0xda,
tpm2Command = 0xc0,
tpm2Answer = 0xaa,
tpm2End = 0x36,
tpm2Ack = 0xAC
};
enum Mode
{
mNone,
mCommunication,
mProgram
};
struct Data
{
int pos;
uint8_t type;
uint16_t fs;
uint16_t maxSize;
uint8_t command;
CRGB rgb[MAX_LEDS];
} data;
byte args[MAX_ARGS];
unsigned long lastDataAt = 0;
int program = 0;
int mode = mNone;
int effectDelay = 100;
static struct pt pt1;
// int freeRam()
// {
// extern int __heap_start, *__brkval;
// int v;
// return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
// }
void setup()
{
SERIAL.begin(BAUDRATE);
delay(1000);
int ledCount = MAX_LEDS;
if (ANALOG_MODE == ANALOG_MODE_LAST_LED) {
ledCount--;
}
memset(data.rgb, 0, sizeof(struct CRGB) * ledCount);
FastLED.addLeds<LED_TYPE, LED_PINS, COLOR_ORDER>(data.rgb, ledCount);
// color adjustments
FastLED.setBrightness ( BRIGHTNESS );
FastLED.setTemperature( COLOR_TEMPERATURE );
FastLED.setCorrection ( COLOR_CORRECTION );
FastLED.setDither ( DITHER_MODE );
#ifdef INITIAL_LED_TEST_ENABLED
for (int v=0;v<INITIAL_LED_TEST_BRIGHTNESS;v++)
{
oneColorAll(v,v,v);
delay(INITIAL_LED_TEST_TIME_MS/2/INITIAL_LED_TEST_BRIGHTNESS);
}
for (int v=0;v<INITIAL_LED_TEST_BRIGHTNESS;v++)
{
oneColorAll(INITIAL_LED_TEST_BRIGHTNESS-v,INITIAL_LED_TEST_BRIGHTNESS-v,INITIAL_LED_TEST_BRIGHTNESS-v);
delay(INITIAL_LED_TEST_TIME_MS/2/INITIAL_LED_TEST_BRIGHTNESS);
}
#define BRIGHT 127 //max led intensity (1-500)
#define INHALE 1250 //Inhalation time in milliseconds.
#define PULSE INHALE*1000/BRIGHT
#define REST 1000 //Rest Between Inhalations.
while(true)
{
//ramp increasing intensity, Inhalation:
for (int i=1;i<BRIGHT;i++){
oneColorAll(i,i,i);
delayMicroseconds(PULSE-i*10); // wait
delay(0); //to prevent watchdog firing.
}
//ramp decreasing intensity, Exhalation (half time):
for (int i=BRIGHT-1;i>0;i--){
oneColorAll(i,i,i);
delayMicroseconds(PULSE-i*10); // wait
i--;
delay(0); //to prevent watchdog firing.
}
delay(REST); //take a rest...
}
#endif
oneColorAll(0,0,0);
memset(args, 0, MAX_ARGS);
resetVars();
PT_INIT(&pt1);
while (!SERIAL) {
; // wait for serial port to connect. Needed for native USB
}
}
/*==============================================================================*/
/* Thread für Programm/Effekte
/*==============================================================================*/
static int playProgramThread(struct pt *pt)
{
static unsigned long timestamp = 0;
PT_BEGIN(pt);
while(1)
{
PT_WAIT_UNTIL(pt, millis() - timestamp > effectDelay);
playProgram();
timestamp = millis();
}
PT_END(pt);
}
/*==============================================================================*/
/* loop
/*==============================================================================*/
void loop()
{
while (1)
{
// if data available switch to communication mode
if (SERIAL.available() > 0)
{
if (mode != mCommunication)
{
mode = mCommunication;
resetVars();
}
doCommunication();
}
else
// communication timeout after 0.5 seconds
while (SERIAL.available() == 0 && millis()-lastDataAt > 1000)
{
if (mode != mProgram)
{
mode = mProgram;
resetVars();
}
else
playProgramThread(&pt1);
}
}
}
/*==============================================================================*/
/* do communication
/*==============================================================================*/
void doCommunication()
{
// read ...
while (SERIAL.available() > 0)
{
byte val = SERIAL.read();
lastDataAt = millis();
if (data.pos == posStart && val == tpm2Start) // Startbyte
resetVars();
else if (data.pos == posType && (val == tpm2DataFrame || val == tpm2Command)) // Block-Art
data.type = val;
else if (data.pos == posFsHigh) // Framesize (High Bit)
{
data.fs = (val << 8) & 0xFF00;
data.maxSize = data.fs;
}
else if (data.pos == posFsLow) // Framesize (Low byte)
{
data.fs += val & 0x00FF;
data.maxSize = data.fs;
if (data.fs > MAX_LEDS*3) // framsize too high
{
data.fs = MAX_LEDS*3;
}
}
else if (data.pos == posData + data.maxSize && val == tpm2End) // End Byte
parsePacket();
else if (data.pos >= posData && data.pos < posData+data.fs) // Bytes zwischen Header und Ende lesen
evaluateData(val);
else if (data.pos >= posData && data.pos < posData+data.maxSize) // Bytes zwischen Header und Ende lesen
continue;
else // protocol violation ...
{
resetVars();
continue;
}
data.pos++;
}
}
/*==============================================================================*/
/* evaluate data
/*==============================================================================*/
void evaluateData(byte val)
{
if (data.type == tpm2DataFrame) // frame data
{
uint8_t* rgb = (uint8_t*)data.rgb;
rgb[data.pos-posData] = val;
}
else // command data
{
if (data.pos == posData)
{
data.command = val;
memset(args, 0, sizeof(args));
}
else
args[data.pos-posData-1] = val;
}
}
/*==============================================================================*/
/* reset variables
/*==============================================================================*/
void resetVars()
{
memset(&data, 0, sizeof(Data));
//data.rgb = (struct CRGB*)FastSPI_LED.getRGBData();
memset(data.rgb, 0, MAX_LEDS * sizeof(struct CRGB));
}
/*==============================================================================*/
/* parse packet
/*==============================================================================*/
void parsePacket()
{
switch (data.type)
{
case tpm2DataFrame:
{
showLeds();
break;
}
case tpm2Command:
{
setProgram();
break;
}
default:
break;
}
SERIAL.write(tpm2Ack);
resetVars();
data.pos = -1;
}
/*==============================================================================*/
/* set LED color
/*==============================================================================*/
void setLedColor(int led, uint8_t r, uint8_t g, uint8_t b)
{
data.rgb[led].r = r;
data.rgb[led].g = g;
data.rgb[led].b = b;
}
/*==============================================================================*/
/* one Color All
/*==============================================================================*/
void oneColorAll(uint8_t r, uint8_t g, uint8_t b)
{
memset(data.rgb, 0, MAX_LEDS * sizeof(struct CRGB));
for (int led = 0; led < MAX_LEDS; led++)
setLedColor(led, r, g, b);
showLeds();
effectDelay = 1000;
}
/*==============================================================================*/
/* Output Leds
/*==============================================================================*/
void showLeds()
{
FastLED.show();
}
void setProgram()
{
program = data.command;
}
void playProgram()
{
switch (program)
{
case 0: oneColorAll(args[0],args[1],args[2]); break;
case 1: rainbow_loop(20); break;
default: oneColorAll(0,0,0); break;
}
}
/* Set LED Color of given LED */
void oneColorAllNOSHOW(int r, int g, int b)
{
resetVars();
for (int led = 0; led < MAX_LEDS; led++)
{
setLedColor(led, r, g, b);
}
}
/*==============================================================================*/
/* Effect 0: Fixed color - Arguments RR GG BB
/*==============================================================================*/
/*==============================================================================*/
/* Effect 1: Loops rainbow colors around the stripe
/*==============================================================================*/
void rainbow_loop(int idelay) { //-LOOP HSV RAINBOW
static double idex = 0;
static double ihue = 0;
double steps = (double)255/MAX_LEDS;
for(int led = 0 ; led < MAX_LEDS; led++ ) {
ihue = led * steps + idex;
if (ihue >= 255)
ihue -= 255;
data.rgb[led] = CHSV((int)ihue, 255, 255);
if (led == 0)
idex += steps;
if (idex >= 255)
idex = 0;
}
showLeds();
effectDelay = idelay;
}