~toykeeper/flashlight-firmware/trunk

« back to all changes in this revision

Viewing changes to ToyKeeper/spaghetti-monster/fsm-ramping.c

  • Committer: Selene Scriven
  • Date: 2018-07-05 10:22:48 UTC
  • mto: This revision was merged to the branch mainline in revision 209.
  • Revision ID: bzr@toykeeper.net-20180705102248-4157s7ly7ascx0w3
Forked Bistro as a base for Dragon.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * fsm-ramping.c: Ramping functions for SpaghettiMonster.
3
 
 * Handles 1- to 4-channel smooth ramping on a single LED.
4
 
 *
5
 
 * Copyright (C) 2017 Selene Scriven
6
 
 *
7
 
 * This program is free software: you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation, either version 3 of the License, or
10
 
 * (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
 */
20
 
 
21
 
#ifndef FSM_RAMPING_C
22
 
#define FSM_RAMPING_C
23
 
 
24
 
#ifdef USE_RAMPING
25
 
 
26
 
void set_level(uint8_t level) {
27
 
    actual_level = level;
28
 
 
29
 
    #ifdef USE_SET_LEVEL_GRADUALLY
30
 
    gradual_target = level;
31
 
    #endif
32
 
 
33
 
    #ifdef USE_INDICATOR_LED_WHILE_RAMPING
34
 
        #ifdef USE_INDICATOR_LED
35
 
        if (! go_to_standby)
36
 
            indicator_led((level > 0) + (level > MAX_1x7135));
37
 
        #endif
38
 
        //if (level > MAX_1x7135) indicator_led(2);
39
 
        //else if (level > 0) indicator_led(1);
40
 
        //else if (! go_to_standby) indicator_led(0);
41
 
    #else
42
 
        #if defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)
43
 
        if (! go_to_standby) {
44
 
            #ifdef USE_INDICATOR_LED
45
 
                indicator_led(0);
46
 
            #endif
47
 
            #ifdef USE_AUX_RGB_LEDS
48
 
                rgb_led_set(0);
49
 
                #ifdef USE_BUTTON_LED
50
 
                    button_led_set((level > 0) + (level > MAX_1x7135));
51
 
                #endif
52
 
            #endif
53
 
        }
54
 
        #endif
55
 
    #endif
56
 
 
57
 
    //TCCR0A = PHASE;
58
 
    if (level == 0) {
59
 
        #if PWM_CHANNELS >= 1
60
 
        PWM1_LVL = 0;
61
 
        #endif
62
 
        #if PWM_CHANNELS >= 2
63
 
        PWM2_LVL = 0;
64
 
        #endif
65
 
        #if PWM_CHANNELS >= 3
66
 
        PWM3_LVL = 0;
67
 
        #endif
68
 
        #if PWM_CHANNELS >= 4
69
 
        PWM4_LVL = 0;
70
 
        #endif
71
 
        // disable the power channel, if relevant
72
 
        #ifdef LED_ENABLE_PIN
73
 
        LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN);
74
 
        #endif
75
 
        #ifdef LED_ENABLE2_PIN
76
 
        LED_ENABLE2_PORT &= ~(1 << LED_ENABLE2_PIN);
77
 
        #endif
78
 
    } else {
79
 
        level --;
80
 
 
81
 
        // enable the power channel, if relevant
82
 
        #ifdef LED_ENABLE_PIN
83
 
        LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN);
84
 
        #endif
85
 
        #ifdef LED_ENABLE2_PIN
86
 
        LED_ENABLE2_PORT |= (1 << LED_ENABLE2_PIN);
87
 
        #endif
88
 
 
89
 
        #ifdef USE_TINT_RAMPING
90
 
        #ifndef TINT_RAMPING_CORRECTION
91
 
        #define TINT_RAMPING_CORRECTION 26  // 140% brightness at middle tint
92
 
        #endif
93
 
        // calculate actual PWM levels based on a single-channel ramp
94
 
        // and a global tint value
95
 
        uint8_t brightness = PWM_GET(pwm1_levels, level);
96
 
        uint8_t warm_PWM, cool_PWM;
97
 
 
98
 
        // auto-tint modes
99
 
        uint8_t mytint;
100
 
        #if 1
101
 
        // perceptual by ramp level
102
 
        if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; }
103
 
        else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); }
104
 
        #else
105
 
        // linear with power level
106
 
        //if (tint == 0) { mytint = brightness; }
107
 
        //else if (tint == 255) { mytint = 255 - brightness; }
108
 
        #endif
109
 
        // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198)
110
 
        else { mytint = (tint * 100 / 99) - 1; }
111
 
 
112
 
        // middle tints sag, so correct for that effect
