]> www.fi.muni.cz Git - bike-lights.git/blob - pwmled.c
5c816b3351e4b3077f46084baa6cdb5d3045f6da
[bike-lights.git] / pwmled.c
1 #include <avr/io.h>
2
3 #include "lights.h"
4
5 static unsigned char pwm_vals[N_PWMLEDS*N_PWMLED_MODES];
6 static unsigned char adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
7         /* pwmled0 */
8         0x04, 0x14, 0x24, 0x38,
9         /* pwmled1 */
10         0x04, 0x14, 0x24, 0x38,
11         /* pwmled2 */
12         0x04, 0x14, 0x24, 0x38,
13 };
14
15 // TODO: maybe convert this to bitmask to simplify pwmled_needs_adc() ?
16 static unsigned char pwmled_state[N_PWMLEDS];
17 #define ST_DISABLED 0
18 #define ST_PROBING  1
19 #define ST_OFF      2
20 #define ST_ON       3
21
22 static unsigned char pwmled_mode[N_PWMLEDS];
23
24 static unsigned char pwm_probes[N_PWMLEDS];
25
26 static void start_probing(unsigned char n)
27 {
28         pwmled_state[n] = ST_PROBING;
29         pwm_set(n, 0);
30         pwm_on(n);
31         pwm_probes[n] = 0;
32 }
33
34 void pwmled_init()
35 {
36         unsigned char i;
37
38         for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++)
39                 pwm_vals[i] = 0;
40
41         for (i = 0; i < N_PWMLEDS; i++) {
42                 start_probing(i);
43         }
44 }
45
46 unsigned char pwmled_needs_adc(unsigned char n)
47 {
48         unsigned char st = pwmled_state[n];
49         if (st == ST_PROBING || st == ST_ON)
50                 return 1;
51         else
52                 return 0;
53 }
54
55 unsigned char pwmled_enabled(unsigned char n)
56 {
57         unsigned char st = pwmled_state[n];
58         if (st == ST_OFF || st == ST_ON)
59                 return 1;
60         else
61                 return 0;
62 }
63
64 void pwmled_set_mode(unsigned char n, unsigned char mode)
65 {
66         if (!pwmled_enabled(n))
67                 return;
68
69         if (mode == 0) {
70                 pwm_off(n);
71                 pwmled_state[n] = ST_OFF;
72                 return;
73         }
74
75         if (mode <= N_PWMLED_MODES) {
76                 mode--;
77                 pwm_set(n, pwm_vals[n*N_PWMLED_MODES+mode]);
78                 pwmled_state[n] = ST_ON;
79                 pwmled_mode[n] = mode;
80         }
81 }
82
83 static void inline probing_adc(unsigned char n, uint16_t adcval)
84 {
85         unsigned char need_bigger = 0, i;
86         unsigned char *pwm_p = &pwm_vals[n*N_PWMLED_MODES];
87         unsigned char *adc_p = &adc_vals[n*N_PWMLED_MODES];
88         unsigned char pwm = pwm_probes[n];
89
90 #if 0
91         log_byte(0xF4);
92         log_byte(n);
93         log_word(adcval);
94 #endif
95
96 #if 0
97         if (pwm == 0 && adcval > 0) { // non-zero voltage with zero PWM?
98                 pwmled_state[n] = ST_DISABLED;
99                 log_byte(n);
100                 log_byte(0xF0);
101                 log_word(adcval);
102                 return;
103         }
104 #endif
105
106         for (i = 0; i < N_PWMLED_MODES; i++, pwm_p++, adc_p++) {
107                 uint16_t adc = *adc_p;
108                 if (adc >= adcval) {
109                         *pwm_p = pwm;
110                         need_bigger = 1;
111                 }
112         }
113
114 #if 0
115         if ((n == 1 && pwm > 0x35) || adcval != 0) {
116                 log_byte(n);
117                 log_byte(0xF3);
118                 log_byte(pwm);
119                 log_word(adcval);
120         }
121 #endif
122
123         if (!need_bigger) { // successfully probed
124                 pwm_off(n);
125                 // pwm_set(n, 0);
126                 pwmled_state[n] = ST_OFF;
127                 log_byte(0xF1);
128                 log_byte(n);
129
130                 return;
131         }
132
133         if (pwm >= 0x70) { // over the maximum!
134                 pwm_off(n);
135                 pwmled_state[n] = ST_DISABLED;
136                 log_byte(0xF2);
137                 log_byte(n);
138                 // pwm_set(n, 0);
139                 return;
140         }
141
142         // try to increase
143         pwm++;
144         pwm_probes[n] = pwm;
145         pwm_set(n, pwm);
146 }
147
148 // Feedback loop
149 static void inline on_adc(unsigned char n, uint16_t adcval)
150 {
151 #if 0
152         uint16_t new_pwm = led_modes[led_mode].pwmval;
153         uint16_t old_pwm = new_pwm;
154         uint16_t adc_exp = led_modes[led_mode].expected;
155
156         log_word(((adcval & 0xFF) << 8) | old_pwm);
157
158         if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly
159                 new_pwm = 2*old_pwm/3;
160         } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit
161                 new_pwm = old_pwm - 1;
162         } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit
163                 new_pwm = old_pwm + 1;
164         }
165
166         if (new_pwm > 0x60) { // odpojeno?
167                 new_pwm = 0x60;
168         }
169         if (new_pwm < 2) { // zkrat?
170                 new_pwm = 2;
171         }
172
173 set_pwm:
174         if (new_pwm != old_pwm) {
175                 led_modes[led_mode].pwmval = new_pwm;
176                 OCR1D = new_pwm;
177         }
178         // ADCSRA |= _BV(ADSC);
179 #endif
180 }
181
182 void pwmled_adc(unsigned char n, uint16_t adcval)
183 {
184         unsigned char i, probing;
185         switch (pwmled_state[n]) {
186         case ST_PROBING:
187                 probing_adc(n, adcval);
188
189                 probing = 0;
190                 for (i = 0; i < N_PWMLEDS; i++)
191                         if (pwmled_state[i] == ST_PROBING)
192                                 probing = 1;
193
194                 if (!probing) {
195                         for (i = 0; i < N_PWMLEDS; i++)
196                                 log_byte(pwmled_state[i]);
197                                 
198                         for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++)
199                                 log_byte(pwm_vals[i]);
200                         log_flush();
201                 }
202                 
203                 return;
204         case ST_ON:
205                 on_adc(n, adcval);
206                 return;
207         // WTF am I doing in this function then?
208         }
209 }