]> www.fi.muni.cz Git - bike-lights.git/blobdiff - pwmled.c
lights.c split into more modules
[bike-lights.git] / pwmled.c
diff --git a/pwmled.c b/pwmled.c
new file mode 100644 (file)
index 0000000..4861793
--- /dev/null
+++ b/pwmled.c
@@ -0,0 +1,180 @@
+#include <avr/io.h>
+
+#include "lights.h"
+
+static unsigned char pwm_vals[N_PWMLEDS*N_PWMLED_MODES];
+static unsigned char adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
+       /* pwmled0 */
+       0x04, 0x14, 0x24, 0x38,
+       /* pwmled1 */
+       0x04, 0x14, 0x24, 0x38,
+       /* pwmled2 */
+       0x04, 0x14, 0x24, 0x38,
+};
+
+static unsigned char pwmled_state[N_PWMLEDS];
+#define ST_DISABLED 0
+#define ST_PROBING  1
+#define ST_OFF      2
+#define ST_ON       3
+
+static unsigned char pwmled_mode[N_PWMLEDS];
+
+static unsigned char pwm_probes[N_PWMLEDS];
+
+static void start_probing(unsigned char n)
+{
+       pwmled_state[n] = ST_PROBING;
+       pwm_set(n, 0);
+       pwm_on(n);
+       pwm_probes[n] = 0;
+}
+
+void pwmled_init()
+{
+       unsigned char i;
+
+       for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++)
+               pwm_vals[i] = 0;
+
+       for (i = 0; i < N_PWMLEDS; i++) {
+               start_probing(i);
+       }
+}
+
+unsigned char pwmled_is_on(unsigned char n)
+{
+       unsigned char st = pwmled_state[n];
+       if (st == ST_PROBING || st == ST_ON)
+               return 1;
+       else
+               return 0;
+}
+
+static void inline probing_adc(unsigned char n, uint16_t adcval)
+{
+       unsigned char need_bigger = 0, i;
+       unsigned char *pwm_p = &pwm_vals[n*N_PWMLED_MODES];
+       unsigned char *adc_p = &adc_vals[n*N_PWMLED_MODES];
+       unsigned char pwm = pwm_probes[n];
+
+#if 0
+       log_byte(n);
+       log_byte(0xF4);
+       log_word(adcval);
+#endif
+
+#if 0
+       if (pwm == 0 && adcval > 0) { // non-zero voltage with zero PWM?
+               pwmled_state[n] = ST_DISABLED;
+               log_byte(n);
+               log_byte(0xF0);
+               log_word(adcval);
+               return;
+       }
+#endif
+
+       for (i = 0; i < N_PWMLED_MODES; i++, pwm_p++, adc_p++) {
+               uint16_t adc = *adc_p;
+               if (adc >= adcval) {
+                       *pwm_p = pwm;
+                       need_bigger = 1;
+               }
+       }
+
+#if 0
+       if ((n == 1 && pwm > 0x35) || adcval != 0) {
+               log_byte(n);
+               log_byte(0xF3);
+               log_byte(pwm);
+               log_word(adcval);
+       }
+#endif
+
+       if (!need_bigger) { // successfully probed
+               pwm_off(n);
+               // pwm_set(n, 0);
+               pwmled_state[n] = ST_OFF;
+               log_byte(n);
+               log_byte(0xF1);
+
+               return;
+       }
+
+       if (pwm >= 0x60) { // over the maximum!
+               pwmled_state[n] = ST_DISABLED;
+               log_byte(n);
+               log_byte(0xF2);
+               pwm_off(n);
+               // pwm_set(n, 0);
+               return;
+       }
+
+       // try to increase
+       pwm++;
+       pwm_probes[n] = pwm;
+       pwm_set(n, pwm);
+}
+
+// Feedback loop
+static void inline on_adc(unsigned char n, uint16_t adcval)
+{
+#if 0
+       uint16_t new_pwm = led_modes[led_mode].pwmval;
+       uint16_t old_pwm = new_pwm;
+       uint16_t adc_exp = led_modes[led_mode].expected;
+
+       log_word(((adcval & 0xFF) << 8) | old_pwm);
+
+       if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly
+               new_pwm = 2*old_pwm/3;
+       } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit
+               new_pwm = old_pwm - 1;
+       } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit
+               new_pwm = old_pwm + 1;
+       }
+
+       if (new_pwm > 0x60) { // odpojeno?
+               new_pwm = 0x60;
+       }
+       if (new_pwm < 2) { // zkrat?
+               new_pwm = 2;
+       }
+
+set_pwm:
+       if (new_pwm != old_pwm) {
+               led_modes[led_mode].pwmval = new_pwm;
+               OCR1D = new_pwm;
+       }
+       // ADCSRA |= _BV(ADSC);
+#endif
+}
+
+void pwmled_adc(unsigned char n, uint16_t adcval)
+{
+       unsigned char i, probing;
+       switch (pwmled_state[n]) {
+       case ST_PROBING:
+               probing_adc(n, adcval);
+
+               probing = 0;
+               for (i = 0; i < N_PWMLEDS; i++)
+                       if (pwmled_state[i] == ST_PROBING)
+                               probing = 1;
+
+               if (!probing) {
+                       for (i = 0; i < N_PWMLEDS; i++)
+                               log_byte(pwmled_state[i]);
+                               
+                       for (i = 0; i < N_PWMLEDS*N_PWMLED_MODES; i++)
+                               log_byte(pwm_vals[i]);
+                       log_flush();
+               }
+               
+               return;
+       case ST_ON:
+               on_adc(n, adcval);
+               return;
+       // WTF am I doing in this function then?
+       }
+}