2 #include <avr/eeprom.h>
6 #define AMBIENT_FAST_SHIFT 2 // running avg of ADC vals
7 #define AMBIENT_SLOW_SHIFT 6 // 1 << AMBIENT_SLOW_SHIFT times slower
9 static uint16_t ambient_fast, ambient_slow;
10 volatile unsigned char ambient_zone, ambient_shadow;
11 static unsigned char ambient_min, ambient_max, ambient_drop;
14 #define AMBIENT_LOG_SIZE 256
15 static unsigned char ambient_log_offset_stored EEMEM;
16 static unsigned char ambient_log_offset;
17 static unsigned char ambient_log[AMBIENT_LOG_SIZE] EEMEM;
19 /* My photodiode reads 0x00C5 .. 0x033B */
21 uint16_t lo, hi; // TODO: consider changing this to bytes
25 * Note: these have to be sorted, starting with 0, ending with 0xFFFF
26 * and having small overlaps in order to provide a bit of hysteresis.
28 static ambient_zone_t ambient_zones[N_AMBIENT_ZONES] = {
30 { 0x0000, 0x02d0 }, // dark
31 { 0x02b0, 0x0318 }, // evening
32 { 0x0308, 0x032c }, // dawn
33 { 0x0324, 0xffff }, // day
35 { 0x0000, 0x0250 }, // dark
36 { 0x0230, 0x02e8 }, // evening
37 { 0x02d0, 0x0302 }, // dawn
38 { 0x02fc, 0xffff }, // day
42 #define SHADOW_DROP_LIMIT 0x20 // in ADC units (0..0x3ff)
54 ambient_log_offset = eeprom_read_byte(&ambient_log_offset_stored);
56 if (ambient_log_offset == AMBIENT_LOG_SIZE)
57 ambient_log_offset = 0; // start over
62 unsigned char stored_offset;
64 ambient_log_min_max();
66 stored_offset = eeprom_read_byte(&ambient_log_offset_stored);
67 if (stored_offset != ambient_log_offset)
68 eeprom_write_byte(&ambient_log_offset_stored,
72 void ambient_log_min_max()
74 if (ambient_log_offset >= AMBIENT_LOG_SIZE - 1)
75 ambient_log_offset = 0; // start over
77 ambient_max -= ambient_min;
83 if (ambient_drop > 15)
86 eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_min);
87 eeprom_write_byte(&ambient_log[ambient_log_offset++],
88 (ambient_max << 4) | ambient_drop);
95 static inline void ambient_zone_changed()
97 pwmled_select_brightness();
101 static unsigned char val_to_zone(uint16_t ambient_val)
103 unsigned char new_zone = ambient_zone;
105 if (new_zone >= N_AMBIENT_ZONES)
106 new_zone = N_AMBIENT_ZONES-1;
108 while (ambient_zones[new_zone].lo > ambient_val)
111 while (ambient_zones[new_zone].hi < ambient_val)
117 void ambient_adc(uint16_t adcval)
119 unsigned char new_zone, user_zone, new_shadow = 0;
120 unsigned char byte_fast, byte_slow, drop;
121 uint16_t fast_10bit, slow_10bit;
123 // running avg - shorter timespan
124 ambient_fast += adcval - (ambient_fast >> AMBIENT_FAST_SHIFT);
126 // running avg - longer timespan
127 fast_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT);
128 ambient_slow += fast_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT);
130 // ambient zones are governed by shorter timespan by default
131 new_zone = val_to_zone(fast_10bit);
133 slow_10bit = ambient_slow >> AMBIENT_SLOW_SHIFT;
135 if ((new_zone > ambient_zone)
136 || (new_zone > 1 && new_zone == ambient_zone - 1)) {
137 // but change to the neighbouring zone is governed by _slow,
138 // except to the darkest zone, where we want fast reaction.
139 new_zone = val_to_zone(slow_10bit);
142 // user_param ambient zone override
143 if ((user_zone = get_user_param(0)) > 0)
144 new_zone = user_zone - 1;
146 #if 0 // ignore shadow-entering code altogether for now
147 // are we entering the shadow?
148 if (!user_zone && new_zone < ambient_zone
149 && ambient_zone >= 2 && slow_10bit > fast_10bit
150 && slow_10bit - fast_10bit >= SHADOW_DROP_LIMIT) {
151 // we are entering the shadow
155 if (ambient_shadow) {
157 new_zone = ambient_zone; // don't change while entering shadow
158 ambient_shadow = new_shadow; // update the timeout
161 if (!ambient_shadow) { // leaving the shadow
162 ambient_zone_changed();
165 } else if (new_shadow) {
166 ambient_shadow = new_shadow; // set up the timeout
167 new_zone = ambient_zone; // don't change while entering shadow
168 ambient_zone_changed(); // notify others the first time
172 // TODO: maybe use these values instead of 10-bit?
173 byte_fast = fast_10bit >> 2;
174 byte_slow = slow_10bit >> 2;
176 if (byte_slow > byte_fast) {
177 drop = byte_slow - byte_fast;
178 if (drop > ambient_drop)
182 if (ambient_min > byte_slow)
183 ambient_min = byte_slow;
185 if (ambient_max < byte_slow)
186 ambient_max = byte_slow;
188 if (new_zone != ambient_zone) {
189 ambient_zone = new_zone;
192 log_byte(ambient_zone);
196 ambient_zone_changed();