mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Fix WLED & Smoothing (#1567)
* WLED - Fix empty segment element in DB * WLED - Fix to not overwrite on state when not isStayOnAfterStreaming * Refactor ProviderRestApi, increase default timeout * Fix Smoothing - Fix empty updates, consider smoothing configs for effects * UI - Fix not removed priority * Add missing header and code updates * setRedirectPolicy was only introduced in Qt 5.9 * Adalight - Align to HyperSerial v9.0.0 * HyperSerial Hyperion with awa protocol v8.0.0 * Correct line-endings
This commit is contained in:
@@ -0,0 +1,655 @@
|
||||
#include <NeoPixelBus.h>
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////// CONFIG SECTION STARTS /////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define THIS_IS_RGBW // RGBW SK6812, otherwise comment it
|
||||
#define COLD_WHITE // for RGBW (THIS_IS_RGBW enabled) select COLD version, comment it if NEUTRAL
|
||||
|
||||
const bool skipFirstLed = false; // if set the first led in the strip will be set to black (for level shifters using sacrifice LED)
|
||||
const int serialSpeed = 2000000; // serial port speed
|
||||
#define DATA_PIN 2 // PIN: data output for LED strip
|
||||
|
||||
const bool reportStats = false; // Send back processing statistics
|
||||
const int reportStatInterval_s = 10; // Send back processing every interval in seconds
|
||||
|
||||
/* Statistics breakdown:
|
||||
FPS: Updates to the LEDs per second
|
||||
F-FPS: Frames identified per second
|
||||
S: Shown (Done) updates to the LEDs per given interval
|
||||
F: Frames identified per interval (garbled grames cannot be counted)
|
||||
G: Good frames identified per interval
|
||||
B: Total bad frames of all types identified per interval
|
||||
BF: Bad frames identified per interval
|
||||
BS: Skipped incomplete frames
|
||||
BC: Frames failing CRC check per interval
|
||||
BFL Frames failing Fletcher content validation per interval
|
||||
*/
|
||||
|
||||
//Developer configs
|
||||
#define ENABLE_STRIP
|
||||
#define ENABLE_CHECK_FLETCHER
|
||||
|
||||
const int SERIAL_SIZE_RX = 4096;
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
const int serial2Speed = 460800;
|
||||
const bool reportInput = false;
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////// CONFIG SECTION ENDS /////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const String version = "8.0";
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
float whiteLimit = 1.0f;
|
||||
#ifdef COLD_WHITE
|
||||
uint8_t rCorrection = 0xA0; // adjust red -> white in 0-0xFF range
|
||||
uint8_t gCorrection = 0xA0; // adjust green -> white in 0-0xFF range
|
||||
uint8_t bCorrection = 0xA0; // adjust blue -> white in 0-0xFF range
|
||||
#else
|
||||
uint8_t rCorrection = 0xB0; // adjust red -> white in 0-0xFF range
|
||||
uint8_t gCorrection = 0xB0; // adjust green -> white in 0-0xFF range
|
||||
uint8_t bCorrection = 0x70; // adjust blue -> white in 0-0xFF range
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int ledCount = 0; // This is dynamic, don't change it
|
||||
int pixelCount = 0; // This is dynamic, don't change it
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
#define LED_TYPE NeoGrbwFeature
|
||||
#if defined(ARDUINO_LOLIN_S2_MINI)
|
||||
#define LED_METHOD NeoEsp32I2s0Sk6812Method
|
||||
#else
|
||||
#define LED_METHOD NeoEsp32I2s1Sk6812Method
|
||||
#endif
|
||||
#else
|
||||
#define LED_TYPE NeoGrbFeature
|
||||
#if defined(ARDUINO_LOLIN_S2_MINI)
|
||||
#define LED_METHOD NeoEsp32I2s0Ws2812xMethod
|
||||
#else
|
||||
#define LED_METHOD NeoEsp32I2s1Ws2812xMethod
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LED_DRIVER NeoPixelBus<LED_TYPE, LED_METHOD>
|
||||
|
||||
uint8_t* ledBuffer;
|
||||
int ledBufferSize;
|
||||
|
||||
#ifdef ENABLE_STRIP
|
||||
LED_DRIVER* strip = NULL;
|
||||
#endif
|
||||
|
||||
enum class AwaProtocol
|
||||
{
|
||||
HEADER_A,
|
||||
HEADER_w,
|
||||
HEADER_a,
|
||||
HEADER_HI,
|
||||
HEADER_LO,
|
||||
HEADER_CRC,
|
||||
CHANNELCALIB_GAIN,
|
||||
CHANNELCALIB_RED,
|
||||
CHANNELCALIB_GREEN,
|
||||
CHANNELCALIB_BLUE,
|
||||
PIXEL,
|
||||
FLETCHER1,
|
||||
FLETCHER2,
|
||||
FLETCHER_EXT
|
||||
};
|
||||
|
||||
AwaProtocol state = AwaProtocol::HEADER_A;
|
||||
|
||||
const int headerSize = 6;
|
||||
const int trailerSize = 3;
|
||||
const int calibInfoSize = 4;
|
||||
int bytesRead = 0;
|
||||
|
||||
bool isVersion2 = false;
|
||||
bool isChannelCalib = false;
|
||||
uint8_t CRC = 0;
|
||||
int count = 0;
|
||||
int currentPixel = 0;
|
||||
uint16_t fletcher1 = 0;
|
||||
uint16_t fletcher2 = 0;
|
||||
uint16_t fletcherExt = 0;
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
RgbwColor inputColor;
|
||||
uint8_t wChannel[256];
|
||||
uint8_t rChannel[256];
|
||||
uint8_t gChannel[256];
|
||||
uint8_t bChannel[256];
|
||||
#else
|
||||
RgbColor inputColor;
|
||||
#endif
|
||||
|
||||
bool ledsComplete = false;
|
||||
|
||||
// statistics
|
||||
const int reportStatInterval_ms = reportStatInterval_s * 1000;
|
||||
unsigned long curTime;
|
||||
unsigned long stat_start = 0;
|
||||
uint16_t stat_shown = 0;
|
||||
uint16_t stat_frames = 0;
|
||||
uint16_t stat_good = 0;
|
||||
uint16_t stat_bad = 0;
|
||||
|
||||
uint16_t stat_bad_frame = 0;
|
||||
uint16_t stat_bad_skip = 0;
|
||||
uint16_t stat_bad_crc = 0;
|
||||
uint16_t stat_bad_fletcher = 0;
|
||||
|
||||
uint16_t stat_final_shown = 0;
|
||||
uint16_t stat_final_frames = 0;
|
||||
uint16_t stat_final_good = 0;
|
||||
uint16_t stat_final_bad = 0;
|
||||
|
||||
uint16_t stat_final_bad_frame = 0;
|
||||
uint16_t stat_final_bad_skip = 0;
|
||||
uint16_t stat_final_bad_crc = 0;
|
||||
uint16_t stat_final_bad_fletcher = 0;
|
||||
|
||||
//Debugging
|
||||
String inputString;
|
||||
String inputErrorString;
|
||||
String debugString;
|
||||
|
||||
void printStringHex(String string)
|
||||
{
|
||||
#ifndef ENABLE_STRIP
|
||||
Serial2.println(string.length());
|
||||
for (int i = 0; i < string.length(); ++i)
|
||||
{
|
||||
if (i % 36 == 0)
|
||||
{
|
||||
Serial2.println();
|
||||
Serial2.print("[");
|
||||
Serial2.print(i);
|
||||
Serial2.print("] ");
|
||||
}
|
||||
|
||||
if (string[i] < 16)
|
||||
Serial2.print("0");
|
||||
Serial2.print(string[i], HEX);
|
||||
Serial2.print(":");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void showMe()
|
||||
{
|
||||
#ifdef ENABLE_STRIP
|
||||
if (strip != NULL && strip->CanShow())
|
||||
{
|
||||
stat_shown++;
|
||||
strip->Show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// statistics
|
||||
inline void showStats()
|
||||
{
|
||||
if (reportStats)
|
||||
{
|
||||
if (stat_frames > 0)
|
||||
{
|
||||
stat_final_shown = stat_shown;
|
||||
stat_final_frames = stat_frames;
|
||||
stat_final_good = stat_good;
|
||||
stat_final_bad = stat_bad;
|
||||
|
||||
stat_final_bad_frame = stat_bad_frame;
|
||||
stat_final_bad_skip = stat_bad_skip;
|
||||
stat_final_bad_crc = stat_bad_crc;
|
||||
stat_final_bad_fletcher = stat_bad_fletcher;
|
||||
}
|
||||
|
||||
stat_start = curTime;
|
||||
stat_shown = 0;
|
||||
stat_frames = 0;
|
||||
stat_good = 0;
|
||||
stat_bad = 0;
|
||||
|
||||
stat_bad_frame = 0;
|
||||
stat_bad_skip = 0;
|
||||
stat_bad_crc = 0;
|
||||
stat_bad_fletcher = 0;
|
||||
|
||||
String summary = String("FPS: ") + (stat_final_shown / reportStatInterval_s) +
|
||||
" F-FPS: " + (stat_final_frames / reportStatInterval_s) +
|
||||
" S: " + stat_final_shown +
|
||||
" F: " + stat_final_frames +
|
||||
" G: " + stat_final_good +
|
||||
" B: " + stat_final_bad +
|
||||
" (BF: " + stat_final_bad_frame +
|
||||
" BS: " + stat_final_bad_skip +
|
||||
" BC: " + stat_final_bad_crc +
|
||||
" BFL: " + stat_final_bad_fletcher +
|
||||
")";
|
||||
#ifdef ENABLE_STRIP
|
||||
Serial.println(summary);
|
||||
#else
|
||||
Serial2.println(summary);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InitLeds(uint16_t ledCount, int pixelCount, bool channelCalibration = false)
|
||||
{
|
||||
if (ledBuffer != NULL)
|
||||
delete ledBuffer;
|
||||
|
||||
ledBufferSize = pixelCount + (channelCalibration ? calibInfoSize : 0);
|
||||
ledBuffer = new uint8_t[ledBufferSize];
|
||||
|
||||
#ifdef ENABLE_STRIP
|
||||
if (strip != NULL)
|
||||
delete strip;
|
||||
|
||||
strip = new LED_DRIVER(ledCount, DATA_PIN);
|
||||
strip->Begin();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void processSerialData()
|
||||
{
|
||||
while (Serial.available()) {
|
||||
|
||||
char input = Serial.read();
|
||||
++bytesRead;
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
if (reportInput)
|
||||
inputString += input;
|
||||
#endif
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AwaProtocol::HEADER_A:
|
||||
if (input == 'A')
|
||||
{
|
||||
state = AwaProtocol::HEADER_w;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_w:
|
||||
if (input == 'w')
|
||||
state = AwaProtocol::HEADER_a;
|
||||
else
|
||||
{
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_a:
|
||||
if (input == 'a')
|
||||
{
|
||||
isVersion2 = false;
|
||||
state = AwaProtocol::HEADER_HI;
|
||||
}
|
||||
else if (input == 'A')
|
||||
{
|
||||
state = AwaProtocol::HEADER_HI;
|
||||
isVersion2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_HI:
|
||||
|
||||
stat_frames++;
|
||||
|
||||
count = input << 8;
|
||||
|
||||
CRC = input;
|
||||
fletcher1 = 0;
|
||||
fletcher2 = 0;
|
||||
fletcherExt = 0;
|
||||
state = AwaProtocol::HEADER_LO;
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_LO:
|
||||
count += input + 1;
|
||||
|
||||
if (ledCount != count || isChannelCalib != isVersion2)
|
||||
{
|
||||
ledCount = count;
|
||||
isChannelCalib = isVersion2;
|
||||
pixelCount = ledCount * 3;
|
||||
|
||||
if (isChannelCalib)
|
||||
prepareCalibration();
|
||||
|
||||
InitLeds(ledCount, pixelCount, isChannelCalib);
|
||||
}
|
||||
|
||||
CRC = CRC ^ input ^ 0x55;
|
||||
|
||||
state = AwaProtocol::HEADER_CRC;
|
||||
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_CRC:
|
||||
|
||||
// Check, if incomplete package information was skipped, set bytesread to headersize and skip wrong input
|
||||
if (bytesRead != headerSize)
|
||||
{
|
||||
stat_bad_skip++;
|
||||
bytesRead = headerSize;
|
||||
}
|
||||
|
||||
currentPixel = 0;
|
||||
if (CRC == input)
|
||||
{
|
||||
state = AwaProtocol::PIXEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// CRC failure
|
||||
stat_bad++;
|
||||
stat_bad_crc++;
|
||||
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::PIXEL:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
if (currentPixel == pixelCount)
|
||||
{
|
||||
if (isChannelCalib)
|
||||
state = AwaProtocol::CHANNELCALIB_GAIN;
|
||||
else
|
||||
state = AwaProtocol::FLETCHER1;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_GAIN:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
state = AwaProtocol::CHANNELCALIB_RED;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_RED:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::CHANNELCALIB_GREEN;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_GREEN:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::CHANNELCALIB_BLUE;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_BLUE:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER1;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER1:
|
||||
fletcher1 = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER2;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER2:
|
||||
fletcher2 = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER_EXT;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER_EXT:
|
||||
fletcherExt = input;
|
||||
ledsComplete = true;
|
||||
|
||||
state = AwaProtocol::HEADER_A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Init serial port
|
||||
int bufSize = Serial.setRxBufferSize(SERIAL_SIZE_RX);
|
||||
Serial.begin(serialSpeed);
|
||||
Serial.setTimeout(50);
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
Serial2.begin(serial2Speed);
|
||||
|
||||
Serial2.println();
|
||||
Serial2.println("Welcome!");
|
||||
Serial2.println("Hyperion Awa driver " + version);
|
||||
Serial2.println("!!! Debug Output !!!");
|
||||
#endif
|
||||
|
||||
// Display config
|
||||
Serial.println();
|
||||
Serial.println("Welcome!");
|
||||
Serial.println("Hyperion Awa driver " + version);
|
||||
Serial.print("(Build: ");
|
||||
Serial.print(__DATE__);
|
||||
Serial.print(" ");
|
||||
Serial.print(__TIME__);
|
||||
Serial.println(")");
|
||||
|
||||
// first LED info
|
||||
if (skipFirstLed)
|
||||
Serial.println("First LED: disabled");
|
||||
else
|
||||
Serial.println("First LED: enabled");
|
||||
|
||||
// RGBW claibration info
|
||||
#ifdef THIS_IS_RGBW
|
||||
#ifdef COLD_WHITE
|
||||
Serial.println("Default color mode: RGBW cold");
|
||||
#else
|
||||
Serial.println("Default color mode: RGBW neutral");
|
||||
#endif
|
||||
prepareCalibration();
|
||||
#else
|
||||
Serial.println("Color mode: RGB");
|
||||
#endif
|
||||
|
||||
InitLeds(ledCount, pixelCount);
|
||||
}
|
||||
|
||||
void prepareCalibration()
|
||||
{
|
||||
#ifdef THIS_IS_RGBW
|
||||
// prepare LUT calibration table, cold white is much better than "neutral" white
|
||||
for (uint32_t i = 0; i < 256; i++)
|
||||
{
|
||||
// color calibration
|
||||
float red = rCorrection * i; // adjust red
|
||||
float green = gCorrection * i; // adjust green
|
||||
float blue = bCorrection * i; // adjust blue
|
||||
|
||||
wChannel[i] = (uint8_t)round(min(whiteLimit * i, 255.0f));
|
||||
rChannel[i] = (uint8_t)round(min(red / 0xFF, 255.0f));
|
||||
gChannel[i] = (uint8_t)round(min(green / 0xFF, 255.0f));
|
||||
bChannel[i] = (uint8_t)round(min(blue / 0xFF, 255.0f));
|
||||
}
|
||||
|
||||
Serial.write("RGBW calibration. White limit(%): ");
|
||||
Serial.print(whiteLimit * 100.0f);
|
||||
Serial.write(" %, red: ");
|
||||
Serial.print(rCorrection);
|
||||
Serial.write(" , green: ");
|
||||
Serial.print(gCorrection);
|
||||
Serial.write(" , blue: ");
|
||||
Serial.print(bCorrection);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
curTime = millis();
|
||||
|
||||
#ifdef __AVR__
|
||||
// nothing , USART Interrupt is implemented
|
||||
ESPserialEvent();
|
||||
#else
|
||||
// ESP8266 polling
|
||||
ESPserialEvent();
|
||||
#endif
|
||||
|
||||
if (ledsComplete)
|
||||
{
|
||||
#ifndef ENABLE_STRIP
|
||||
if (reportInput)
|
||||
{
|
||||
Serial2.println();
|
||||
Serial2.print("<input> L: ");
|
||||
printStringHex(inputString);
|
||||
Serial2.println("<\input>");
|
||||
inputString = "";
|
||||
|
||||
Serial2.print("bytesRead: ");
|
||||
Serial2.print(bytesRead);
|
||||
Serial2.print(" , currentPixel: ");
|
||||
Serial2.print(currentPixel);
|
||||
Serial2.print(" ,pixelCount: ");
|
||||
Serial2.print(pixelCount);
|
||||
Serial2.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
int frameSize = headerSize + ledBufferSize + trailerSize;
|
||||
|
||||
if (bytesRead > frameSize)
|
||||
{
|
||||
//Add number of frames ignored on top of frame
|
||||
int frames = bytesRead / frameSize;
|
||||
stat_frames += frames;
|
||||
|
||||
//Count frame plus frames ignored as bad frames
|
||||
int badFrames = frames + 1;
|
||||
stat_bad += badFrames;
|
||||
stat_bad_frame += badFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#ifdef ENABLE_CHECK_FLETCHER
|
||||
//Test if content is valid
|
||||
uint16_t item = 0;
|
||||
uint16_t fletch1 = 0;
|
||||
uint16_t fletch2 = 0;
|
||||
uint16_t fletchExt = 0;
|
||||
|
||||
while (item < ledBufferSize)
|
||||
{
|
||||
fletch1 = (fletch1 + (uint16_t)ledBuffer[item]) % 255;
|
||||
fletch2 = (fletch2 + fletch1) % 255;
|
||||
fletcherExt = (fletcherExt + ((uint16_t)ledBuffer[item] ^ (item))) % 255;
|
||||
++item;
|
||||
}
|
||||
if ((fletch1 == fletcher1) && (fletch2 == fletcher2) && (ledBuffer[item-1] == (fletcherExt != 0x41) ? fletcherExt : 0xaa))
|
||||
{
|
||||
#endif
|
||||
stat_good++;
|
||||
|
||||
uint16_t startLed = 0;
|
||||
if (skipFirstLed)
|
||||
{
|
||||
#ifdef ENABLE_STRIP
|
||||
#ifdef THIS_IS_RGBW
|
||||
strip->SetPixelColor(startLed, RgbwColor(0, 0, 0, 0));
|
||||
#else
|
||||
strip->SetPixelColor(startLed, RgbColor(0, 0, 0));
|
||||
#endif
|
||||
#endif
|
||||
startLed = 1;
|
||||
}
|
||||
|
||||
for (uint16_t led = startLed; led < ledCount; ++led)
|
||||
{
|
||||
inputColor.R = ledBuffer[led * 3];
|
||||
inputColor.G = ledBuffer[led * 3 + 1];
|
||||
inputColor.B = ledBuffer[led * 3 + 2];
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
inputColor.W = min(rChannel[inputColor.R],
|
||||
min(gChannel[inputColor.G],
|
||||
bChannel[inputColor.B]));
|
||||
inputColor.R -= rChannel[inputColor.W];
|
||||
inputColor.G -= gChannel[inputColor.W];
|
||||
inputColor.B -= bChannel[inputColor.W];
|
||||
inputColor.W = wChannel[inputColor.W];
|
||||
#endif
|
||||
#ifdef ENABLE_STRIP
|
||||
strip->SetPixelColor(led, inputColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
showMe();
|
||||
yield();
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
if (isChannelCalib)
|
||||
{
|
||||
uint8_t incoming_gain = ledBuffer[pixelCount];
|
||||
uint8_t incoming_red = ledBuffer[pixelCount + 1];
|
||||
uint8_t incoming_green = ledBuffer[pixelCount + 2];
|
||||
uint8_t incoming_blue = ledBuffer[pixelCount + 3];
|
||||
|
||||
float final_limit = (incoming_gain != 255) ? incoming_gain / 255.0f : 1.0f;
|
||||
if (rCorrection != incoming_red || gCorrection != incoming_green || bCorrection != incoming_blue || whiteLimit != final_limit)
|
||||
{
|
||||
rCorrection = incoming_red;
|
||||
gCorrection = incoming_green;
|
||||
bCorrection = incoming_blue;
|
||||
whiteLimit = final_limit;
|
||||
prepareCalibration();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CHECK_FLETCHER
|
||||
}
|
||||
else
|
||||
{
|
||||
stat_bad++;
|
||||
stat_bad_fletcher++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bytesRead = 0;
|
||||
state = AwaProtocol::HEADER_A;
|
||||
|
||||
ledsComplete = false;
|
||||
}
|
||||
|
||||
if ((curTime - stat_start > reportStatInterval_ms))
|
||||
{
|
||||
if (stat_frames > 0)
|
||||
{
|
||||
showStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AVR__
|
||||
void serialEvent()
|
||||
{
|
||||
processSerialData();
|
||||
}
|
||||
#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
void ESPserialEvent()
|
||||
{
|
||||
processSerialData();
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,646 @@
|
||||
#include <NeoPixelBus.h>
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////// CONFIG SECTION STARTS /////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define THIS_IS_RGBW // RGBW SK6812, otherwise comment it
|
||||
#define COLD_WHITE // for RGBW (THIS_IS_RGBW enabled) select COLD version, comment it if NEUTRAL
|
||||
|
||||
const bool skipFirstLed = false; // if set the first led in the strip will be set to black (for level shifters using sacrifice LED)
|
||||
const int serialSpeed = 2000000; // serial port speed
|
||||
|
||||
const bool reportStats = false; // Send back processing statistics
|
||||
const int reportStatInterval_s = 10; // Send back processing every interval in seconds
|
||||
|
||||
/* Statistics breakdown:
|
||||
FPS: Updates to the LEDs per second
|
||||
F-FPS: Frames identified per second
|
||||
S: Shown (Done) updates to the LEDs per given interval
|
||||
F: Frames identified per interval (garbled grames cannot be counted)
|
||||
G: Good frames identified per interval
|
||||
B: Total bad frames of all types identified per interval
|
||||
BF: Bad frames identified per interval
|
||||
BS: Skipped incomplete frames
|
||||
BC: Frames failing CRC check per interval
|
||||
BFL Frames failing Fletcher content validation per interval
|
||||
*/
|
||||
|
||||
//Developer configs
|
||||
#define ENABLE_STRIP
|
||||
#define ENABLE_CHECK_FLETCHER
|
||||
|
||||
const int SERIAL_SIZE_RX = 4096;
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
const int serial2Speed = 460800;
|
||||
const bool reportInput = false;
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////// CONFIG SECTION ENDS /////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const String version = "8.0";
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
float whiteLimit = 1.0f;
|
||||
#ifdef COLD_WHITE
|
||||
uint8_t rCorrection = 0xA0; // adjust red -> white in 0-0xFF range
|
||||
uint8_t gCorrection = 0xA0; // adjust green -> white in 0-0xFF range
|
||||
uint8_t bCorrection = 0xA0; // adjust blue -> white in 0-0xFF range
|
||||
#else
|
||||
uint8_t rCorrection = 0xB0; // adjust red -> white in 0-0xFF range
|
||||
uint8_t gCorrection = 0xB0; // adjust green -> white in 0-0xFF range
|
||||
uint8_t bCorrection = 0x70; // adjust blue -> white in 0-0xFF range
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int ledCount = 0; // This is dynamic, don't change it
|
||||
int pixelCount = 0; // This is dynamic, don't change it
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
#define LED_TYPE NeoGrbwFeature
|
||||
#define LED_METHOD NeoEsp8266Uart1Sk6812Method
|
||||
#else
|
||||
#define LED_TYPE NeoGrbFeature
|
||||
#define LED_METHOD NeoEsp8266Uart1Ws2812xMethod
|
||||
#endif
|
||||
|
||||
#define LED_DRIVER NeoPixelBus<LED_TYPE, LED_METHOD>
|
||||
|
||||
uint8_t* ledBuffer;
|
||||
int ledBufferSize;
|
||||
|
||||
#ifdef ENABLE_STRIP
|
||||
LED_DRIVER* strip = NULL;
|
||||
#endif
|
||||
|
||||
enum class AwaProtocol
|
||||
{
|
||||
HEADER_A,
|
||||
HEADER_w,
|
||||
HEADER_a,
|
||||
HEADER_HI,
|
||||
HEADER_LO,
|
||||
HEADER_CRC,
|
||||
CHANNELCALIB_GAIN,
|
||||
CHANNELCALIB_RED,
|
||||
CHANNELCALIB_GREEN,
|
||||
CHANNELCALIB_BLUE,
|
||||
PIXEL,
|
||||
FLETCHER1,
|
||||
FLETCHER2,
|
||||
FLETCHER_EXT
|
||||
};
|
||||
|
||||
AwaProtocol state = AwaProtocol::HEADER_A;
|
||||
|
||||
const int headerSize = 6;
|
||||
const int trailerSize = 3;
|
||||
const int calibInfoSize = 4;
|
||||
int bytesRead = 0;
|
||||
|
||||
bool isVersion2 = false;
|
||||
bool isChannelCalib = false;
|
||||
uint8_t CRC = 0;
|
||||
int count = 0;
|
||||
int currentPixel = 0;
|
||||
uint16_t fletcher1 = 0;
|
||||
uint16_t fletcher2 = 0;
|
||||
uint16_t fletcherExt = 0;
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
RgbwColor inputColor;
|
||||
uint8_t wChannel[256];
|
||||
uint8_t rChannel[256];
|
||||
uint8_t gChannel[256];
|
||||
uint8_t bChannel[256];
|
||||
#else
|
||||
RgbColor inputColor;
|
||||
#endif
|
||||
|
||||
bool ledsComplete = false;
|
||||
|
||||
// statistics
|
||||
const int reportStatInterval_ms = reportStatInterval_s * 1000;
|
||||
unsigned long curTime;
|
||||
unsigned long stat_start = 0;
|
||||
uint16_t stat_shown = 0;
|
||||
uint16_t stat_frames = 0;
|
||||
uint16_t stat_good = 0;
|
||||
uint16_t stat_bad = 0;
|
||||
|
||||
uint16_t stat_bad_frame = 0;
|
||||
uint16_t stat_bad_skip = 0;
|
||||
uint16_t stat_bad_crc = 0;
|
||||
uint16_t stat_bad_fletcher = 0;
|
||||
|
||||
uint16_t stat_final_shown = 0;
|
||||
uint16_t stat_final_frames = 0;
|
||||
uint16_t stat_final_good = 0;
|
||||
uint16_t stat_final_bad = 0;
|
||||
|
||||
uint16_t stat_final_bad_frame = 0;
|
||||
uint16_t stat_final_bad_skip = 0;
|
||||
uint16_t stat_final_bad_crc = 0;
|
||||
uint16_t stat_final_bad_fletcher = 0;
|
||||
|
||||
//Debugging
|
||||
String inputString;
|
||||
String inputErrorString;
|
||||
String debugString;
|
||||
|
||||
void printStringHex(String string)
|
||||
{
|
||||
#ifndef ENABLE_STRIP
|
||||
Serial2.println(string.length());
|
||||
for (int i = 0; i < string.length(); ++i)
|
||||
{
|
||||
if (i % 36 == 0)
|
||||
{
|
||||
Serial2.println();
|
||||
Serial2.print("[");
|
||||
Serial2.print(i);
|
||||
Serial2.print("] ");
|
||||
}
|
||||
|
||||
if (string[i] < 16)
|
||||
Serial2.print("0");
|
||||
Serial2.print(string[i], HEX);
|
||||
Serial2.print(":");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void showMe()
|
||||
{
|
||||
#ifdef ENABLE_STRIP
|
||||
if (strip != NULL && strip->CanShow())
|
||||
{
|
||||
stat_shown++;
|
||||
strip->Show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// statistics
|
||||
inline void showStats()
|
||||
{
|
||||
if (reportStats)
|
||||
{
|
||||
if (stat_frames > 0)
|
||||
{
|
||||
stat_final_shown = stat_shown;
|
||||
stat_final_frames = stat_frames;
|
||||
stat_final_good = stat_good;
|
||||
stat_final_bad = stat_bad;
|
||||
|
||||
stat_final_bad_frame = stat_bad_frame;
|
||||
stat_final_bad_skip = stat_bad_skip;
|
||||
stat_final_bad_crc = stat_bad_crc;
|
||||
stat_final_bad_fletcher = stat_bad_fletcher;
|
||||
}
|
||||
|
||||
stat_start = curTime;
|
||||
stat_shown = 0;
|
||||
stat_frames = 0;
|
||||
stat_good = 0;
|
||||
stat_bad = 0;
|
||||
|
||||
stat_bad_frame = 0;
|
||||
stat_bad_skip = 0;
|
||||
stat_bad_crc = 0;
|
||||
stat_bad_fletcher = 0;
|
||||
|
||||
String summary = String("FPS: ") + (stat_final_shown / reportStatInterval_s) +
|
||||
" F-FPS: " + (stat_final_frames / reportStatInterval_s) +
|
||||
" S: " + stat_final_shown +
|
||||
" F: " + stat_final_frames +
|
||||
" G: " + stat_final_good +
|
||||
" B: " + stat_final_bad +
|
||||
" (BF: " + stat_final_bad_frame +
|
||||
" BS: " + stat_final_bad_skip +
|
||||
" BC: " + stat_final_bad_crc +
|
||||
" BFL: " + stat_final_bad_fletcher +
|
||||
")";
|
||||
#ifdef ENABLE_STRIP
|
||||
Serial.println(summary);
|
||||
#else
|
||||
Serial2.println(summary);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InitLeds(uint16_t ledCount, int pixelCount, bool channelCalibration = false)
|
||||
{
|
||||
if (ledBuffer != NULL)
|
||||
delete ledBuffer;
|
||||
|
||||
ledBufferSize = pixelCount + (channelCalibration ? calibInfoSize : 0);
|
||||
ledBuffer = new uint8_t[ledBufferSize];
|
||||
|
||||
#ifdef ENABLE_STRIP
|
||||
if (strip != NULL)
|
||||
delete strip;
|
||||
|
||||
strip = new LED_DRIVER(ledCount);
|
||||
strip->Begin();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void processSerialData()
|
||||
{
|
||||
while (Serial.available()) {
|
||||
|
||||
char input = Serial.read();
|
||||
++bytesRead;
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
if (reportInput)
|
||||
inputString += input;
|
||||
#endif
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AwaProtocol::HEADER_A:
|
||||
if (input == 'A')
|
||||
{
|
||||
state = AwaProtocol::HEADER_w;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_w:
|
||||
if (input == 'w')
|
||||
state = AwaProtocol::HEADER_a;
|
||||
else
|
||||
{
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_a:
|
||||
if (input == 'a')
|
||||
{
|
||||
isVersion2 = false;
|
||||
state = AwaProtocol::HEADER_HI;
|
||||
}
|
||||
else if (input == 'A')
|
||||
{
|
||||
state = AwaProtocol::HEADER_HI;
|
||||
isVersion2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_HI:
|
||||
|
||||
stat_frames++;
|
||||
|
||||
count = input << 8;
|
||||
|
||||
CRC = input;
|
||||
fletcher1 = 0;
|
||||
fletcher2 = 0;
|
||||
fletcherExt = 0;
|
||||
state = AwaProtocol::HEADER_LO;
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_LO:
|
||||
count += input + 1;
|
||||
|
||||
if (ledCount != count || isChannelCalib != isVersion2)
|
||||
{
|
||||
ledCount = count;
|
||||
isChannelCalib = isVersion2;
|
||||
pixelCount = ledCount * 3;
|
||||
|
||||
if (isChannelCalib)
|
||||
prepareCalibration();
|
||||
|
||||
InitLeds(ledCount, pixelCount, isChannelCalib);
|
||||
}
|
||||
|
||||
CRC = CRC ^ input ^ 0x55;
|
||||
|
||||
state = AwaProtocol::HEADER_CRC;
|
||||
|
||||
break;
|
||||
|
||||
case AwaProtocol::HEADER_CRC:
|
||||
|
||||
// Check, if incomplete package information was skipped, set bytesread to headersize and skip wrong input
|
||||
if (bytesRead != headerSize)
|
||||
{
|
||||
stat_bad_skip++;
|
||||
bytesRead = headerSize;
|
||||
}
|
||||
|
||||
currentPixel = 0;
|
||||
if (CRC == input)
|
||||
{
|
||||
state = AwaProtocol::PIXEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// CRC failure
|
||||
stat_bad++;
|
||||
stat_bad_crc++;
|
||||
|
||||
state = AwaProtocol::HEADER_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::PIXEL:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
if (currentPixel == pixelCount)
|
||||
{
|
||||
if (isChannelCalib)
|
||||
state = AwaProtocol::CHANNELCALIB_GAIN;
|
||||
else
|
||||
state = AwaProtocol::FLETCHER1;
|
||||
}
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_GAIN:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
state = AwaProtocol::CHANNELCALIB_RED;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_RED:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::CHANNELCALIB_GREEN;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_GREEN:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::CHANNELCALIB_BLUE;
|
||||
break;
|
||||
|
||||
case AwaProtocol::CHANNELCALIB_BLUE:
|
||||
ledBuffer[currentPixel++] = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER1;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER1:
|
||||
fletcher1 = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER2;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER2:
|
||||
fletcher2 = input;
|
||||
|
||||
state = AwaProtocol::FLETCHER_EXT;
|
||||
break;
|
||||
|
||||
case AwaProtocol::FLETCHER_EXT:
|
||||
fletcherExt = input;
|
||||
ledsComplete = true;
|
||||
|
||||
state = AwaProtocol::HEADER_A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Init serial port
|
||||
int bufSize = Serial.setRxBufferSize(SERIAL_SIZE_RX);
|
||||
Serial.begin(serialSpeed);
|
||||
Serial.setTimeout(50);
|
||||
|
||||
#ifndef ENABLE_STRIP
|
||||
Serial2.begin(serial2Speed);
|
||||
|
||||
Serial2.println();
|
||||
Serial2.println("Welcome!");
|
||||
Serial2.println("Hyperion Awa driver " + version);
|
||||
Serial2.println("!!! Debug Output !!!");
|
||||
#endif
|
||||
|
||||
// Display config
|
||||
Serial.println();
|
||||
Serial.println("Welcome!");
|
||||
Serial.println("Hyperion Awa driver " + version);
|
||||
Serial.print("(Build: ");
|
||||
Serial.print(__DATE__);
|
||||
Serial.print(" ");
|
||||
Serial.print(__TIME__);
|
||||
Serial.println(")");
|
||||
|
||||
// first LED info
|
||||
if (skipFirstLed)
|
||||
Serial.println("First LED: disabled");
|
||||
else
|
||||
Serial.println("First LED: enabled");
|
||||
|
||||
// RGBW claibration info
|
||||
#ifdef THIS_IS_RGBW
|
||||
#ifdef COLD_WHITE
|
||||
Serial.println("Default color mode: RGBW cold");
|
||||
#else
|
||||
Serial.println("Default color mode: RGBW neutral");
|
||||
#endif
|
||||
prepareCalibration();
|
||||
#else
|
||||
Serial.println("Color mode: RGB");
|
||||
#endif
|
||||
|
||||
InitLeds(ledCount, pixelCount);
|
||||
}
|
||||
|
||||
void prepareCalibration()
|
||||
{
|
||||
#ifdef THIS_IS_RGBW
|
||||
// prepare LUT calibration table, cold white is much better than "neutral" white
|
||||
for (uint32_t i = 0; i < 256; i++)
|
||||
{
|
||||
// color calibration
|
||||
float red = rCorrection * i; // adjust red
|
||||
float green = gCorrection * i; // adjust green
|
||||
float blue = bCorrection * i; // adjust blue
|
||||
|
||||
wChannel[i] = (uint8_t)round(min(whiteLimit * i, 255.0f));
|
||||
rChannel[i] = (uint8_t)round(min(red / 0xFF, 255.0f));
|
||||
gChannel[i] = (uint8_t)round(min(green / 0xFF, 255.0f));
|
||||
bChannel[i] = (uint8_t)round(min(blue / 0xFF, 255.0f));
|
||||
}
|
||||
|
||||
Serial.write("RGBW calibration. White limit(%): ");
|
||||
Serial.print(whiteLimit * 100.0f);
|
||||
Serial.write(" %, red: ");
|
||||
Serial.print(rCorrection);
|
||||
Serial.write(" , green: ");
|
||||
Serial.print(gCorrection);
|
||||
Serial.write(" , blue: ");
|
||||
Serial.print(bCorrection);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
curTime = millis();
|
||||
|
||||
#ifdef __AVR__
|
||||
// nothing , USART Interrupt is implemented
|
||||
ESPserialEvent();
|
||||
#else
|
||||
// ESP8266 polling
|
||||
ESPserialEvent();
|
||||
#endif
|
||||
|
||||
if (ledsComplete)
|
||||
{
|
||||
#ifndef ENABLE_STRIP
|
||||
if (reportInput)
|
||||
{
|
||||
Serial2.println();
|
||||
Serial2.print("<input> L: ");
|
||||
printStringHex(inputString);
|
||||
Serial2.println("<\input>");
|
||||
inputString = "";
|
||||
|
||||
Serial2.print("bytesRead: ");
|
||||
Serial2.print(bytesRead);
|
||||
Serial2.print(" , currentPixel: ");
|
||||
Serial2.print(currentPixel);
|
||||
Serial2.print(" ,pixelCount: ");
|
||||
Serial2.print(pixelCount);
|
||||
Serial2.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
int frameSize = headerSize + ledBufferSize + trailerSize;
|
||||
|
||||
if (bytesRead > frameSize)
|
||||
{
|
||||
//Add number of frames ignored on top of frame
|
||||
int frames = bytesRead / frameSize;
|
||||
stat_frames += frames;
|
||||
|
||||
//Count frame plus frames ignored as bad frames
|
||||
int badFrames = frames + 1;
|
||||
stat_bad += badFrames;
|
||||
stat_bad_frame += badFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#ifdef ENABLE_CHECK_FLETCHER
|
||||
//Test if content is valid
|
||||
uint16_t item = 0;
|
||||
uint16_t fletch1 = 0;
|
||||
uint16_t fletch2 = 0;
|
||||
uint16_t fletchExt = 0;
|
||||
|
||||
while (item < ledBufferSize)
|
||||
{
|
||||
fletch1 = (fletch1 + (uint16_t)ledBuffer[item]) % 255;
|
||||
fletch2 = (fletch2 + fletch1) % 255;
|
||||
fletcherExt = (fletcherExt + ((uint16_t)ledBuffer[item] ^ (item))) % 255;
|
||||
++item;
|
||||
}
|
||||
if ((fletch1 == fletcher1) && (fletch2 == fletcher2) && (ledBuffer[item-1] == (fletcherExt != 0x41) ? fletcherExt : 0xaa))
|
||||
{
|
||||
#endif
|
||||
stat_good++;
|
||||
|
||||
uint16_t startLed = 0;
|
||||
if (skipFirstLed)
|
||||
{
|
||||
#ifdef ENABLE_STRIP
|
||||
#ifdef THIS_IS_RGBW
|
||||
strip->SetPixelColor(startLed, RgbwColor(0, 0, 0, 0));
|
||||
#else
|
||||
strip->SetPixelColor(startLed, RgbColor(0, 0, 0));
|
||||
#endif
|
||||
#endif
|
||||
startLed = 1;
|
||||
}
|
||||
|
||||
for (uint16_t led = startLed; led < ledCount; ++led)
|
||||
{
|
||||
inputColor.R = ledBuffer[led * 3];
|
||||
inputColor.G = ledBuffer[led * 3 + 1];
|
||||
inputColor.B = ledBuffer[led * 3 + 2];
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
inputColor.W = min(rChannel[inputColor.R],
|
||||
min(gChannel[inputColor.G],
|
||||
bChannel[inputColor.B]));
|
||||
inputColor.R -= rChannel[inputColor.W];
|
||||
inputColor.G -= gChannel[inputColor.W];
|
||||
inputColor.B -= bChannel[inputColor.W];
|
||||
inputColor.W = wChannel[inputColor.W];
|
||||
#endif
|
||||
#ifdef ENABLE_STRIP
|
||||
strip->SetPixelColor(led, inputColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
showMe();
|
||||
yield();
|
||||
|
||||
#ifdef THIS_IS_RGBW
|
||||
if (isChannelCalib)
|
||||
{
|
||||
uint8_t incoming_gain = ledBuffer[pixelCount];
|
||||
uint8_t incoming_red = ledBuffer[pixelCount + 1];
|
||||
uint8_t incoming_green = ledBuffer[pixelCount + 2];
|
||||
uint8_t incoming_blue = ledBuffer[pixelCount + 3];
|
||||
|
||||
float final_limit = (incoming_gain != 255) ? incoming_gain / 255.0f : 1.0f;
|
||||
if (rCorrection != incoming_red || gCorrection != incoming_green || bCorrection != incoming_blue || whiteLimit != final_limit)
|
||||
{
|
||||
rCorrection = incoming_red;
|
||||
gCorrection = incoming_green;
|
||||
bCorrection = incoming_blue;
|
||||
whiteLimit = final_limit;
|
||||
prepareCalibration();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CHECK_FLETCHER
|
||||
}
|
||||
else
|
||||
{
|
||||
stat_bad++;
|
||||
stat_bad_fletcher++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bytesRead = 0;
|
||||
state = AwaProtocol::HEADER_A;
|
||||
|
||||
ledsComplete = false;
|
||||
}
|
||||
|
||||
if ((curTime - stat_start > reportStatInterval_ms))
|
||||
{
|
||||
if (stat_frames > 0)
|
||||
{
|
||||
showStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AVR__
|
||||
void serialEvent()
|
||||
{
|
||||
processSerialData();
|
||||
}
|
||||
#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
void ESPserialEvent()
|
||||
{
|
||||
processSerialData();
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user