113
 
        uint16_t base_PWM = brightness;
114
 
        // correction is only necessary when PWM is fast
115
 
        if (level > HALFSPEED_LEVEL) {
116
 
            base_PWM = brightness
117
 
                     + ((((uint16_t)brightness) * TINT_RAMPING_CORRECTION / 64) * triangle_wave(mytint) / 255);
118
 
        }
119
 
 
120
 
        cool_PWM = (((uint16_t)mytint * (uint16_t)base_PWM) + 127) / 255;
121
 
        warm_PWM = base_PWM - cool_PWM;
122
 
 
123
 
        PWM1_LVL = warm_PWM;
124
 
        PWM2_LVL = cool_PWM;
125
 
        #else
126
 
 
127
 
        #if PWM_CHANNELS >= 1
128
 
        PWM1_LVL = PWM_GET(pwm1_levels, level);
129
 
        #endif
130
 
        #if PWM_CHANNELS >= 2
131
 
        PWM2_LVL = PWM_GET(pwm2_levels, level);
132
 
        #endif
133
 
        #if PWM_CHANNELS >= 3
134
 
        PWM3_LVL = PWM_GET(pwm3_levels, level);
135
 
        #endif
136
 
        #if PWM_CHANNELS >= 4
137
 
        PWM4_LVL = PWM_GET(pwm4_levels, level);
138
 
        #endif
139
 
 
140
 
        #endif  // ifdef USE_TINT_RAMPING
141
 
    }
142
 
    #ifdef USE_DYNAMIC_UNDERCLOCKING
143
 
    auto_clock_speed();
144
 
    #endif
145
 
}
146
 
 
147
 
#ifdef USE_SET_LEVEL_GRADUALLY
148
 
inline void set_level_gradually(uint8_t lvl) {
149
 
    gradual_target = lvl;
150
 
}
151
 
 
152
 
// call this every frame or every few frames to change brightness very smoothly
153
 
void gradual_tick() {
154
 
    // go by only one ramp level at a time instead of directly to the target
155
 
    uint8_t gt = gradual_target;
156
 
    if (gt < actual_level) gt = actual_level - 1;
157
 
    else if (gt > actual_level) gt = actual_level + 1;
158
 
 
159
 
    gt --;  // convert 1-based number to 0-based
160
 
 
161
 
    PWM_DATATYPE target;
162
 
 
163
 
    #if PWM_CHANNELS >= 1
164
 
    target = PWM_GET(pwm1_levels, gt);
165
 
    if ((gt < actual_level)     // special case for FET-only turbo
166
 
            && (PWM1_LVL == 0)  // (bypass adjustment period for first step)
167
 
            && (target == PWM_TOP)) PWM1_LVL = PWM_TOP;
168
 
    else if (PWM1_LVL < target) PWM1_LVL ++;
169
 
    else if (PWM1_LVL > target) PWM1_LVL --;
170
 
    #endif
171
 
    #if PWM_CHANNELS >= 2
172
 
    target = PWM_GET(pwm2_levels, gt);
173
 
    if (PWM2_LVL < target) PWM2_LVL ++;
174
 
    else if (PWM2_LVL > target) PWM2_LVL --;
175
 
    #endif
176
 
    #if PWM_CHANNELS >= 3
177
 
    target = PWM_GET(pwm3_levels, gt);
178
 
    if (PWM3_LVL < target) PWM3_LVL ++;
179
 
    else if (PWM3_LVL > target) PWM3_LVL --;
180
 
    #endif
181
 
    #if PWM_CHANNELS >= 4
182
 
    target = PWM_GET(pwm4_levels, gt);
183
 
    if (PWM4_LVL < target) PWM4_LVL ++;
184
 
    else if (PWM4_LVL > target) PWM4_LVL --;
185
 
    #endif
186
 
 
187
 
    // did we go far enough to hit the next defined ramp level?
188
 
    // if so, update the main ramp level tracking var
189
 
    if ((PWM1_LVL == PWM_GET(pwm1_levels, gt))
190
 
        #if PWM_CHANNELS >= 2
191
 
            && (PWM2_LVL == PWM_GET(pwm2_levels, gt))
192
 
        #endif
193
 
        #if PWM_CHANNELS >= 3
194
 
            && (PWM3_LVL == PWM_GET(pwm3_levels, gt))
195
 
        #endif
196
 
        #if PWM_CHANNELS >= 4
197
 
            && (PWM4_LVL == PWM_GET(pwm4_levels, gt))
198
 
        #endif
199
 
        )
200
 
    {
201
 
        actual_level = gt + 1;
202
 
    }
203
 
}
204
 
#endif
205
 
 
206
 
#endif  // ifdef USE_RAMPING
207
 
#endif