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