Skip to content

Instantly share code, notes, and snippets.

/stairlight.ino Secret

Created January 14, 2017 21:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/5128e70bc37dadba7d57267268ae5ede to your computer and use it in GitHub Desktop.
Save anonymous/5128e70bc37dadba7d57267268ae5ede to your computer and use it in GitHub Desktop.
Stairlight
#include <LiquidCrystal.h>
#include <IRremote.h>
#include <I2C.h>
#include <FAB_LED.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <avr/wdt.h> //watchdog
#define RTC_ADDRESS 0x68 // I2C address of the RTC module
#define RTC_SECONDS 0x00
#define RTC_MINS 0x01
#define RTC_HOURS 0x02
#define RTC_DAY 0x03
#define RTC_DATE 0x04
#define RTC_MONTH 0x05
#define RTC_YEAR 0x06
#define RTC_CONTROL 0x07
#define numPixels 300
#define maxWBrightness 100 //gamma off, white color
#define default_resolution 3
#define anim_speed 20 //anim speed is the default offset at 60 fps
ws2812b<D, 7> ledstrip;
#define GREEN(x,i) x[i]
#define RED(x,i) x[i+1]
#define BLUE(x,i) x[i+2]
IRrecv irreceiver(10);
decode_results results;
LiquidCrystal lcd(13, 11, 5, 4, 12, 2);
byte upDownChar[8] = {
0b00100,
0b01110,
0b11011,
0b00000,
0b00000,
0b11011,
0b01110,
0b00100
};
byte leftChar[8] = {
0b00010,
0b00110,
0b01100,
0b11000,
0b11000,
0b01100,
0b00110,
0b00010
};
byte rightChar[8] = {
0b01000,
0b01100,
0b00110,
0b00011,
0b00011,
0b00110,
0b01100,
0b01000
};
byte upChar[8] = {
0b00100,
0b01110,
0b01110,
0b11011,
0b11011,
0b10001,
0b00000,
0b00000
};
byte downChar[8] = {
0b00000,
0b00000,
0b10001,
0b11011,
0b11011,
0b01110,
0b01110,
0b00100
};
extern const uint8_t gamma[], dim_curve[];
unsigned long x = 0, frame;
int16_t fps = 0, cps = 0, L1max, L1min, L2max, L2min, L1switch, L1offset, L2switch, L2offset, hue;
int16_t report, position, kelvin, maxKelvin, minKelvin;
uint16_t menu, clockSeconds, slideshow, current_time, evening_time, morning_time;
byte light = 50, Bmax = 100, Bmin = 20, mode, repeat, lcd_brightness = 20, lcd_maxBrightness;
byte resolution = default_resolution, maxGBrightness;
byte colorSample[6] = {}, rtc[13] = {}, evening[4] = {}, morning[4] = {};
int8_t timeout, default_timeout = 30;
boolean button, auto_light, auto_dim, standby_light, white, show, gamma_correction, flashing;
boolean lcd_update, lcd_light, trigger1, trigger2, PIR1, PIR2, RTC = true, inMenu = false, night_mode;
volatile bool second = false;
byte buffer1[numPixels * 3] = {};
void rtcSignal()
{
second = true;
}
void initRTC(bool power)
{
byte temp = 255;
I2c.read(RTC_ADDRESS, RTC_SECONDS, 1);
if (power == true) temp = I2c.receive() & 0b01111111; //power on
else temp = I2c.receive() | 0b10000000; //power off
I2c.write(RTC_ADDRESS, RTC_SECONDS, temp);
I2c.read(RTC_ADDRESS, RTC_HOURS, 1);
temp = I2c.receive() & 0b00111111;
I2c.write(RTC_ADDRESS, RTC_HOURS, temp); //set 24 hour format
I2c.write(RTC_ADDRESS, RTC_CONTROL, 0b00010000); //1 hz interrupts
}
/*byte decToBcd(byte val) {
return ((val / 10 * 16) + (val % 10));
}*/
byte bcdToDec(byte val1, byte val2) {
val1 = val1 << 4 | val2;
return ((val1 / 16 * 10) + (val1 % 16));
}
void setRTC()
{
byte rawData[7] = {};
for (byte i = 0, n = 0; i < 7; i++) {
if (i == 3) rawData[i++] = rtc[n++];
else {
rawData[i] = rtc[n++] | (rtc[n++] << 4);
}
}
I2c.write(RTC_ADDRESS, RTC_SECONDS, rawData, 7);
}
void readRTC()
{
byte rawData[7] = {};
I2c.read(RTC_ADDRESS, RTC_SECONDS, 7, rawData);
for (byte i = 0, n = 0; i < 7; i++) {
if (i == 3) rtc[n++] = rawData[i++];
else {
rtc[n++] = rawData[i] & 0b00001111;
rtc[n++] = rawData[i] >> 4;
}
}
}
void larsonScanner(unsigned long offset, uint16_t firstLed, uint16_t pixels, uint16_t resolution, byte r, byte g, byte b) {
byte temp;
offset /= 5;
pixels--;
if (offset > (pixels * 2)) offset %= (pixels * 2);
if (offset > pixels) offset = pixels * 2 - offset;
pixels++;
int T_high = offset + resolution, T_low = offset - resolution;
for (int i = firstLed, n; i < pixels; i++) {
n = i * 3;
if (i < T_low) temp = 0;
if (i > T_high) temp = 0;
if (i == T_low || i == T_high) temp = 65;
if (i == (T_low + 1) || i == (T_high - 1)) temp = 160;
if (i > (T_low + 1) && i < (T_high - 1)) temp = 255;
RED(buffer1, n) = r * temp / 255;
GREEN(buffer1, n) = g * temp / 255;
BLUE(buffer1, n) = b * temp / 255;
}
}
void lightWipe(boolean state, bool direction, int pos, byte r, byte g, byte b) {
byte temp;
if (state && direction) {
for (int i = 0, n; i < numPixels; i++) {
n = i * 3;
if (i < pos) temp = 255;
if (i == pos) temp = 223;
if (i == pos + 1) temp = 191;
if (i == pos + 2) temp = 159;
if (i == pos + 3) temp = 127;
if (i == pos + 4) temp = 95;
if (i == pos + 5) temp = 63;
if (i == pos + 6) temp = 31;
if (i > pos + 6) temp = 0;
RED(buffer1, n) = r * temp / 255;
GREEN(buffer1, n) = g * temp / 255;
BLUE(buffer1, n) = b * temp / 255;
}
}
if (!state && direction) {
for (int i = 0, n; i < numPixels; i++) {
n = i * 3;
if (i < pos) temp = 0;
if (i == pos) temp = 31;
if (i == pos + 1) temp = 63;
if (i == pos + 2) temp = 95;
if (i == pos + 3) temp = 127;
if (i == pos + 4) temp = 159;
if (i == pos + 5) temp = 191;
if (i == pos + 6) temp = 223;
if (i > pos + 6) temp = 255;
RED(buffer1, n) = r * temp / 255;
GREEN(buffer1, n) = g * temp / 255;
BLUE(buffer1, n) = b * temp / 255;
}
}
if (state && !direction) {
for (int i = numPixels - 1, n; i >= 0; i--) {
n = i * 3;
if (i < pos) temp = 0;
if (i == pos) temp = 31;
if (i == pos + 1) temp = 63;
if (i == pos + 2) temp = 95;
if (i == pos + 3) temp = 127;
if (i == pos + 4) temp = 159;
if (i == pos + 5) temp = 191;
if (i == pos + 6) temp = 223;
if (i > pos + 6) temp = 255;
RED(buffer1, n) = r * temp / 255;
GREEN(buffer1, n) = g * temp / 255;
BLUE(buffer1, n) = b * temp / 255;
}
}
if (!state && !direction) {
for (int i = numPixels - 1, n; i >= 0; i--) {
n = i * 3;
if (i < pos) temp = 255;
if (i == pos) temp = 223;
if (i == pos + 1) temp = 191;
if (i == pos + 2) temp = 159;
if (i == pos + 3) temp = 127;
if (i == pos + 4) temp = 95;
if (i == pos + 5) temp = 63;
if (i == pos + 6) temp = 31;
if (i > pos + 6) temp = 0;
RED(buffer1, n) = r * temp / 255;
GREEN(buffer1, n) = g * temp / 255;
BLUE(buffer1, n) = b * temp / 255;
}
}
}
void getRGB(int hue, int sat, int val) {
/* convert hue, saturation and brightness ( HSB/HSV ) to RGB
The dim_curve is used only on brightness/value and on saturation (inverted).
This looks the most natural.
*/
val = pgm_read_byte(&dim_curve[val]);
if (! white) val *= 1.33;
if (gamma_correction) val = pgm_read_byte(&gamma[val]);
sat = 255 - pgm_read_byte(&dim_curve[255 - sat]);
int r;
int g;
int b;
int base;
if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
colorSample[0] = val;
colorSample[1] = val;
colorSample[2] = val;
}
else {
base = ((255 - sat) * val) >> 8;
switch (hue / 60) {
case 0:
r = val;
g = (((val - base) * hue) / 60) + base;
b = base;
break;
case 1:
r = (((val - base) * (60 - (hue % 60))) / 60) + base;
g = val;
b = base;
break;
case 2:
r = base;
g = val;
b = (((val - base) * (hue % 60)) / 60) + base;
break;
case 3:
r = base;
g = (((val - base) * (60 - (hue % 60))) / 60) + base;
b = val;
break;
case 4:
r = (((val - base) * (hue % 60)) / 60) + base;
g = base;
b = val;
break;
case 5:
r = val;
g = base;
b = (((val - base) * (60 - (hue % 60))) / 60) + base;
break;
}
RED(colorSample, 0) = r;
GREEN(colorSample, 0) = g;
BLUE(colorSample, 0) = b;
}
}
void lightAdjustment(byte light, bool gam) {
if (light != 255) {
if (gam) light = pgm_read_byte(&gamma[light]);
for (int i = 3; i < 6; i++) colorSample[i] = colorSample[i] * light / 255;
}
}
void getColorTemp(int colorTemp) {
/* Start with a temperature, in Kelvin, somewhere between 1000 and 40000. (Other values may work,
but I can't make any promises about the quality of the algorithm's estimates above 40000 K.)
Note also that the temperature and color variables need to be declared as floating-point.
colorTemp = desired temp / 100.
*/
colorTemp /= 100;
if (colorTemp <= 66) RED(colorSample, 3) = 255;
else {
RED(colorSample, 3) = (float)329.698727446 * pow((colorTemp - 60), -0.1332047592);
RED(colorSample, 3) = constrain(RED(colorSample, 3), 0, 255);
}
if (colorTemp <= 66) GREEN(colorSample, 3) = (float)99.4708025861 * log(colorTemp) - 161.1195681661;
else GREEN(colorSample, 3) = (float)288.1221695283 * pow((colorTemp - 60), -0.0755148492);
GREEN(colorSample, 3) = constrain(GREEN(colorSample, 3), 0, 255);
if (colorTemp >= 66) BLUE(colorSample, 3) = 255;
else {
if (colorTemp <= 19) BLUE(colorSample, 3) = 0;
else BLUE(colorSample, 3) = (float)138.5177312231 * log(colorTemp - 10) - 305.0447927307;
BLUE(colorSample, 3) = constrain(BLUE(colorSample, 3), 0, 255);
}
}
void menuHandler(byte button) {
static byte temp;
if (inMenu) {
lcd_update = true;
switch (button) {
case 15:
switch (menu) {
case 51:
menu = 52;
break;
case 52:
L1switch = analogRead(A0);
break;
case 53:
menu = 54;
break;
case 54:
L2switch = analogRead(A1);
break;
case 56:
L1max = 0;
L1min = 1023;
L2max = 0;
L2min = 1023 ;
EEPROM.put(0, L1max);
EEPROM.put(2, L1min);
EEPROM.put(10, L2max);
EEPROM.put(12, L2min);
menu = 57;
break;
default:
goto select;
break;
}
break;
case 14:
if (menu >= 20 && menu < 30) menu = 11;
else if (menu < 20) {
menu = 1;
inMenu = false;
}
if (menu >= 40 && menu < 50) menu = 12;
if (menu == 60 || menu == 61) menu = 13;
if (menu >= 70 && menu < 80) menu = 14;
if (menu > 80 && menu <= 86) {
menu--;
break;
}
if (menu > 90 && menu <= 94) {
menu--;
break;
}
if (menu > 100 && menu <= 104) {
menu--;
break;
}
switch (menu) {
case 30:
menu = 20;
EEPROM.put(4, Bmax);
break;
case 31:
menu = 21;
EEPROM.put(5, Bmin);
break;
case 32:
menu = 22;
EEPROM.put(6, standby_light);
break;
case 33:
menu = 23;
EEPROM.put(7, default_timeout);
break;
case 34:
menu = 24;
EEPROM.put(8, white);
break;
case 35:
menu = 25;
EEPROM.put(9, gamma_correction);
break;
case 50:
EEPROM.put(33, auto_light);
menu = 40;
break;
case 51:
menu = 41;
break;
case 52:
menu = 41;
EEPROM.put(14, L1switch);
break;
case 53:
menu = 42;
break;
case 54:
menu = 42;
EEPROM.put(16, L2switch);
break;
case 55:
EEPROM.put(34, auto_dim);
menu = 43;
break;
case 56:
menu = 44;
break;
case 57:
menu = 44;
break;
case 64:
menu = 60;
EEPROM.put(18, lcd_light);
break;
case 63:
menu = 61;
EEPROM.put(19, lcd_maxBrightness);
break;
case 80:
setRTC();
menu = 70;
break;
case 90:
EEPROM.put(20, evening);
menu = 71;
break;
case 100:
EEPROM.put(24, morning);
menu = 72;
break;
case 110:
EEPROM.put(28, night_mode);
menu = 26;
break;
case 111:
EEPROM.put(29, minKelvin);
menu = 27;
break;
case 112:
EEPROM.put(31, maxKelvin);
menu = 28;
break;
}
break;
case 16:
select:
if (menu >= 80 && menu < 86) menu++;
if (menu >= 90 && menu < 94) menu++;
if (menu >= 100 && menu < 104) menu++;
switch (menu) {
case 9:
menu = 10;
break;
case 10:
menu = 11;
break;
case 11:
menu = 20;
break;
case 12:
menu = 40;
break;
case 13:
menu = 60;
break;
case 14:
menu = 70;
break;
case 20:
menu = 30;
break;
case 21:
menu = 31;
break;
case 22:
menu = 32;
break;
case 23:
menu = 33;
break;
case 24:
menu = 34;
break;
case 25:
menu = 35;
break;
case 26:
menu = 110;
break;
case 27:
white = true;
menu = 111;
break;
case 28:
white = true;
menu = 112;
break;
case 40:
menu = 50;
break;
case 41:
menu = 51;
break;
case 42:
menu = 53;
break;
case 43:
menu = 55;
break;
case 44:
menu = 56;
break;
case 51:
menu = 52;
break;
case 53:
menu = 54;
break;
case 60:
menu = 64;
break;
case 61:
menu = 63;
break;
case 70:
menu = 80;
break;
case 71:
menu = 90;
break;
case 72:
menu = 100;
break;
}
break;
case 18:
if (menu > 10 && menu < 20) menu--;
if (menu >= 20 && menu <= 28) menu--;
if (menu >= 40 && menu <= 44) menu--;
if (menu == 33 && default_timeout < 120) default_timeout++;
if (menu == 52 && L1switch < L1max) L1switch++;
if (menu == 54 && L2switch < L2max) L2switch++;
if (menu == 60 || menu == 61) menu--;
if (menu == 63 && lcd_maxBrightness < 255) lcd_maxBrightness += 5;
if (menu >= 70 && menu <= 72) menu--;
if (menu == 111 && minKelvin < maxKelvin) {
minKelvin += 50;
kelvin = minKelvin;
}
if (menu == 112 && maxKelvin < 6500) {
maxKelvin += 50;
kelvin = maxKelvin;
}
switch (menu) {
case 10:
menu = 14;
break;
case 19:
menu = 28;
break;
case 39:
menu = 44;
break;
case 30:
light = ++Bmax;
if (! gamma_correction && Bmax > maxWBrightness) Bmax = maxWBrightness;
if (gamma_correction && Bmax > maxGBrightness) Bmax = maxGBrightness;
break;
case 31:
light = ++Bmin;
if (Bmin > Bmax) Bmin = Bmax;
break;
case 32:
standby_light = true;
break;
case 34:
white = true;
break;
case 35:
if (! gamma_correction) {
temp = Bmax;
while (pgm_read_byte(&gamma[temp]) <= Bmax) {
temp++;
}
Bmax = temp;
temp = Bmin;
while (pgm_read_byte(&gamma[temp]) <= Bmin) {
temp++;
}
Bmin = temp;
temp = light;
while (pgm_read_byte(&gamma[temp]) <= light) {
temp++;
}
light = temp;
}
gamma_correction = true;
break;
case 50:
auto_light = true;
break;
case 55:
auto_dim = true;
break;
case 59:
menu = 61;
break;
case 64:
lcd_light = true;
break;
case 69:
menu = 72;
break;
case 81:
if (rtc[5] < 2) rtc[5]++;
if (rtc[5] == 2 && rtc[4] > 3) rtc[4] = 3;
break;
case 82:
if (rtc[4] < 9) rtc[4]++;
if (rtc[5] == 2 && rtc[4] > 3) rtc[4] = 3;
break;
case 83:
if (rtc[3] < 5) rtc[3]++;
break;
case 84:
if (rtc[2] < 9) rtc[2]++;
break;
case 85:
if (rtc[1] < 5) rtc[1]++;
break;
case 86:
if (rtc[0] > 9) rtc[0]++;
break;
case 91:
if (evening[3] < 2) evening[3]++;
if (evening[3] == 2 && evening[2] > 3) evening[2] = 3;
break;
case 92:
if (evening[2] < 9) evening[2]++;
if (evening[3] == 2 && evening[2] > 3) evening[2] = 3;
break;
case 93:
if (evening[1] < 5) evening[1]++;
break;
case 94:
if (evening[0] < 9) evening[0]++;
break;
case 101:
if (morning[3] < 2) morning[3]++;
if (morning[3] == 2 && morning[2] > 3) morning[2] = 3;
break;
case 102:
if (morning[2] < 9) morning[2]++;
if (morning[3] == 2 && morning[2] > 3) morning[2] = 3;
break;
case 103:
if (morning[1] < 5) morning[1]++;
break;
case 104:
if (morning[0] < 9) morning[0]++;
break;
case 110:
night_mode = true;
break;
}
break;
case 12:
if (menu < 15) menu++;
if (menu >= 20 && menu <= 28) menu++;
if (menu >= 40 && menu <= 44) menu++;
if (menu == 30 && Bmax > Bmin) light = --Bmax;
if (menu == 33 && default_timeout > 10) default_timeout--;
if (menu == 52 && L1switch > L1min) L1switch--;
if (menu == 54 && L2switch > L2min) L2switch--;
if (menu == 60 || menu == 61) menu++;
if (menu == 63 && lcd_maxBrightness > 20) lcd_maxBrightness -= 5;
if (menu >= 70 && menu <= 72) menu++;
if (menu == 111 && minKelvin > 2000) {
minKelvin -= 50;
kelvin = minKelvin;
}
if (menu == 112 && maxKelvin > minKelvin) {
maxKelvin -= 50;
kelvin = maxKelvin;
}
switch (menu) {
case 15:
menu = 11;
break;
case 29:
menu = 20;
break;
case 45:
menu = 40;
break;
case 31:
light = --Bmin;
if (! gamma_correction && Bmin < 5) Bmin = 5;
if (gamma_correction && Bmin < 63) Bmin = 63;
break;
case 32:
standby_light = false;
break;
case 34:
white = false;
break;
case 35:
if (gamma_correction) {
Bmax = min(pgm_read_byte(&gamma[Bmax]), maxWBrightness);
Bmin = max(pgm_read_byte(&gamma[Bmin]), 5);
light = pgm_read_byte(&gamma[light]);
}
gamma_correction = false;
break;
case 50:
auto_light = false;
break;
case 55:
auto_dim = false;
break;
case 62:
menu = 60;
break;
case 64:
lcd_light = false;
break;
case 73:
menu = 70;
break;
case 81:
if (rtc[5] > 0) rtc[5]--;
break;
case 82:
if (rtc[4] > 0) rtc[4]--;
break;
case 83:
if (rtc[3] > 0) rtc[3]--;
break;
case 84:
if (rtc[2] > 0) rtc[2]--;
break;
case 85:
if (rtc[1] > 0) rtc[1]--;
break;
case 86:
if (rtc[0] > 0) rtc[0]--;
break;
case 91:
if (evening[3] > 0) evening[3]--;
break;
case 92:
if (evening[2] > 0) evening[2]--;
break;
case 93:
if (evening[1] > 0) evening[1]--;
break;
case 94:
if (evening[0] > 0) evening[0]--;
break;
case 101:
if (morning[3] > 0) morning[3]--;
break;
case 102:
if (morning[2] > 0) morning[2]--;
break;
case 103:
if (morning[1] > 0) morning[1]--;
break;
case 104:
if (morning[0] > 0) morning[0]--;
break;
case 110:
night_mode = false;
break;
}
break;
}
}
}
void byte2() {
lcd.setCursor(0, 1);
lcd.write(byte(2));
lcd.setCursor(2, 1);
}
void byte4() {
lcd.setCursor(0, 1);
lcd.write(byte(4));
lcd.setCursor(3, 1);
}
void print_night() {
lcd.print(F(" starts"));
lcd.setCursor(0, 1);
lcd.print(F("at: "));
lcd.write(byte(0));
lcd.write(byte(1));
lcd.setCursor(7, 1);
}
void print_LED() {
lcd.print(F("LED"));
}
void lcd_menu(uint16_t page) {
byte temp;
if (page <= 80 || page == 90 || page == 100 || page >= 110) {
lcd.clear();
lcd.setCursor(0, 0);
}
if (page > 0 && page <= 3) {
if (mode == 0) lcd.print(F("Standby..."));
else if (mode == 255) {
lcd.print(light);
lcd.setCursor(11, 0);
if (white) lcd.print(kelvin);
else lcd.print(hue);
}
else lcd.print(F("Active..."));
lcd.setCursor(0, 1);
}
if (page > 10 && page < 30) goto byte3;
if (page == 60 || page == 61) goto byte3;
if (page >= 70 && page <= 72) goto byte3;
if (page >= 40 && page < 50) {
byte3:
lcd.write(byte(3));
lcd.setCursor(3, 0);
}
switch (page) {
case 0: //welcome
lcd.print(F("Stairlights v1.0"));
lcd.setCursor(0, 1);
lcd.print(F("by Istvan Kocsis"));
break;
case 1:
lcd.print(F("Press OK to menu"));
break;
case 2:
lcd.print(F("Press any to set"));
break;
case 3:
goto print_fps;
break;
case 4:
readRTC();
lcd.print(F("Time:"));
lcd.setCursor(8, 0);
lcd.print(rtc[5]);
lcd.print(rtc[4]);
lcd.print(F(":"));
lcd.print(rtc[3]);
lcd.print(rtc[2]);
lcd.print(F(":"));
lcd.print(rtc[1]);
lcd.print(rtc[0]);
lcd.setCursor(0, 1);
print_fps:
lcd.print(F("FPS:"));
if (fps > 9) lcd.setCursor(5, 1);
else lcd.setCursor(6, 1);
lcd.print(fps);
lcd.setCursor(8, 1);
lcd.print(F("CPS:"));
lcd.print(cps);
break;
case 9: //inMenu
lcd.write(byte(2));
lcd.setCursor(2, 0);
lcd.print(F("to scroll"));
lcd.setCursor(0, 1);
lcd.write(byte(0));
lcd.print(F(" to go back"));
break;
case 10: //inMenu
lcd.write(byte(1));
lcd.setCursor(2, 0);
lcd.print(F("or OK"));
lcd.setCursor(0, 1);
lcd.print(F("to select"));
break;
case 11: //LED settings
print_LED();
goto case14;
break;
case 12: //Sensor settings
lcd.setCursor(2, 0);
lcd.print(F("Ambient light"));
lcd.setCursor(0, 1);
lcd.write(byte(4));
lcd.print(F("sensor settings"));
break;
case 13: //LCD settings
lcd.print(F("Display"));
goto case14;
break;
case 14: //time settings
lcd.print(F("Date/Time"));
case14:
byte4();
lcd.print(F("settings"));
break;
case 20: //LED submenu
print_LED();
lcd.print(F(" max"));
goto case21;
break;
case 21: //LED submenu
print_LED();
lcd.print(F(" min"));
case21:
byte4();
lcd.print(F("brightness"));
break;
case 22: //LED submenu
print_LED();
lcd.print(F(" standby"));
byte4();
lcd.print(F("running light"));
break;
case 23: //LED submenu
print_LED();
byte4();
lcd.print(F("timeout"));
break;
case 24: //LED submenu
print_LED();
lcd.print(F(" color"));
byte4();
lcd.print(F("set"));
break;
case 25: //LED gamma
print_LED();
lcd.print(F(" gamma"));
byte4();
lcd.print(F("correction"));
break;
case 26: //LED night mode filter
goto case27;
break;
case 27: //LED night mode temp
case27:
lcd.print(F("Night mode"));
byte4();
if (page == 27) goto case28;
else lcd.print(F("blue filter"));
break;
case 28: //LED day mode temp
lcd.print(F("Day mode"));
byte4();
case28:
lcd.print(F("temperature"));
break;
case 30: //LED max brightness
lcd.print(F("Max brightness:"));
byte2();
lcd.print(Bmax);
break;
case 31: //LED min brightness
lcd.print(F("Min brightness:"));
byte2();
lcd.print(Bmin);
break;
case 32: //LED standby
lcd.print(F("Standby light:"));
byte2();
if (standby_light) lcd.print(F("ON"));
else lcd.print(F("OFF"));
break;
case 33: //LED timeout
lcd.print(F("LED timeout:"));
byte2();
lcd.print(default_timeout);
lcd.print(F(" sec"));
break;
case 34: //LED color
lcd.print(F("Default mode:"));
byte2();
if (white) lcd.print(F("White"));
else lcd.print(F("Color"));
break;
case 35: //LED gamma
lcd.print(F("Correction:"));
byte2();
if (gamma_correction) lcd.print(F("ON"));
else lcd.print(F("OFF"));
break;
case 40: //Sensor auto light
lcd.print(F("Ambient light"));
byte4();
lcd.print(F("activating"));
break;
case 41: //Sensor adjust
lcd.print(F("Primary"));
goto case42;
break;
case 42: //Sensor adjust
lcd.setCursor(1, 0);
lcd.print(F("Secondary"));
case42:
lcd.print(F(" light"));
byte4();
lcd.print(F("sensor"));
break;
case 43:
lcd.print(F("Auto dimming"));
byte4();
lcd.print(F("in the dark"));
break;
case 44: //Sensor calibration
lcd.print(F("Light sensor"));
byte4();
lcd.print(F("recalibration"));
break;
case 50:
lcd.print(F("Only in dark?"));
lcd.setCursor(0, 1);
lcd.write(byte(2));
lcd.setCursor(2, 1);
if (auto_light) lcd.print(F("Auto ON"));
else lcd.print(F("Always ACTIVE"));
break;
case 51:
goto case53;
break;
case 52:
temp = map(L1switch, L1min, L1max, 0, 100);
lcd.print(F("Sensitivity:"));
lcd.setCursor(0, 1);
lcd.write(byte(2));
if (L1switch > 999) lcd.setCursor(1, 1);
else if (L1switch > 99) lcd.setCursor(2, 1);
else if (L1switch > 9) lcd.setCursor(3, 1);
else lcd.setCursor(4, 1);
lcd.print(L1switch);
if (temp < 10 ) lcd.setCursor(7, 1);
else lcd.setCursor(6, 1);
lcd.print(temp);
lcd.print(F("% of max"));
break;
case 53:
case53:
lcd.print(F("OK: read sensor"));
lcd.setCursor(0, 1);
lcd.write(byte(2));
lcd.setCursor(1, 1);
lcd.print(F(": to adjust"));
break;
case 54:
temp = map(L2switch, L2min, L2max, 0, 100);
lcd.print(F("Sensitivity:"));
lcd.setCursor(0, 1);
lcd.write(byte(2));
if (L2switch > 999) lcd.setCursor(1, 1);
else if (L1switch > 99) lcd.setCursor(2, 1);
else if (L2switch > 9) lcd.setCursor(3, 1);
else lcd.setCursor(4, 1);
lcd.print(L2switch);
if (temp < 10 ) lcd.setCursor(7, 1);
else lcd.setCursor(6, 1);
lcd.print(temp);
lcd.print(F("% of max"));
break;
case 55:
lcd.write(byte(2));
lcd.setCursor(2, 0);
lcd.print(F("Auto dimming"));
lcd.setCursor(0, 1);
if (auto_dim) lcd.print(F("ON: dim in dark"));
else lcd.print(F("OFF: full power"));
break;
case 56:
lcd.print(F("OK to reset"));
lcd.setCursor(0, 1);
lcd.print(F("stored values?"));
break;
case 57:
lcd.print(F("Calibration data"));
lcd.setCursor(0, 1);
lcd.print(F("cleared!"));
break;
case 60:
lcd.print(F("LCD backlight"));
byte4();
lcd.print(F("mode"));
break;
case 61:
lcd.print(F("LCD"));
byte4();
lcd.print(F("brightness"));
break;
case 63:
lcd.print(F("Brightness:"));
byte2();
lcd.print(lcd_maxBrightness);
break;
case 64:
lcd.write(byte(2));
lcd.setCursor(2, 0);
lcd.print(F("Auto dimming"));
lcd.setCursor(2, 1);
if (lcd_light) lcd.print(F("Always ON"));
else lcd.print(F("Auto OFF"));
break;
case 70:
lcd.print(F("Set time"));
lcd.setCursor(0, 1);
lcd.write(byte(4));;
break;
case 71:
lcd.print(F("Set start of"));
goto case72;
break;
case 72:
lcd.print(F("Set end of"));
case72:
byte4();
lcd.print(F("night mode"));
break;
case 80:
lcd.print(F("Time:"));
lcd.setCursor(8, 0);
lcd.print(rtc[5]);
lcd.print(rtc[4]);
lcd.print(F(":"));
lcd.print(rtc[3]);
lcd.print(rtc[2]);
lcd.print(F(":"));
lcd.print(rtc[1]);
lcd.print(rtc[0]);
lcd.setCursor(0, 1);
lcd.write(byte(0));
lcd.write(byte(1));
break;
case 81:
lcd.setCursor(8, 0);
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[5]);
lcd.print(rtc[4]);
break;
case 82:
lcd.setCursor(8, 0);
lcd.print(rtc[5]);
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[4]);
lcd.print(F(":"));
lcd.print(rtc[3]);
break;
case 83:
lcd.setCursor(9, 0);
lcd.print(rtc[4]);
lcd.print(F(":"));
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[3]);
lcd.print(rtc[2]);
break;
case 84:
lcd.setCursor(11, 0);
lcd.print(rtc[3]);
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[2]);
lcd.print(F(":"));
lcd.print(rtc[1]);
break;
case 85:
lcd.setCursor(12, 0);
lcd.print(rtc[2]);
lcd.print(F(":"));
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[1]);
lcd.print(rtc[0]);
break;
case 86:
lcd.setCursor(14, 0);
lcd.print(rtc[1]);
if (!flashing) lcd.print(F("_"));
else lcd.print(rtc[0]);
break;
case 90:
lcd.print(F("Evening"));
print_night();
lcd.print(evening[3]);
lcd.print(evening[2]);
lcd.print(F(":"));
lcd.print(evening[1]);
lcd.print(evening[0]);
break;
case 91:
lcd.setCursor(7, 1);
if (!flashing) lcd.print(F("_"));
else lcd.print(evening[3]);
lcd.print(evening[2]);
break;
case 92:
lcd.setCursor(7, 1);
lcd.print(evening[3]);
if (!flashing) lcd.print(F("_"));
else lcd.print(evening[2]);
lcd.print(F(":"));
lcd.print(evening[1]);
break;
case 93:
lcd.setCursor(8, 1);
lcd.print(evening[2]);
lcd.print(F(":"));
if (!flashing) lcd.print(F("_"));
else lcd.print(evening[1]);
lcd.print(evening[0]);
break;
case 94:
lcd.setCursor(10, 1);
lcd.print(evening[1]);
if (!flashing) lcd.print(F("_"));
else lcd.print(evening[0]);
break;
case 100:
lcd.print(F("Morning"));
print_night();
lcd.print(morning[3]);
lcd.print(morning[2]);
lcd.print(F(":"));
lcd.print(morning[1]);
lcd.print(morning[0]);
break;
case 101:
lcd.setCursor(7, 1);
if (!flashing) lcd.print(F("_"));
else lcd.print(morning[3]);
lcd.print(morning[2]);
break;
case 102:
lcd.setCursor(7, 1);
lcd.print(morning[3]);
if (!flashing) lcd.print(F("_"));
else lcd.print(morning[2]);
lcd.print(F(":"));
lcd.print(morning[1]);
break;
case 103:
lcd.setCursor(8, 1);
lcd.print(morning[2]);
lcd.print(F(":"));
if (!flashing) lcd.print(F("_"));
else lcd.print(morning[1]);
lcd.print(morning[0]);
break;
case 104:
lcd.setCursor(10, 1);
lcd.print(morning[1]);
if (!flashing) lcd.print(F("_"));
else lcd.print(morning[0]);
break;
case 110: //LED temperature
lcd.print(F("Filter light"));
byte2();
if (night_mode) lcd.print(F("ON"));
else lcd.print(F("OFF"));
break;
case 111:
goto case112;
break;
case 112:
case112:
lcd.print(F("Temperature:"));
byte2();
if (page == 112) lcd.print(maxKelvin);
else lcd.print(minKelvin); //case 111
lcd.print(F(" Kelvin"));
break;
}
}
ISR(WDT_vect, ISR_NAKED)
{
register uint8_t *upStack;
upStack = (uint8_t *)SP + 1;
report = (*upStack << 8) | *(++upStack);
eeprom_write_word((uint16_t *)500, report);
}
void setup() {
//watchdog config
byte resetflag = MCUSR; // save flags for debug
MCUSR = 0; // reset various flags
WDTCSR |= 0b00011000; // see docs, set WDCE, WDE
WDTCSR = 0b01101001; // set WDIE, WDE, and appropriate delay
wdt_reset();
//LCD
lcd.createChar(0, leftChar);
lcd.createChar(1, rightChar);
lcd.createChar(2, upDownChar);
lcd.createChar(3, upChar);
lcd.createChar(4, downChar);
pinMode(6, OUTPUT);
analogWrite(6, lcd_brightness);
lcd.begin(16, 2);
lcd_menu(0);
//IR receiver
irreceiver.enableIRIn(); // Start the receiver
//pinMode(8, INPUT);
pinMode(13, OUTPUT);
if (resetflag & 0b00001000) digitalWrite(13, HIGH);
else digitalWrite(13, LOW);
ledstrip.clear(1000);
Serial.begin(9600);
I2c.begin();
I2c.setSpeed(true);
I2c.pullup(true);
I2c.timeOut(1000);
//I2C RTC
pinMode(3, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(3), rtcSignal, FALLING);
initRTC(true);
float temp1 = analogRead(A7) / 204.6; //map to 0..5V
Serial.print(F("Battery: "));
Serial.print(temp1);
Serial.println(F("V"));
readRTC();
//watchdog report
EEPROM.get(500, report);
Serial.print(F("Froze at: 0x"));
Serial.println(report * 2, HEX);
if (resetflag != 0) Serial.print(F("Reset: "));
switch (resetflag) {
case 1:
Serial.println(F("Power-on"));
break;
case 2:
Serial.println(F("External"));
break;
case 4:
Serial.println(F("Brown-out"));
break;
case 8:
Serial.println(F("Watchdog"));
break;
}
//calculate maxGBrightness
maxGBrightness = maxWBrightness;
while (pgm_read_byte(&gamma[maxGBrightness]) <= maxWBrightness) {
maxGBrightness++;
}
//Stored sensor calibration data
EEPROM.get(0, L1max);
EEPROM.get(2, L1min);
EEPROM.get(10, L2max);
EEPROM.get(12, L2min);
Serial.print(F("Sensor data: "));
Serial.print(L1max);
Serial.print(F(", "));
Serial.println(L1min);
Serial.print(L2max);
Serial.print(F(", "));
Serial.println(L2min);
//load data from eeprom
EEPROM.get(4, Bmax);
EEPROM.get(5, Bmin);
EEPROM.get(6, standby_light);
EEPROM.get(7, default_timeout);
EEPROM.get(8, white);
EEPROM.get(9, gamma_correction);
EEPROM.get(14, L1switch);
EEPROM.get(16, L2switch);
EEPROM.get(18, lcd_light);
EEPROM.get(19, lcd_maxBrightness);
EEPROM.get(20, evening);
EEPROM.get(24, morning);
EEPROM.get(28, night_mode);
EEPROM.get(29, minKelvin);
EEPROM.get(31, maxKelvin);
EEPROM.get(33, auto_light);
EEPROM.get(34, auto_dim);
}
void loop() {
wdt_reset(); //reset wathdog timer
frame = micros();
//PIR trigger
if (digitalRead(8) == HIGH && !PIR1) {
PIR1 = true;
trigger1 = true;
//Serial.println("PIR 1");
}
else if (digitalRead(8) == LOW) PIR1 = false;
if (digitalRead(9) == HIGH && !PIR2) {
PIR2 = true;
trigger2 = true;
//Serial.println("PIR 2");
}
else if (digitalRead(9) == LOW) PIR2 = false;
//Infra remote
if (irreceiver.decode(&results)) {
//Serial.println(results.value, HEX);
irreceiver.resume();
switch (results.value) {
case 0xFDA857: //OK
//Serial.println(F("OK"));
mode = 255;
repeat = 0;
if (! inMenu) {
inMenu = true;
menu = 9;
}
else menuHandler(15);
break;
case 0xFD8877: //UP
//Serial.println(F("Up"));
mode = 255;
repeat = 8;
show = true;
timeout = default_timeout;
goto up;
break;
case 0xFD9867: //DOWN
//Serial.println(F("Down"));
mode = 255;
repeat = 2;
show = true;
timeout = default_timeout;
goto down;
break;
case 0xFD28D7: //Left
//Serial.println(F("Left"));
mode = 255;
if (! inMenu) repeat = 4;
else repeat = 0;
show = true;
timeout = default_timeout;
goto left;
break;
case 0xFD6897: //Right
//Serial.println(F("Right"));
mode = 255;
if (! inMenu) repeat = 6;
else repeat = 0;
show = true;
timeout = default_timeout;
goto right;
break;
/*case 0xFD30CF: //Star
Serial.println(F("Star"));
RTC = !RTC;
initRTC(RTC);
repeat = 0;
timeout = default_timeout;
menuHandler(17);
break;*/
case 0xFD708F: //Cross
//Serial.println(F("Cross"));
white = !white;
mode = 255;
repeat = 0;
show = true;
timeout = default_timeout;
menuHandler(19);
break;
/*case 0xFD00FF: // 1
Serial.println(F("1"));
repeat = 0;
menuHandler(1);
break;
case 0xFD807F: // 2
Serial.println(F("2"));
repeat = 0;
menuHandler(2);
break;
case 0xFD40BF: // 3
Serial.println(F("3"));
repeat = 0;
menuHandler(3);
break;
case 0xFD20DF: // 4
Serial.println(F("4"));
repeat = 0;
menuHandler(4);
break;
case 0xFDA05F: // 5
Serial.println(F("5"));
repeat = 0;
menuHandler(5);
break;
case 0xFD609F: // 6
Serial.println(F("6"));
repeat = 0;
menuHandler(6);
break;
case 0xFD10EF: // 7
Serial.println(F("7"));
repeat = 0;
menuHandler(7);
break;
case 0xFD906F: // 8
Serial.println(F("8"));
repeat = 0;
menuHandler(8);
break;
case 0xFD50AF: // 9
Serial.println(F("9"));
repeat = 0;
menuHandler(9);
break;
case 0xFDB04F: // 0
Serial.println(F("0"));
repeat = 0;
menuHandler(10);
break;*/
default:
mode = 255;
show = true;
timeout = default_timeout;
break;
}
if (results.value == 0xFFFFFFFF) {
switch (repeat) {
case 8: //Up
up:
if (! inMenu) {
lcd_update = true;
if (light < Bmax) light += 5;
else light = Bmax;
//Serial.println(light);
}
else menuHandler(18);
break;
case 2: //Down
down:
if (! inMenu) {
if (light > Bmin) light -= 5;
else light = Bmin;
lcd_update = true;
//Serial.println(light);
}
else menuHandler(12);
break;
case 4: //Left
left:
if (! inMenu) {
lcd_update = true;
if (white) {
if (kelvin > 2000) kelvin -= 50;
else kelvin = 2000;
//Serial.println(kelvin);
}
else {
if (hue >= 2) hue -= 2;
else hue = 359;
//Serial.println(hue);
}
}
else menuHandler(14);
break;
case 6: //Right
right:
if (! inMenu) {
lcd_update = true;
if (white) {
if (kelvin < 6500) kelvin += 50;
else kelvin = 6500;
//Serial.println(kelvin);
}
else {
if (hue <= 357) hue += 2;
else hue = 0;
//Serial.println(hue);
}
}
else menuHandler(16);
break;
}
}
}
//light sensor
if (analogRead(A0) > L1max) {
L1max = analogRead(A0);
EEPROM.put(0, L1max);
}
if (analogRead(A0) < L1min) {
L1min = analogRead(A0);
EEPROM.put(2, L1min);
}
if (analogRead(A1) > L2max) {
L2max = analogRead(A1);
EEPROM.put(10, L2max);
}
if (analogRead(A1) < L2min) {
L2min = analogRead(A1);
EEPROM.put(12, L2min);
}
if (mode == 0) {
int temp1, temp2;
temp1 = analogRead(A0);
temp2 = analogRead(A1);
static int hys1 = temp1, hys2 = temp2;
if (temp1 > hys1 + 5 || temp1 < hys1 - 5) hys1 = temp1;
if (temp2 > hys2 + 5 || temp2 < hys2 - 5) hys2 = temp2;
if (auto_light) {
if (hys1 <= L1switch || hys2 <= L2switch) {
if (auto_dim) goto dimming;
else light = Bmax;
}
else light = 0;
}
else if (auto_dim) {
dimming:
light = min(max(map(hys1, L1min, L1switch, Bmin, Bmax), map(hys2, L2min, L2switch, Bmin, Bmax)), Bmax);
}
else light = Bmax;
}
//event manager
if (trigger1 && mode == 0) {
mode = 1;
timeout = default_timeout;
position = -6;
trigger1 = false;
}
if (trigger2 && mode == 1) {
mode = 12;
position = -6;
trigger2 = false;
}
if (trigger2 && mode == 0) {
mode = 2;
timeout = default_timeout;
position = numPixels;
trigger2 = false;
}
if (trigger1 && mode == 2) {
mode = 21;
position = numPixels;
trigger1 = false;
}
if (timeout < 1 && mode == 1) {
mode = 21;
position = numPixels;
}
if (timeout < 1 && mode == 2) {
mode = 12;
position = -6;
}
if (timeout < 1 && mode == 255) {
mode = 12;
position = -6;
}
switch (mode) {
case 0: //standby
if (standby_light) {
if (white) {
getColorTemp(kelvin);
lightAdjustment(min(3, light), false);
larsonScanner(x, 0, numPixels, resolution, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, min(3, light));
larsonScanner(x, 0, numPixels, resolution, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
show = true;
}
break;
case 1:
if (white) {
getColorTemp(kelvin);
lightAdjustment(light, gamma_correction);
lightWipe(true, true, position, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, light);
lightWipe(true, true, position, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
if (position < numPixels) {
position += 4;
show = true;
}
break;
case 12:
if (white) {
getColorTemp(kelvin);
lightAdjustment(light, gamma_correction);
lightWipe(false, true, position, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, light);
lightWipe(false, true, position, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
if (position < numPixels) {
position += 2;
show = true;
}
else mode = 0;
break;
case 2:
if (white) {
getColorTemp(kelvin);
lightAdjustment(light, gamma_correction);
lightWipe(true, false, position, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, light);
lightWipe(true, false, position, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
if (position > -6) {
position -= 4;
show = true;
}
break;
case 21:
if (white) {
getColorTemp(kelvin);
lightAdjustment(light, gamma_correction);
lightWipe(false, false, position, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, light);
lightWipe(false, false, position, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
if (position > -6) {
position -= 2;
show = true;
}
else mode = 0;
break;
case 255:
if (white) {
getColorTemp(kelvin);
lightAdjustment(light, gamma_correction);
lightWipe(true, true, numPixels, RED(colorSample, 3), GREEN(colorSample, 3), BLUE(colorSample, 3));
}
else {
getRGB(hue, 255, light);
lightWipe(true, true, numPixels, RED(colorSample, 0), GREEN(colorSample, 0), BLUE(colorSample, 0));
}
break;
}
//LED update
if (show) {
ledstrip.sendPixels(numPixels, buffer1);
show = false;
fps++;
}
//LCD
if (lcd_update || second) {
if (! inMenu && (clockSeconds > slideshow + 5)) {
menu++;
if (menu > 4) menu = 1;
slideshow = clockSeconds;
}
if (inMenu && timeout == 0) {
menu = 1;
inMenu = false;
//Serial.print("Shit");
}
lcd_menu(menu);
lcd_update = false;
}
if (mode == 0 && lcd_brightness > 0 && !lcd_light) analogWrite(6, --lcd_brightness);
if (mode == 255) {
if (lcd_brightness < lcd_maxBrightness) analogWrite(6, ++lcd_brightness);
else if (lcd_brightness != lcd_maxBrightness) analogWrite(6, --lcd_brightness);
}
frame = (micros() - frame);
x += round(anim_speed * float(60.0 / (1000000 / frame))); //60 fps = 100% speed
cps++;
if (second) {
flashing = !flashing;
clockSeconds++;
if (timeout > 0 ) timeout--;
//Time manager
if (night_mode && !inMenu) {
current_time = bcdToDec(rtc[5], rtc[4]) * 60 + bcdToDec(rtc[3], rtc[2]);
evening_time = bcdToDec(evening[3], evening[2]) * 60 + bcdToDec(evening[1], evening[0]);
morning_time = bcdToDec(morning[3], morning[2]) * 60 + bcdToDec(morning[1], morning[0]);
if (current_time >= evening_time) {
if (current_time - evening_time <= 30) {
byte temp = current_time - evening_time;
kelvin = map(temp, 0, 30, maxKelvin, minKelvin);
//Serial.println("1");
}
else {
kelvin = minKelvin;
//Serial.println("2");
}
}
else if (current_time <= morning_time) {
if (morning_time - current_time <= 30) {
byte temp = morning_time - current_time;
kelvin = map(temp, 0, 30, maxKelvin, minKelvin);
//Serial.println("3");
}
else {
kelvin = minKelvin;
//Serial.println("4");
}
}
else {
kelvin = maxKelvin;
//Serial.println("5");
}
}
fps = 0;
cps = 0;
second = false;
}
}
const byte PROGMEM dim_curve[] = {
0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11,
11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15,
15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20,
20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35,
36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47,
48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82,
83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109,
110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144,
146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190,
193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255,
};
const uint8_t PROGMEM gamma[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment