]> www.fi.muni.cz Git - openparking.git/blob - firmware/firmware.c
d70705d5993c25a2ce5829200e12d38a2349c6c3
[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 do_measurements()
89 {
90         uint8_t trig;
91
92         for (trig = 0; trig < N_TRIGGERS; trig++) {
93                 do_measurement(trig);
94                 _delay_ms(200);
95         }
96 }
97
98 static void led_set(uint8_t led, uint8_t state)
99 {
100         if (led == 0) {
101                 if (state) {
102                         PORTC |= _BV(PC5);
103                         led_bitmap |= 1;
104                 } else {
105                         PORTC &= ~_BV(PC5);
106                         led_bitmap &= ~1;
107                 }
108         } else {
109                 if (state) {
110                         PORTB |= _BV(PB5);
111                         led_bitmap |= 2;
112                 } else {
113                         PORTB &= ~_BV(PB5);
114                         led_bitmap &= ~2;
115                 }
116         }
117 }
118
119 static void eval_bitmaps()
120 {
121         uint16_t free_b = 0, err_b = 0, mask;
122         uint8_t i;
123
124         for (i = 0; i < N_SENSORS; i++) {
125                 mask = 1 << i;
126
127                 if (thresholds[i]) {
128                         if (distances[i] == -1 || distances[i] == 0) {
129                                 err_b |= mask;
130                         } else if (distances[i] > thresholds[i]) {
131                                 free_b |= mask;
132                         }
133                 }
134         }
135
136         free_bitmap = free_b;
137         err_bitmap  = err_b;
138
139         if (led1_sensors) {
140                 if (led1_sensors & free_bitmap) {
141                         led_set(0, 1);
142                 } else {
143                         led_set(0, 0);
144                 }
145         }
146
147         if (led2_sensors) {
148                 if (led2_sensors & free_bitmap) {
149                         led_set(1, 1);
150                 } else {
151                         led_set(1, 0);
152                 }
153         }
154 }
155
156 uint8_t hold_reg_is_valid(uint16_t reg, uint16_t val)
157 {
158         if (reg == MB_HOLD_REGS_BASE) 
159                 return val > 0 && val <= 247;
160
161         return 1;
162 }
163
164 int main()
165 {
166         modbus_init(0);
167
168         // output pins
169         DDRD |= _BV(PD7); // Trig D
170         DDRB |= _BV(PB4) | _BV(PB5); // Trig B, LED 2
171         DDRC |= _BV(PC4) | _BV(PC5); // Trig C, LED 1
172
173         // set up the timer
174         TCCR1A = 0;
175         TCCR1B = _BV(CS12)|_BV(CS10); // CLK/1024
176
177         // enable interrupts
178         sei();
179
180         while(1) {
181                 uint8_t trig;
182                 for (trig = 0; trig < N_TRIGGERS; trig++) {
183                         uint16_t now;
184                         do_measurement(trig);
185                         now = get_clock();
186                         while (get_clock()-now < MEASUREMENT_WAIT)
187                                 modbus_poll();
188                 }
189
190                 eval_bitmaps();
191 //              led_set(0,
192 //                      distances[4] > 100 || distances[11] > 100);
193         }
194 }
195