update adalight sketch (#299)

* rename platform rpi-pwm to rpi. remove original rpi platform
install symlink to bin folder
create effects folder for custom effects

* fix osx jobs evaluation

* - add rewrite time to serial leds
- rework adalight sketch

* add analog output

* adalight: add analog mode: last led

* tune adalight sketch to final state
move refresh code to leddevice base class, so every leddevice can use it
This commit is contained in:
redPanther 2016-11-29 23:14:15 +01:00 committed by GitHub
parent 6b3f0e42b5
commit 81dea1583d
12 changed files with 297 additions and 120 deletions

View File

@ -1,117 +1,239 @@
#include "FastLED.h"
// How many leds in your strip?
#define NUM_LEDS 240
#define ANALOG_MODE_AVERAGE 0
#define ANALOG_MODE_LAST_LED 1
// For led chips like Neopixels, 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), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 6
/**************************************
S E T U P
set following values to your needs
**************************************/
// Number of leds in your strip. set to 1 and ANALOG_OUTPUT_ENABLED to true to activate analog only
#define NUM_LEDS 100
#define SPI_LEDS false // connection type. Set "true" for 4 wire and "false" for 3 Wire stripes.
#define LED_TYPE WS2812B // type of your led controller, possible values, see below
// 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
#define DATA_PIN 6
#define CLOCK_PIN 13
#define COLOR_ORDER RGB
#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 true
#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 CRGB(255,255,255) // RGB value describing the color correction
// Baudrate, higher rate allows faster refresh rate and more LEDs (defined in /etc/boblight.conf)
#define serialRate 460800 // use 115200 for ftdi based boards
/**************************************
A D A L I G H T C O D E
no user changes needed
**************************************/
// Adalight sends a "Magic Word" (defined in /etc/boblight.conf) before sending the pixel data
uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i;
// Baudrate, higher rate allows faster refresh rate and more LEDs (defined in /etc/boblight.conf)
#define serialRate 460800
unsigned long endTime;
// Define the array of leds
CRGB leds[NUM_LEDS];
void setup() {
// Uncomment/edit one of the following lines for your leds arrangement.
// FastLED.addLeds<NEOPIXEL , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<BTM1829 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<TM1812 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<TM1809 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<TM1804 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<TM1803 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<UCS1903 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<UCS1903B , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<UCS1904 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<UCS2903 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2812 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2852 , DATA_PIN, RGB>(leds, NUM_LEDS);
FastLED.addLeds<WS2812B , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<SK6812 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<SK6822 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<APA106 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<PL9823 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2811 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2813 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<APA104 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2811_40 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<GW6205 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<GW6205_40 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<LPD1886 , DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<LPD1886_8BIT, DATA_PIN, RGB>(leds, NUM_LEDS);
// set rgb to analog led stripe
void showAnalogRGB(const CRGB& led) {
if (ANALOG_OUTPUT_ENABLED) {
byte r = map(led.r, 0,255,0,ANALOG_BRIGHTNESS_RED);
byte g = map(led.g, 0,255,0,ANALOG_BRIGHTNESS_GREEN);
byte b = map(led.b, 0,255,0,ANALOG_BRIGHTNESS_BLUE);
analogWrite(ANALOG_RED_PIN , r);
analogWrite(ANALOG_GREEN_PIN, g);
analogWrite(ANALOG_BLUE_PIN , b);
}
}
// FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2801 , DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<WS2803 , DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<P9813 , DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<APA102 , DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<SK9822 , DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
// set color to all leds
void showColor(const CRGB& led) {
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
LEDS.showColor(led);
#endif
showAnalogRGB(led);
}
// switch of digital and analog leds
void switchOff() {
#if ANALOG_ONLY == false
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
FastLED.show();
#endif
showAnalogRGB(leds[0]);
}
// function to check if serial data is available
// if timeout occured leds switch of, if configured
bool checkIncommingData() {
boolean dataAvailable = true;
while (!Serial.available()) {
if ( OFF_TIMEOUT > 0 && endTime < millis()) {
switchOff();
dataAvailable = false;
endTime = millis() + OFF_TIMEOUT;
}
}
return dataAvailable;
}
// main function that setups and runs the code
void setup() {
// additional ground pin to make wiring a bit easier
pinMode(ANALOG_GROUND_PIN, OUTPUT);
digitalWrite(ANALOG_GROUND_PIN, LOW);
// analog output
if (ANALOG_OUTPUT_ENABLED) {
pinMode(ANALOG_BLUE_PIN , OUTPUT);
pinMode(ANALOG_RED_PIN , OUTPUT);
pinMode(ANALOG_GREEN_PIN, OUTPUT);
}
// Uncomment/edit one of the following lines for your leds arrangement.
int ledCount = NUM_LEDS;
if (ANALOG_MODE == ANALOG_MODE_LAST_LED) {
ledCount--;
}
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
#if SPI_LEDS == true
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, COLOR_ORDER>(leds, ledCount);
#else
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, ledCount);
#endif
#endif
// color adjustments
FastLED.setBrightness ( BRIGHTNESS );
FastLED.setTemperature( COLOR_TEMPERATURE );
FastLED.setCorrection ( COLOR_CORRECTION );
FastLED.setDither ( DITHER_MODE );
// initial RGB flash
LEDS.showColor(CRGB(255, 0, 0));
delay(250);
LEDS.showColor(CRGB(0, 255, 0));
delay(250);
LEDS.showColor(CRGB(0, 0, 255));
delay(250);
LEDS.showColor(CRGB(0, 0, 0));
showColor(CRGB(255, 0, 0)); delay(400);
showColor(CRGB(0, 255, 0)); delay(400);
showColor(CRGB(0, 0, 255)); delay(400);
showColor(CRGB(0, 0, 0));
Serial.begin(serialRate);
Serial.print("Ada\n"); // Send "Magic Word" string to host
}
boolean transmissionSuccess;
unsigned long sum_r, sum_g, sum_b;
// loop() is avoided as even that small bit of function overhead
// has a measurable impact on this code's overall throughput.
while (true) {
// wait for first byte of Magic Word
for (i = 0; i < sizeof prefix; ++i) {
// If next byte is not in Magic Word, the start over
if (!checkIncommingData() || prefix[i] != Serial.read()) {
i = 0;
}
}
// Hi, Lo, Checksum
if (!checkIncommingData()) continue;
hi = Serial.read();
if (!checkIncommingData()) continue;
lo = Serial.read();
if (!checkIncommingData()) continue;
chk = Serial.read();
// if checksum does not match go back to wait
if (chk != (hi ^ lo ^ 0x55)) continue;
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
transmissionSuccess = true;
sum_r = 0;
sum_g = 0;
sum_b = 0;
// read the transmission data and set LED values
for (uint8_t idx = 0; idx < NUM_LEDS; idx++) {
byte r, g, b;
if (!checkIncommingData()) {
transmissionSuccess = false;
break;
}
r = Serial.read();
if (!checkIncommingData()) {
transmissionSuccess = false;
break;
}
g = Serial.read();
if (!checkIncommingData()) {
transmissionSuccess = false;
break;
}
b = Serial.read();
leds[idx].r = r;
leds[idx].g = g;
leds[idx].b = b;
#if ANALOG_OUTPUT_ENABLED == true && ANALOG_MODE == ANALOG_MODE_AVERAGE
sum_r += r;
sum_g += g;
sum_b += b;
#endif
}
// shows new values
if (transmissionSuccess) {
endTime = millis() + OFF_TIMEOUT;
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
FastLED.show();
#endif
#if ANALOG_OUTPUT_ENABLED == true
#if ANALOG_MODE == ANALOG_MODE_LAST_LED
showAnalogRGB(leds[NUM_LEDS-1]);
#else
showAnalogRGB(CRGB(sum_r/NUM_LEDS, sum_g/NUM_LEDS, sum_b/NUM_LEDS));
#endif
#endif
}
}
} // end of setup
void loop() {
// wait for first byte of Magic Word
for (i = 0; i < sizeof prefix; ++i) {
waitLoop: while (!Serial.available()) ;;
// Check next byte in Magic Word
if (prefix[i] == Serial.read()) continue;
// otherwise, start over
i = 0;
goto waitLoop;
}
// Hi, Lo, Checksum
while (!Serial.available()) ;;
hi = Serial.read();
while (!Serial.available()) ;;
lo = Serial.read();
while (!Serial.available()) ;;
chk = Serial.read();
// if checksum does not match go back to wait
if (chk != (hi ^ lo ^ 0x55))
{
i = 0;
goto waitLoop;
}
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
// read the transmission data and set LED values
for (uint8_t i = 0; i < NUM_LEDS; i++) {
byte r, g, b;
while (!Serial.available());
r = Serial.read();
while (!Serial.available());
g = Serial.read();
while (!Serial.available());
b = Serial.read();
leds[i].r = r;
leds[i].g = g;
leds[i].b = b;
}
// shows new values
FastLED.show();
// Not used. See note in setup() function.
}

View File

@ -12,6 +12,8 @@
#include <map>
#include <algorithm>
#include <QTimer>
// Utility includes
#include <utils/ColorRgb.h>
#include <utils/ColorRgbw.h>
@ -81,4 +83,15 @@ protected:
static int _ledCount;
static int _ledRGBCount;
static int _ledRGBWCount;
/// Timer object which makes sure that led data is written at a minimum rate
/// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds
QTimer _refresh_timer;
protected slots:
/// Write the last data to the leds again
int rewriteLeds();
private:
std::vector<ColorRgb> _ledValues;
};

View File

@ -17,9 +17,14 @@ LedDevice::LedDevice()
, _log(Logger::getInstance("LedDevice"))
, _ledBuffer(0)
, _deviceReady(true)
, _refresh_timer()
{
LedDevice::getLedDeviceSchemas();
// setup timer
_refresh_timer.setSingleShot(false);
_refresh_timer.setInterval(0);
connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
}
// dummy implemention
@ -103,7 +108,17 @@ QJsonObject LedDevice::getLedDeviceSchemas()
int LedDevice::setLedValues(const std::vector<ColorRgb>& ledValues)
{
return _deviceReady ? write(ledValues) : -1;
if (!_deviceReady)
return -1;
_ledValues = ledValues;
// restart the timer
if (_refresh_timer.interval() > 0)
{
_refresh_timer.start();
}
return write(ledValues);
}
int LedDevice::switchOff()
@ -118,3 +133,8 @@ void LedDevice::setLedCount(int ledCount)
_ledRGBCount = _ledCount * sizeof(ColorRgb);
_ledRGBWCount = _ledCount * sizeof(ColorRgbw);
}
int LedDevice::rewriteLeds()
{
return write(_ledValues);
}

