1 | #include <avr/sleep.h>
|
2 | #include <avr/interrupt.h>
|
3 | #include <avr/io.h>
|
4 |
|
5 | static event equeue[EVQUEUESIZE];
|
6 | volatile static uint8_t eqhead = 0;
|
7 | static uint8_t eqtail = 0;
|
8 |
|
9 | static uint8_t ticksEnabled = 0;
|
10 |
|
11 | typedef struct evhdl_record
|
12 | {
|
13 | ev_handler handler;
|
14 | ev_filter filter;
|
15 | void *data;
|
16 | } evhdl_record;
|
17 |
|
18 | typedef struct evhdl_vector
|
19 | {
|
20 | uint8_t nhandlers;
|
21 | evhdl_record handlers[MAXEVHANDLERS];
|
22 | } evhdl_vector;
|
23 |
|
24 | static evhdl_vector handlervector[NUMEVTYPES];
|
25 |
|
26 | void event_init(void)
|
27 | {
|
28 | /* configure interrupts: */
|
29 | GIMSK |= _BV(PCIE1);
|
30 | PCMSK1 |= _BV(PCINT8) | _BV(PCINT9) | _BV(PCINT10);
|
31 | TIMSK1 |= _BV(OCIE1A);
|
32 |
|
33 | /* power management, disable unused stuff: */
|
34 | PRR |= _BV(PRTIM1) | _BV(PRTIM0) | _BV(PRUSI) | _BV(PRADC);
|
35 | MCUCR &= ~(_BV(BODS) | _BV(BODSE));
|
36 | MCUCR |= _BV(BODS);
|
37 | MCUCR &= ~_BV(BODSE);
|
38 | set_sleep_mode(SLEEP_MODE_PWR_SAVE);
|
39 | sleep_enable();
|
40 | }
|
41 |
|
42 | void event_raise(ev_type type, uint8_t ev_data)
|
43 | {
|
44 | cli();
|
45 | equeue[eqhead].type = type;
|
46 | equeue[eqhead].data = ev_data;
|
47 | if (++eqhead == EVQUEUESIZE) eqhead = 0;
|
48 | sei();
|
49 | }
|
50 |
|
51 | static void enableTicks(void)
|
52 | {
|
53 | if (ticksEnabled++) return;
|
54 | PRR &= ~_BV(PRTIM1);
|
55 | GTCCR |= _BV(TSM) | _BV(PSR10);
|
56 | // TCCR1B = _BV(WGM12) | _BV(CS10) | _BV(CS11); /* CTC, 8MHz / 64 */
|
57 | TCCR1B = _BV(WGM12) | _BV(CS11); /* CTC, 1MHz / 8 */
|
58 | OCR1A = 1250; /* 10 ms */
|
59 | TCNT1 = 0;
|
60 | GTCCR &= ~_BV(TSM);
|
61 | }
|
62 |
|
63 | static void disableTicks(void)
|
64 | {
|
65 | if (ticksEnabled && --ticksEnabled) return;
|
66 | GTCCR |= _BV(TSM) | _BV(PSR10);
|
67 | TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
|
68 | GTCCR &= ~_BV(TSM);
|
69 | PRR |= _BV(PRTIM1);
|
70 | }
|
71 |
|
72 | BOOL event_register(ev_type type, ev_handler handler,
|
73 | ev_filter filter, void *data)
|
74 | {
|
75 | for (uint8_t i = 0; i < MAXEVHANDLERS; ++i)
|
76 | {
|
77 | if (handlervector[type].handlers[i].handler)
|
78 | {
|
79 | if (handlervector[type].handlers[i].handler == handler
|
80 | && handlervector[type].handlers[i].data == data)
|
81 | {
|
82 | handlervector[type].handlers[i].filter = filter;
|
83 | return TRUE;
|
84 | }
|
85 | continue;
|
86 | }
|
87 | handlervector[type].handlers[i].handler = handler;
|
88 | handlervector[type].handlers[i].filter = filter;
|
89 | handlervector[type].handlers[i].data = data;
|
90 | ++handlervector[type].nhandlers;
|
91 | if (type == EV_TICK) enableTicks();
|
92 | return TRUE;
|
93 | }
|
94 | return FALSE;
|
95 | }
|
96 |
|
97 | BOOL event_unregister(ev_type type, ev_handler handler, void *data)
|
98 | {
|
99 | for (uint8_t i = 0; i < MAXEVHANDLERS; ++i)
|
100 | {
|
101 | if (handlervector[type].handlers[i].handler != handler
|
102 | || handlervector[type].handlers[i].data != data)
|
103 | {
|
104 | continue;
|
105 | }
|
106 | handlervector[type].handlers[i].handler = 0;
|
107 | --handlervector[type].nhandlers;
|
108 | if (type == EV_TICK) disableTicks();
|
109 | return TRUE;
|
110 | }
|
111 | return FALSE;
|
112 | }
|
113 |
|
114 | ISR(PCINT1_vect)
|
115 | {
|
116 | equeue[eqhead].type = EV_PINCHANGE;
|
117 | equeue[eqhead].data = PINB;
|
118 | if (++eqhead == EVQUEUESIZE) eqhead = 0;
|
119 | }
|
120 |
|
121 | ISR(TIM1_COMPA_vect)
|
122 | {
|
123 | equeue[eqhead].type = EV_TICK;
|
124 | if (++eqhead == EVQUEUESIZE) eqhead = 0;
|
125 | }
|
126 |
|
127 | void event_loop(void)
|
128 | {
|
129 | sei();
|
130 | while (1)
|
131 | {
|
132 | /* run event queue */
|
133 | while (eqtail != eqhead)
|
134 | {
|
135 | event *ev = &(equeue[eqtail]);
|
136 | evhdl_vector *v = &(handlervector[ev->type]);
|
137 | if (v->nhandlers)
|
138 | {
|
139 | for (uint8_t i = 0; i < MAXEVHANDLERS; ++i)
|
140 | {
|
141 | if (!(v->handlers[i].handler)) continue;
|
142 | if (!(v->handlers[i].filter) ||
|
143 | v->handlers[i].filter(ev,
|
144 | v->handlers[i].handler, v->handlers[i].data))
|
145 | {
|
146 | v->handlers[i].handler(ev, v->handlers[i].data);
|
147 | }
|
148 | }
|
149 | }
|
150 | if (++eqtail == EVQUEUESIZE) eqtail = 0;
|
151 | }
|
152 |
|
153 | /* sleep if no more events are pending and no timer tick enabled */
|
154 | cli();
|
155 | if (eqtail == eqhead && !ticksEnabled)
|
156 | {
|
157 | sei();
|
158 | __asm__ volatile("sleep");
|
159 | }
|
160 | else sei();
|
161 | }
|
162 | UNREACHABLE();
|
163 | }
|