]> www.fi.muni.cz Git - bike-lights.git/blob - firmware/main.c
9fdc2fb95bde5c3418f732b1bf9f1204da4d0432
[bike-lights.git] / firmware / main.c
1 #include <avr/io.h>
2 #include <util/delay.h>
3 #include <util/atomic.h>
4 #include <avr/sleep.h>
5 #include <avr/interrupt.h>
6 #include <avr/power.h>
7 #include <avr/wdt.h>
8
9 #include "lights.h"
10
11 static unsigned char prev_jiffies_8;
12
13 static void hw_setup()
14 {
15         init_battery();
16         init_pwm();
17         init_adc();
18         init_tmr();
19         init_buttons();
20
21         init_pwmled();
22         init_gpio();
23         init_ambient();
24         init_pattern();
25         init_control();
26
27         set_sleep_mode(SLEEP_MODE_IDLE);
28 }
29
30 static void inline hw_suspend()
31 {
32         susp_pwm();
33         susp_adc();
34         susp_tmr();
35         susp_gpio();
36         susp_ambient();
37         susp_buttons();
38 }
39
40 void power_down(unsigned char err)
41 {
42         hw_suspend();
43
44         do {
45                 if (err)
46                         gpio_set(0, 1);
47
48                 // G'night
49                 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
50                 sleep_enable();
51                 sleep_bod_disable();
52                 sei();
53                 sleep_cpu();
54
55                 // G'morning
56                 cli();
57                 sleep_disable();
58
59                 // allow wakeup by long button-press only
60         } while (!buttons_wait_for_release());
61
62         // ok, so I will wake up
63         hw_setup();
64 }
65
66 static void inline first_boot()
67 {
68         unsigned char mcusr_save;
69
70         // disable the WDT if running
71         wdt_reset();
72         mcusr_save = MCUSR;
73         MCUSR = 0;
74         wdt_disable();
75
76         if (mcusr_save & _BV(WDRF)) // was watchdog reset?
77                 gpio_set(0, 1);
78
79         init_log(mcusr_save);
80
81         power_usi_disable(); // Once for lifetime
82         ACSRA |= _BV(ACD);   // disable analog comparator
83
84         log_set_state(3);
85
86         hw_setup();
87         power_down(mcusr_save & _BV(WDRF));
88
89         prev_jiffies_8 = jiffies;
90
91         sei();
92 }
93
94 static void inline do_timer()
95 {
96         // For now, we run them all in their own atomic blocks
97         ATOMIC_BLOCK(ATOMIC_FORCEON) {
98                 timer_check_buttons();
99         }
100         ATOMIC_BLOCK(ATOMIC_FORCEON) {
101                 patterns_next_tick();
102         }
103         ATOMIC_BLOCK(ATOMIC_FORCEON) {
104                 pwm_disable_if_not_needed();
105         }
106         ATOMIC_BLOCK(ATOMIC_FORCEON) {
107                 timer_start_slow_adcs();
108         }
109         ATOMIC_BLOCK(ATOMIC_FORCEON) {
110                 if ((jiffies & 0x3FF) == 0)
111                         ambient_log_min_max();
112         }
113 }
114
115 static void inline main_loop_iteration()
116 {
117         unsigned char jiffies_8; /*
118                                   * we use only lower 8-bits in order to
119                                   * avoid the need for locking of 16-bit
120                                   * accesses.
121                                   */
122
123         cli();
124         if (TIMER1_IS_ON()) {
125                 set_sleep_mode(SLEEP_MODE_IDLE);
126         } else if (adc_is_on) {
127                 set_sleep_mode(SLEEP_MODE_ADC);
128         } else {
129                 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
130         }
131
132         sleep_enable();
133         // keep BOD active, no sleep_bod_disable();
134         sei();
135         sleep_cpu();
136         sleep_disable();
137
138         jiffies_8 = jiffies;
139
140         if (jiffies_8 != prev_jiffies_8) { // was timer IRQ
141                 if (jiffies_8 - prev_jiffies_8 > 1) { // overrun
142                         log_byte(0xee);
143                         log_byte(jiffies_8 - prev_jiffies_8);
144                         log_flush();
145                 }
146
147                 prev_jiffies_8 = jiffies_8;
148
149                 do_timer();
150         }
151 }
152
153 int main(void)
154 {
155         first_boot();
156
157         while (1)
158                 main_loop_iteration();
159
160 #if 0
161         DDRB |= _BV(PB2);
162         while (1) {
163                 PORTB |=  _BV( PB2 );
164                 _delay_ms(200);
165                 PORTB &=~ _BV( PB2 );
166                 _delay_ms(200);
167         }
168 #endif
169 }