View File

@ -2,7 +2,6 @@
LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_deviceReady = init(deviceConfig);
}

View File

@ -17,16 +17,7 @@ ProviderRs232::ProviderRs232()
, _bytesWritten(0)
, _frameDropCounter(0)
, _lastError(QSerialPort::NoError)
, _timer()
{
// setup timer
_timer.setSingleShot(false);
_timer.setInterval(1000);
connect(&_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
// start the timer
_timer.start();
connect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
connect(&_rs232Port, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
connect(&_rs232Port, SIGNAL(readyRead()), this, SLOT(readyRead()));
@ -38,7 +29,7 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
_deviceName = deviceConfig["output"].toString().toStdString();
_baudRate_Hz = deviceConfig["rate"].toInt();
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(250);
_timer.setInterval ( deviceConfig["rewriteTime"].toInt(5000) );
_refresh_timer.setInterval( deviceConfig["rewriteTime"].toInt(5000) );
return true;
}
@ -157,8 +148,6 @@ bool ProviderRs232::tryOpen(const int delayAfterConnect_ms)
int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
{
// restart the timer
_timer.start();
if (! _blockedForDelay)
{
if (!_rs232Port.isOpen())

View File

@ -46,15 +46,12 @@ protected:
* @param[in[ size The length of the data
* @param[in] data The data
*
* @return Zero on succes else negative
* @return Zero on success else negative
*/
int writeBytes(const qint64 size, const uint8_t *data);
void closeDevice();
/// The RS232 serial-device
QSerialPort _rs232Port;
private slots:
/// Write the last data to the leds again
int rewriteLeds();
@ -79,7 +76,7 @@ protected:
int _delayAfterConnect_ms;
/// The RS232 serial-device
// QSerialPort _rs232Port;
QSerialPort _rs232Port;
bool _blockedForDelay;
@ -89,9 +86,4 @@ protected:
qint64 _bytesWritten;
qint64 _frameDropCounter;
QSerialPort::SerialPortError _lastError;
/// Timer object which makes sure that led data is written at a minimum rate
/// e.g. Adalight device will switch off when it does not receive data at least
/// every 15 seconds
QTimer _timer;
};

View File

@ -19,6 +19,13 @@
"default": 250,
"append" : "ms",
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true

View File

@ -19,6 +19,13 @@
"default": 250,
"append" : "ms",
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true

View File

@ -19,6 +19,13 @@
"default": 250,
"append" : "ms",
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true

View File

@ -23,6 +23,13 @@
"title":"Delay after connect",
"default": 250,
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true

View File

@ -18,6 +18,13 @@
"title":"Delay after connect",
"default": 250,
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true

View File

@ -18,6 +18,13 @@
"title":"Delay after connect",
"default": 250,
"propertyOrder" : 3
},
"rewriteTime": {
"type": "integer",
"title":"refresh time",
"default": 5000,
"append" : "ms",
"propertyOrder" : 4
}
},
"additionalProperties": true