X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pwmled.c;fp=pwmled.c;h=4861793ff0fbd0e625df98830bf77e816279bd23;hb=4b93ea55987c25fcce022403a505ca1749dc329c;hp=0000000000000000000000000000000000000000;hpb=1647725c8e3e1297a330e5ab18ad6033fec807dd;p=bike-lights.git diff --git a/pwmled.c b/pwmled.c new file mode 100644 index 0000000..4861793 --- /dev/null +++ b/pwmled.c @@ -0,0 +1,180 @@ +#include + +#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? + } +}