|
@@ -77,6 +77,16 @@ uint8_t animate = 0;
|
|
uint8_t red = 1;
|
|
uint8_t red = 1;
|
|
uint8_t green = 1;
|
|
uint8_t green = 1;
|
|
uint8_t blue = 1;
|
|
uint8_t blue = 1;
|
|
|
|
+uint8_t brightness = 50;
|
|
|
|
+
|
|
|
|
+#define DISABLE_FASTLED_CORRECTION 0
|
|
|
|
+#define ENABLE_FASTLED_CORRECTION 1
|
|
|
|
+#define DISABLE_GAMMA_CORRECTION 0
|
|
|
|
+#define USE_PHILIP_GAMMA_CORRECTION 1
|
|
|
|
+#define USE_BG100_S_CURVE_GAMMA_CORRECTION 2
|
|
|
|
+
|
|
|
|
+uint8_t gammaCorrectionType = DISABLE_GAMMA_CORRECTION;
|
|
|
|
+uint8_t useFastLedCorrection = DISABLE_FASTLED_CORRECTION;
|
|
|
|
|
|
// quick fix for gamma correction from Adafruit's Phillip Burgess
|
|
// quick fix for gamma correction from Adafruit's Phillip Burgess
|
|
static uint8_t phillip_adafruitGamma8[] = {
|
|
static uint8_t phillip_adafruitGamma8[] = {
|
|
@@ -129,22 +139,33 @@ static uint8_t bg100_sCurveGamma8[] = {
|
|
* I believe that this color correction has to do with mechanical measurements as they are linear
|
|
* I believe that this color correction has to do with mechanical measurements as they are linear
|
|
* and I know that the human eye sensitivities are anything but. Otherwise this is very crude.
|
|
* and I know that the human eye sensitivities are anything but. Otherwise this is very crude.
|
|
*/
|
|
*/
|
|
-static uint8_t redCorrection = 0xFF;
|
|
|
|
-static uint8_t greenCorrection = 0xB0;
|
|
|
|
-static uint8_t blueCorrection = 0xF0;
|
|
|
|
|
|
+#define FASTLED_RED_CORRECTION = 0x00FF;
|
|
|
|
+#define FASTLED_GREEN_CORRECTION = 0x00B0;
|
|
|
|
+#define FASTLED_BLUE_CORRECTION = 0x00F0;
|
|
|
|
+
|
|
|
|
+uint8_t correctColor(uint8_t input, uint16_t factor) {
|
|
|
|
+ uint16_t out;
|
|
|
|
+ uint16_t in;
|
|
|
|
+ in = input;
|
|
|
|
+ out = in * factor;
|
|
|
|
+ out /= 255;
|
|
|
|
+ return ENABLE_FASTLED_CORRECTION == useFastLedCorrection
|
|
|
|
+ ? gammaCorrection((uint8_t) out)
|
|
|
|
+ : gammaCorrection(input);
|
|
|
|
+}
|
|
|
|
|
|
-/* we are going to cheat the brightness by adjusting pwm resolution
|
|
|
|
- *
|
|
|
|
- * in effect this will change the brightness and we will not need to perform any math
|
|
|
|
- * the way this works is that PWM resolution is 10-bit but when we set the duty-cycle
|
|
|
|
- * we only use values [0..255]. By increasing the resoltion past 255 we reduce the
|
|
|
|
- * brightness. Cool.
|
|
|
|
- */
|
|
|
|
-void adjustBrightness() {
|
|
|
|
- analogWriteRange(511);
|
|
|
|
|
|
+uint8_t gammaCorrection(uint8_t input) {
|
|
|
|
+ switch(gammaCorrectionType) {
|
|
|
|
+ case USE_PHILIP_GAMMA_CORRECTION: return phillip_adafruitGamma8[input];
|
|
|
|
+ case USE_BG100_S_CURVE_GAMMA_CORRECTION: return bg100_sCurveGamma8[input];
|
|
|
|
+ case DISABLE_GAMMA_CORRECTION:
|
|
|
|
+ default:
|
|
|
|
+ }
|
|
|
|
+ return input;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
ESP8266WebServer server(80); // Create a webserver object that listens for HTTP request on port 80
|
|
ESP8266WebServer server(80); // Create a webserver object that listens for HTTP request on port 80
|
|
|
|
|
|
void handleRoot(); // function prototypes for HTTP handlers
|
|
void handleRoot(); // function prototypes for HTTP handlers
|
|
@@ -183,6 +204,10 @@ void setup(void){
|
|
server.on("/dec", HTTP_GET, handleGetDec);
|
|
server.on("/dec", HTTP_GET, handleGetDec);
|
|
server.on("/echo", HTTP_GET, handleEchoHex);
|
|
server.on("/echo", HTTP_GET, handleEchoHex);
|
|
server.on("/animate", HTTP_GET, handleAnimate);
|
|
server.on("/animate", HTTP_GET, handleAnimate);
|
|
|
|
+ server.on("/cfg", HTTP_GET, handleGetCfg);
|
|
|
|
+ server.on("/cfg", HTTP_POST, handleCfg);
|
|
|
|
+ server.on("/brightness", HTTP_POST, handleGetBrightness);
|
|
|
|
+ server.on("/brightness", HTTP_POST, handleBrightness
|
|
|
|
|
|
server.onNotFound(handleNotFound); // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
|
|
server.onNotFound(handleNotFound); // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
|
|
|
|
|
|
@@ -194,9 +219,23 @@ void setup(void){
|
|
#define PIN_6 12 /* GPIO_12 */
|
|
#define PIN_6 12 /* GPIO_12 */
|
|
#define PIN_7 13 /* GPIO_13 */
|
|
#define PIN_7 13 /* GPIO_13 */
|
|
|
|
|
|
|
|
+ /* slowing the PWM frequency decreases the error caused by the power mosfets
|
|
|
|
+ * having a slow turn-off
|
|
|
|
+ * this comes at a cost of flickering. One might think that LED PWM at
|
|
|
|
+ * 1000Hz is not noticeable by the human eye, but one can see the flicker
|
|
|
|
+ * appear as multiple spots when moving. It isn't really a flicker but one
|
|
|
|
+ * can tell.
|
|
|
|
+ */
|
|
//analogWriteFreq(1000);
|
|
//analogWriteFreq(1000);
|
|
analogWriteFreq(250);
|
|
analogWriteFreq(250);
|
|
|
|
|
|
|
|
+ // lower brightness to minimal value
|
|
|
|
+ brightness = 0;
|
|
|
|
+ updateBrightness ();
|
|
|
|
+
|
|
|
|
+ // turn on the onboard led for testing brightness
|
|
|
|
+ analogWrite(/* esp12f onboard led */ 2, 255);
|
|
|
|
+
|
|
// setup pins with a test pwm
|
|
// setup pins with a test pwm
|
|
analogWrite(PIN_5, red);
|
|
analogWrite(PIN_5, red);
|
|
analogWrite(PIN_6, green);
|
|
analogWrite(PIN_6, green);
|
|
@@ -303,15 +342,98 @@ void handleGetDec() {
|
|
server.send(200, "text/html", hex + red + "," + green + "," + blue + '\n');
|
|
server.send(200, "text/html", hex + red + "," + green + "," + blue + '\n');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void handleGetBrightness() {
|
|
|
|
+ String info = "";
|
|
|
|
+ server.send(200, "text/html", info + brightness + '\n');
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* we are going to cheat the brightness by adjusting pwm resolution
|
|
|
|
+ *
|
|
|
|
+ * in effect this will change the brightness and we will not need to perform any math
|
|
|
|
+ * the way this works is that PWM resolution is 10-bit but when we set the duty-cycle
|
|
|
|
+ * we only use values [0..255]. By increasing the resoltion past 255 we reduce the
|
|
|
|
+ * brightness. Cool.
|
|
|
|
+ *
|
|
|
|
+ * [?] because our gate drive voltage source is a weak reverse biased zener
|
|
|
|
+ * regulator and we just use resistors to turn off the power mosfets we
|
|
|
|
+ * have a hard time with power losses turning on and off the mosfet. When
|
|
|
|
+ * we drive all three mosfets on with 100% duty cycle the voltage source
|
|
|
|
+ * drops well below the needed drive voltage and the mosfet Rds becomes
|
|
|
|
+ * pretty terrible. It works but is really bad. If we run less than
|
|
|
|
+ * 50% duty we should be okay. Using 1023 as the starting point means that
|
|
|
|
+ * at 0 brightness mosfets are driven at 25% duty (255/1032). At 100
|
|
|
|
+ * brightness they are driven at 60% duty 255/432.
|
|
|
|
+ */
|
|
|
|
+void updateBrightness () {
|
|
|
|
+ // default range is 0..255
|
|
|
|
+ analogWriteRange(1023);
|
|
|
|
+ // brightness is inverted, technically it is darkness
|
|
|
|
+ uint8_t brightnessValue = 6 * (100 - brightness);
|
|
|
|
+ // reducing PWM range will increase brightness
|
|
|
|
+ analogWriteRange(1023 - brightnessValue);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void handleBrightness() {
|
|
|
|
+ char buffer[4];
|
|
|
|
+ if( ! server.hasArg("brightness")) {
|
|
|
|
+ server.send(400, "text/plain", "400: Invalid Request"); // The request is invalid, so send HTTP status 400
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ // else
|
|
|
|
+ server.arg("brightness").getBytes(buffer, 3);
|
|
|
|
+ brightness = (nibbler(buffer[0]) << 4) + nibbler(buffer[1]);
|
|
|
|
+ // limit brightness to 100
|
|
|
|
+ brightness = 100 < brightness ? 100 : brightness;
|
|
|
|
+ updateBrightness();
|
|
|
|
+ handleGetBrightness();
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void handleCfg() {
|
|
|
|
+ uint8_t valid = 0;
|
|
|
|
+ char buf[3];
|
|
|
|
+ if(server.hasArg("quickGamma")) {
|
|
|
|
+ server.arg("quickGamma").getBytes(buf, 2);
|
|
|
|
+ gammaCorrectionType = '1' == buf[0]
|
|
|
|
+ ? USE_BG100_S_CURVE_GAMMA_CORRECTION
|
|
|
|
+ : DISABLE_GAMMA_CORRECTION;
|
|
|
|
+ valid += 1;
|
|
|
|
+ }
|
|
|
|
+ if(server.hasArg("sCurveGamma")) {
|
|
|
|
+ server.arg("sCurveGamma").getBytes(buf, 2);
|
|
|
|
+ gammaCorrectionType = '1' == buf[0]
|
|
|
|
+ ? USE_PHILIP_GAMMA_CORRECTION
|
|
|
|
+ : DISABLE_GAMMA_CORRECTION;
|
|
|
|
+ valid += 1;
|
|
|
|
+ }
|
|
|
|
+ if(server.hasArg("colorCorrection")) {
|
|
|
|
+ server.arg("colorCorrection").getBytes(buf, 2);
|
|
|
|
+ gammaCorrectionType = '1' == buf[0]
|
|
|
|
+ ? ENABLE_FASTLED_CORRECTION
|
|
|
|
+ : DISABLE_FASTLED_CORRECTION;
|
|
|
|
+ valid += 1;
|
|
|
|
+ }
|
|
|
|
+ if(valid) handleGetCfg(); else server.send(400, "text/plain", "400: Invalid Request");
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void handleGetCfg() {
|
|
|
|
+ String info = "cfg [quickGamma:";
|
|
|
|
+ uint8_t fastled = ENABLE_FASTLED_CORRECTION == useFastLedCorrection;
|
|
|
|
+ uint8_t sCurve = USE_PHILIP_GAMMA_CORRECTION == gammaCorrectionType;
|
|
|
|
+ uint8_t quick = USE_BG100_S_CURVE_GAMMA_CORRECTION == gammaCorrectionType;
|
|
|
|
+ if(valid) server.send(200, "text/html", info + quick + " sCurveGamma:" + sCurve + " colorCorrection:" + fastled + ']' + '\n');
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
void handleRGB() { // If a POST request is made to URI /login
|
|
void handleRGB() { // If a POST request is made to URI /login
|
|
if( ! server.hasArg("color")) {
|
|
if( ! server.hasArg("color")) {
|
|
server.send(400, "text/plain", "400: Invalid Request"); // The request is invalid, so send HTTP status 400
|
|
server.send(400, "text/plain", "400: Invalid Request"); // The request is invalid, so send HTTP status 400
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-
|
|
|
|
// turn of animate
|
|
// turn of animate
|
|
animate = 1;
|
|
animate = 1;
|
|
-
|
|
|
|
// kinda lame but parsing is not super easy here
|
|
// kinda lame but parsing is not super easy here
|
|
server.arg("color").getBytes(hexStr, 7);
|
|
server.arg("color").getBytes(hexStr, 7);
|
|
setColor(
|
|
setColor(
|
|
@@ -319,18 +441,8 @@ void handleRGB() { // If a POST request is made to URI /
|
|
/* green */ (nibbler(hexStr[2]) << 4) + nibbler(hexStr[3]),
|
|
/* green */ (nibbler(hexStr[2]) << 4) + nibbler(hexStr[3]),
|
|
/* blue */ (nibbler(hexStr[4]) << 4) + nibbler(hexStr[5])
|
|
/* blue */ (nibbler(hexStr[4]) << 4) + nibbler(hexStr[5])
|
|
)
|
|
)
|
|
-
|
|
|
|
- /*
|
|
|
|
- server.arg("color").substring(0, 2).toCharArray(hexStr, 2);
|
|
|
|
- r = hexStrToInt(hexStr);
|
|
|
|
- server.arg("color").substring(2, 4).toCharArray(hexStr, 2);
|
|
|
|
- g = hexStrToInt(hexStr);
|
|
|
|
- server.arg("color").substring(4, 6).toCharArray(hexStr, 2);
|
|
|
|
- b = hexStrToInt(hexStr);
|
|
|
|
- */
|
|
|
|
String info = "degub r:";
|
|
String info = "degub r:";
|
|
server.send(200, "text/html", info + red + " g:" + green + " b:" + blue + '\n');
|
|
server.send(200, "text/html", info + red + " g:" + green + " b:" + blue + '\n');
|
|
- //server.send(200, "text/html", "okay");
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void setColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
void setColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
@@ -338,9 +450,17 @@ void setColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
red = r;
|
|
red = r;
|
|
green = g;
|
|
green = g;
|
|
blue = b;
|
|
blue = b;
|
|
- analogWrite(PIN_5, red);
|
|
|
|
- analogWrite(PIN_6, green);
|
|
|
|
- analogWrite(PIN_7, blue);
|
|
|
|
|
|
+ /* [!] it looks like we always correct color, this is not the case
|
|
|
|
+ * the correctColor() routine, and the chained gammaCorrection() routine
|
|
|
|
+ * check configuration settings before setting the LED color.
|
|
|
|
+ *
|
|
|
|
+ * the fast-led correction tones down green significantly and blue a bit.
|
|
|
|
+ * Both linearly, I assume this is not to adjust for human eye sensitivity
|
|
|
|
+ * but just for the junction efficiency
|
|
|
|
+ */
|
|
|
|
+ analogWrite(PIN_5, correctColor(red, FASTLED_RED_CORRECTION));
|
|
|
|
+ analogWrite(PIN_6, correctColor(green, FASTLED_GREEN_CORRECTION));
|
|
|
|
+ analogWrite(PIN_7, correctColor(blue, FASTLED_BLUE_CORRECTION));
|
|
}
|
|
}
|
|
// converts ASCII utf8 chars to integer values, [0..F], otherwise zero
|
|
// converts ASCII utf8 chars to integer values, [0..F], otherwise zero
|
|
uint8_t nibbler(uint8_t v) {
|
|
uint8_t nibbler(uint8_t v) {
|