aboutsummaryrefslogtreecommitdiff
path: root/hwdef-Sofirn_LT1S-Pro.c
diff options
context:
space:
mode:
Diffstat (limited to 'hwdef-Sofirn_LT1S-Pro.c')
-rw-r--r--hwdef-Sofirn_LT1S-Pro.c234
1 files changed, 175 insertions, 59 deletions
diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c
index 61d2157..a6d2b8f 100644
--- a/hwdef-Sofirn_LT1S-Pro.c
+++ b/hwdef-Sofirn_LT1S-Pro.c
@@ -5,68 +5,51 @@
#pragma once
-// single set of LEDs with 1 power channel and dynamic PWM
-void set_level_1ch_dyn(uint8_t level) {
- if (level == 0) {
- RED_PWM_LVL = 0;
- PWM_CNT = 0; // reset phase
- } else {
- level --; // PWM array index = level - 1
- RED_PWM_LVL = PWM_GET(pwm1_levels, level);
- // pulse frequency modulation, a.k.a. dynamic PWM
- PWM_TOP = PWM_GET(pwm_tops, level);
- // force reset phase when turning on from zero
- // (because otherwise the initial response is inconsistent)
- if (! actual_level) PWM_CNT = 0;
- }
-}
+// calculate a "tint ramp" blend between 2 channels
+// results are placed in *warm and *cool vars
+// brightness : total amount of light units to distribute
+// top : maximum allowed brightness per channel
+// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool)
+void calc_2ch_blend(
+ PWM_DATATYPE *warm,
+ PWM_DATATYPE *cool,
+ PWM_DATATYPE brightness,
+ PWM_DATATYPE top,
+ uint8_t blend) {
-
-// warm + cool blend w/ middle sag correction and dynamic PWM
-void set_level_2ch_dyn_blend(uint8_t level) {
#ifndef TINT_RAMPING_CORRECTION
#define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint
#endif
- if (level == 0) {
- WARM_PWM_LVL = 0;
- COOL_PWM_LVL = 0;
- PWM_CNT = 0; // reset phase
- return;
- }
-
- level --; // PWM array index = level - 1
- PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
- uint16_t top = PWM_GET(pwm_tops, level);
-
// calculate actual PWM levels based on a single-channel ramp
- // and a global tint value
- uint16_t warm_PWM, cool_PWM;
- uint8_t mytint = channel_mode_args[channel_mode];
-
+ // and a blend value
+ PWM_DATATYPE warm_PWM, cool_PWM;
PWM_DATATYPE2 base_PWM = brightness;
+
#if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0)
+ uint8_t level = actual_level - 1;
+
// middle tints sag, so correct for that effect
// by adding extra power which peaks at the middle tint
// (correction is only necessary when PWM is fast)
if (level > HALFSPEED_LEVEL) {
base_PWM = brightness
+ ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64)
- * triangle_wave(mytint) / 255);
+ * triangle_wave(blend) / 255);
}
// fade the triangle wave out when above 100% power,
// so it won't go over 200%
if (brightness > top) {
base_PWM -= 2 * (
((brightness - top) * TINT_RAMPING_CORRECTION / 64)
- * triangle_wave(mytint) / 255
+ * triangle_wave(blend) / 255
);
}
// guarantee no more than 200% power
if (base_PWM > (top << 1)) { base_PWM = top << 1; }
#endif
- cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255;
+ cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255;
warm_PWM = base_PWM - cool_PWM;
// when running at > 100% power, spill extra over to other channel
if (cool_PWM > top) {
@@ -77,6 +60,76 @@ void set_level_2ch_dyn_blend(uint8_t level) {
warm_PWM = top;
}
+ *warm = warm_PWM;
+ *cool = cool_PWM;
+}
+
+
+// calculate a 3-channel "auto tint" blend
+// (like red -> warm white -> cool white)
+// results are placed in *a, *b, and *c vars
+// level : ramp level to convert into 3 channel levels
+// (assumes ramp table is "pwm1_levels")
+void calc_auto_3ch_blend(
+ PWM_DATATYPE *a,
+ PWM_DATATYPE *b,
+ PWM_DATATYPE *c,
+ uint8_t level) {
+
+ PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level);
+
+ // tint goes from 0 (red) to 127 (warm white) to 255 (cool white)
+ uint8_t mytint;
+ mytint = 255 * (uint16_t)level / RAMP_SIZE;
+
+ // red is high at 0, low at 255 (linear)
+ *a = (((PWM_DATATYPE2)(255 - mytint)
+ * (PWM_DATATYPE2)vpwm) + 127) / 255;
+ // warm white is low at 0 and 255, high at 127 (linear triangle)
+ *b = (((PWM_DATATYPE2)triangle_wave(mytint)
+ * (PWM_DATATYPE2)vpwm) + 127) / 255;
+ // cool white is low at 0, high at 255 (linear)
+ *c = (((PWM_DATATYPE2)mytint
+ * (PWM_DATATYPE2)vpwm) + 127) / 255;
+
+}
+
+
+// single set of LEDs with 1 power channel and dynamic PWM
+void set_level_red(uint8_t level) {
+ if (level == 0) {
+ RED_PWM_LVL = 0;
+ PWM_CNT = 0; // reset phase
+ } else {
+ level --; // PWM array index = level - 1
+ RED_PWM_LVL = PWM_GET(pwm1_levels, level);
+ // pulse frequency modulation, a.k.a. dynamic PWM
+ PWM_TOP = PWM_GET(pwm_tops, level);
+ // force reset phase when turning on from zero
+ // (because otherwise the initial response is inconsistent)
+ if (! actual_level) PWM_CNT = 0;
+ }
+}
+
+
+// warm + cool blend w/ dynamic PWM
+void set_level_white_blend(uint8_t level) {
+ if (level == 0) {
+ WARM_PWM_LVL = 0;
+ COOL_PWM_LVL = 0;
+ PWM_CNT = 0; // reset phase
+ return;
+ }
+
+ level --; // PWM array index = level - 1
+
+ PWM_DATATYPE warm_PWM, cool_PWM;
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
+ PWM_DATATYPE top = PWM_GET(pwm_tops, level);
+ uint8_t blend = channel_mode_args[channel_mode];
+
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
+
WARM_PWM_LVL = warm_PWM;
COOL_PWM_LVL = cool_PWM;
PWM_TOP = top;
@@ -85,7 +138,7 @@ void set_level_2ch_dyn_blend(uint8_t level) {
// "auto tint" channel mode with dynamic PWM
-void set_level_auto_3ch_dyn_blend(uint8_t level) {
+void set_level_auto_3ch_blend(uint8_t level) {
if (level == 0) {
WARM_PWM_LVL = 0;
COOL_PWM_LVL = 0;
@@ -95,25 +148,12 @@ void set_level_auto_3ch_dyn_blend(uint8_t level) {
}
level --; // PWM array index = level - 1
- PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level);
- // pulse frequency modulation, a.k.a. dynamic PWM
- uint16_t top = PWM_GET(pwm_tops, level);
-
- // tint goes from 0 (red) to 127 (warm white) to 255 (cool white)
- uint8_t mytint;
- mytint = 255 * (uint16_t)level / RAMP_SIZE;
PWM_DATATYPE a, b, c;
+ calc_auto_3ch_blend(&a, &b, &c, level);
- // red is high at 0, low at 255
- a = (((PWM_DATATYPE2)(255 - mytint)
- * (PWM_DATATYPE2)vpwm) + 127) / 255;
- // warm white is low at 0 and 255, high at 127
- b = (((PWM_DATATYPE2)triangle_wave(mytint)
- * (PWM_DATATYPE2)vpwm) + 127) / 255;
- // cool white is low at 0, high at 255
- c = (((PWM_DATATYPE2)mytint
- * (PWM_DATATYPE2)vpwm) + 127) / 255;
+ // pulse frequency modulation, a.k.a. dynamic PWM
+ uint16_t top = PWM_GET(pwm_tops, level);
RED_PWM_LVL = a;
WARM_PWM_LVL = b;
@@ -127,10 +167,9 @@ void set_level_auto_3ch_dyn_blend(uint8_t level) {
void set_level_red_white_blend(uint8_t level) {
// set the warm+cool white LEDs first
channel_mode = CM_WHITE;
- set_level_2ch_dyn_blend(level);
+ set_level_white_blend(level);
channel_mode = CM_WHITE_RED;
- // set the red LED as a ratio of the white output level
if (level == 0) {
RED_PWM_LVL = 0;
PWM_CNT = 0; // reset phase
@@ -140,14 +179,91 @@ void set_level_red_white_blend(uint8_t level) {
level --; // PWM array index = level - 1
PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level);
+ // set the red LED as a ratio of the white output level
// 0 = no red
// 255 = red at 100% of white channel PWM
uint8_t ratio = channel_mode_args[channel_mode];
- PWM_DATATYPE red_pwm;
- red_pwm = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255;
-
- RED_PWM_LVL = red_pwm;
+ RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255;
if (! actual_level) PWM_CNT = 0; // reset phase
}
+
+///// "gradual tick" functions for smooth thermal regulation /////
+
+void gradual_tick_red() {
+ GRADUAL_TICK_SETUP();
+
+ GRADUAL_ADJUST_1CH(pwm1_levels, RED_PWM_LVL);
+
+ if ((RED_PWM_LVL == PWM_GET(pwm1_levels, gt)))
+ {
+ GRADUAL_IS_ACTUAL();
+ }
+}
+
+
+void gradual_tick_white_blend() {
+ uint8_t gt = gradual_target;
+ if (gt < actual_level) gt = actual_level - 1;
+ else if (gt > actual_level) gt = actual_level + 1;
+ gt --;
+
+ // figure out what exact PWM levels we're aiming for
+ PWM_DATATYPE warm_PWM, cool_PWM;
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt);
+ PWM_DATATYPE top = PWM_GET(pwm_tops, gt);
+ uint8_t blend = channel_mode_args[channel_mode];
+
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
+
+ // move up/down if necessary
+ GRADUAL_ADJUST_SIMPLE(warm_PWM, WARM_PWM_LVL);
+ GRADUAL_ADJUST_SIMPLE(cool_PWM, COOL_PWM_LVL);
+
+ // check for completion
+ if ( (WARM_PWM_LVL == warm_PWM)
+ && (COOL_PWM_LVL == cool_PWM)
+ )
+ {
+ GRADUAL_IS_ACTUAL();
+ }
+}
+
+
+void gradual_tick_auto_3ch_blend() {
+ uint8_t gt = gradual_target;
+ if (gt < actual_level) gt = actual_level - 1;
+ else if (gt > actual_level) gt = actual_level + 1;
+ gt --;
+
+ // figure out what exact PWM levels we're aiming for
+ PWM_DATATYPE red, warm, cool;
+ calc_auto_3ch_blend(&red, &warm, &cool, gt);
+
+ // move up/down if necessary
+ GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL);
+ GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL);
+ GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL);
+
+ // check for completion
+ if ( (RED_PWM_LVL == red)
+ && (WARM_PWM_LVL == warm)
+ && (COOL_PWM_LVL == cool)
+ )
+ {
+ GRADUAL_IS_ACTUAL();
+ }
+}
+
+
+void gradual_tick_red_white_blend() {
+ // do the white blend thing...
+ channel_mode = CM_WHITE;
+ gradual_tick_white_blend();
+ channel_mode = CM_WHITE_RED;
+ // ... and then update red to the closest ramp level
+ // (coarse red adjustments aren't visible here anyway)
+ set_level_red(actual_level);
+}
+