#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(0xF4); log_byte(n); 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(0xF1); log_byte(n); return; } if (pwm >= 0x70) { // over the maximum! pwm_off(n); pwmled_state[n] = ST_DISABLED; log_byte(0xF2); log_byte(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? } }