]> www.fi.muni.cz Git - openparking.git/blob - firmware/firmware.c
Three-state LED: display errors if present
[openparking.git] / firmware / firmware.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <util/delay.h>
4 #include <stdio.h>
5 #include "clock.h"
6 #include "modbus.h"
7
8 #define ECHO_TIMEOUT            (CLOCK_HZ/10)   // 10 ms
9 #define MEASUREMENT_WAIT        (CLOCK_HZ/3)    // three triggers per second
10
11 #define N_TRIGGERS 3
12 #define N_SENSORS 12
13 #define N_TRIG_SENSORS 4
14
15 // static int16_t distances[N_SENSORS];
16
17 // hold_regs[0] is unit ID
18 #define thresholds      (hold_regs+1)
19 #define led1_sensors    (hold_regs[13])
20 #define led2_sensors    (hold_regs[14])
21
22 #define led_bitmap      (hold_regs[MB_N_HOLD_REGS_EEPROM])
23 #define distances       (hold_regs+MB_N_HOLD_REGS_EEPROM+1)
24 #define free_bitmap     (hold_regs[MB_N_HOLD_REGS_EEPROM+13])
25 #define err_bitmap      (hold_regs[MB_N_HOLD_REGS_EEPROM+14])
26
27 static void pull_trigger(uint8_t trig)
28 {
29         switch (trig) {
30         case 0: PORTD |= _BV(PD7); _delay_us(10); PORTD &= ~_BV(PD7); break;
31         case 1: PORTB |= _BV(PB4); _delay_us(10); PORTB &= ~_BV(PB4); break;
32         case 2: PORTC |= _BV(PC4); _delay_us(10); PORTC &= ~_BV(PC4); break;
33         }
34 }
35
36 static uint16_t get_pin(uint8_t trig)
37 {
38         switch (trig) {
39         case 0: return (PIND & 0x78) >> 3;
40         case 1: return PINB & 0x0F;
41         default: return PINC & 0x0F;
42         }
43 }
44
45 static void do_measurement(unsigned char trig)
46 {
47         uint16_t starttimes[N_TRIG_SENSORS], starttime;
48         uint8_t to_start = (1 << N_TRIG_SENSORS) - 1;
49         uint8_t to_measure = 0, i;
50
51         pull_trigger(trig);
52
53         starttime = get_clock();
54
55         while (to_start || to_measure) {
56                 uint8_t bits = 0;
57                 uint16_t now = get_clock();
58
59                 if (now-starttime >= ECHO_TIMEOUT)
60                         break;
61
62                 bits = get_pin(trig);
63
64                 for (i = 0; i < N_TRIG_SENSORS; i++) {
65                         uint8_t mask = 1 << i;
66
67                         if ((to_start & mask) && (bits & mask)) {
68                                 // echo start
69                                 starttimes[i] = now;
70                                 to_start &= ~mask;
71                                 to_measure |= mask;
72                         } else if ((to_measure & mask) && !(bits & mask)) {
73                                 // echo end
74                                 to_measure &= ~mask;
75                                 distances[trig*N_TRIG_SENSORS + i]
76                                         = now - starttimes[i];
77                         }
78                 }
79         }
80
81         for (i = 0; i < N_TRIG_SENSORS; i++)
82                 if (to_start & (1 << i))
83                         distances[trig*N_TRIG_SENSORS + i] = -1;
84                 else if (to_measure & (1 << i))
85                         distances[trig*N_TRIG_SENSORS + i] = 0;
86 }
87
88 static void led_set(uint8_t led, uint8_t state)
89 {
90         if (led == 0) {
91                 switch (state) {
92                 case 0:
93                         led_bitmap &= ~1;
94                         led_bitmap &= ~2;
95                         break;
96                 case 1:
97                         led_bitmap |= 1;
98                         led_bitmap &= ~2;
99                         break;
100                 default: // error
101                         led_bitmap |= 2;
102                         break;
103                 }
104         } else {
105                 switch (state) {
106                 case 0:
107                         led_bitmap &= ~4;
108                         led_bitmap &= ~8;
109                         break;
110                 case 1:
111                         led_bitmap |= 4;
112                         led_bitmap &= ~8;
113                         break;
114                 default:
115                         led_bitmap |= 8;
116                         break;
117                 }
118         }
119 }
120
121 static void leds_update()
122 {
123         if (led_bitmap & 1) {
124                 PORTC |= _BV(PC5);
125         } else {
126                 PORTC &= ~_BV(PC5);
127         }
128
129         if (led_bitmap & 2) {
130                 DDRC &= ~_BV(PC5);
131         } else {
132                 DDRC |= _BV(PC5);
133         }
134
135         if (led_bitmap & 4) {
136                 PORTB |= _BV(PB5);
137         } else {
138                 PORTB &= ~_BV(PB5);
139         }
140
141         if (led_bitmap & 8) {
142                 DDRB |= _BV(PB5);
143         } else {
144                 DDRB &= ~_BV(PB5);
145         }
146 }
147
148 static void eval_bitmaps()
149 {
150         uint16_t free_b = 0, err_b = 0, mask;
151         uint8_t i;
152
153         for (i = 0; i < N_SENSORS; i++) {
154                 mask = 1 << i;
155
156                 if (thresholds[i]) {
157                         if (distances[i] == -1 || distances[i] == 0) {
158                                 err_b |= mask;
159                         } else if (distances[i] > thresholds[i]) {
160                                 free_b |= mask;
161                         }
162                 }
163         }
164
165         free_bitmap = free_b;
166         err_bitmap  = err_b;
167
168         if (led1_sensors) {
169                 if (led1_sensors & err_bitmap) {
170                         led_set(0, 2);
171                 } else if (led1_sensors & free_bitmap) {
172                         led_set(0, 1);
173                 } else {
174                         led_set(0, 0);
175                 }
176         }
177
178         if (led2_sensors) {
179                 if (led2_sensors & err_bitmap) {
180                         led_set(1, 2);
181                 } else if (led2_sensors & free_bitmap) {
182                         led_set(1, 1);
183                 } else {
184                         led_set(1, 0);
185                 }
186         }
187 }
188
189 uint8_t hold_reg_is_valid(uint16_t reg, uint16_t val)
190 {
191         if (reg == MB_HOLD_REGS_BASE) 
192                 return val > 0 && val <= 247;
193
194         return 1;
195 }
196
197 int main()
198 {
199         modbus_init(0);
200
201         // output pins
202         DDRD |= _BV(PD7); // Trig D
203         DDRB |= _BV(PB4) | _BV(PB5); // Trig B, LED 2
204         DDRC |= _BV(PC4) | _BV(PC5); // Trig C, LED 1
205
206         // set up the timer
207         TCCR1A = 0;
208         TCCR1B = _BV(CS12)|_BV(CS10); // CLK/1024
209
210         // enable interrupts
211         sei();
212
213         while(1) {
214                 uint8_t trig;
215                 for (trig = 0; trig < N_TRIGGERS; trig++) {
216                         uint16_t now;
217                         do_measurement(trig);
218                         now = get_clock();
219                         while (get_clock()-now < MEASUREMENT_WAIT)
220                                 modbus_poll();
221                 }
222
223                 eval_bitmaps();
224                 leds_update(); // might be written from modbus
225 //              led_set(0,
226 //                      distances[4] > 100 || distances[11] > 100);
227         }
228 }
229