]> www.fi.muni.cz Git - openparking.git/blob - firmware/firmware.c
ce4a91486cda276c43235dca59fd77b373af6bd3
[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 "modbus.h"
6
7 #define TIMEOUT 0x2FF
8
9 #define N_TRIGGERS 3
10 #define N_SENSORS 12
11 #define N_TRIG_SENSORS 4
12
13 // static int16_t distances[N_SENSORS];
14
15 // hold_regs[0] is unit ID
16 #define thresholds      (hold_regs+1)
17 #define led1_sensors    (hold_regs[13])
18 #define led2_sensors    (hold_regs[14])
19
20 #define led_bitmap      (hold_regs[MB_N_HOLD_REGS_EEPROM])
21 #define distances       (hold_regs+MB_N_HOLD_REGS_EEPROM+1)
22 #define free_bitmap     (hold_regs[MB_N_HOLD_REGS_EEPROM+13])
23 #define err_bitmap      (hold_regs[MB_N_HOLD_REGS_EEPROM+14])
24
25 static void pull_trigger(uint8_t trig)
26 {
27         switch (trig) {
28         case 0: PORTD |= _BV(PD7); _delay_us(10); PORTD &= ~_BV(PD7); break;
29         case 1: PORTB |= _BV(PB4); _delay_us(10); PORTB &= ~_BV(PB4); break;
30         case 2: PORTC |= _BV(PC4); _delay_us(10); PORTC &= ~_BV(PC4); break;
31         }
32 }
33
34 static uint16_t get_pin(uint8_t trig)
35 {
36         switch (trig) {
37         case 0: return (PIND & 0x78) >> 3;
38         case 1: return PINB & 0x0F;
39         default: return PINC & 0x0F;
40         }
41 }
42
43 static void do_measurement(unsigned char trig)
44 {
45         uint16_t starttimes[N_TRIG_SENSORS], starttime;
46         uint8_t to_start = (1 << N_TRIG_SENSORS) - 1;
47         uint8_t to_measure = 0, i;
48
49         pull_trigger(trig);
50
51         starttime = TCNT1;
52
53         while (to_start || to_measure) {
54                 uint8_t bits = 0;
55                 uint16_t now = TCNT1;
56
57                 if (now-starttime >= TIMEOUT)
58                         break;
59
60                 bits = get_pin(trig);
61
62                 for (i = 0; i < N_TRIG_SENSORS; i++) {
63                         uint8_t mask = 1 << i;
64
65                         if ((to_start & mask) && (bits & mask)) {
66                                 // echo start
67                                 starttimes[i] = now;
68                                 to_start &= ~mask;
69                                 to_measure |= mask;
70                         } else if ((to_measure & mask) && !(bits & mask)) {
71                                 // echo end
72                                 to_measure &= ~mask;
73                                 distances[trig*N_TRIG_SENSORS + i]
74                                         = now - starttimes[i];
75                         }
76                 }
77         }
78
79         for (i = 0; i < N_TRIG_SENSORS; i++)
80                 if (to_start & (1 << i))
81                         distances[trig*N_TRIG_SENSORS + i] = -1;
82                 else if (to_measure & (1 << i))
83                         distances[trig*N_TRIG_SENSORS + i] = 0;
84 }
85
86 static void do_measurements()
87 {
88         uint8_t trig;
89
90         for (trig = 0; trig < N_TRIGGERS; trig++) {
91                 do_measurement(trig);
92                 _delay_ms(200);
93         }
94 }
95
96 static void led_set(uint8_t led, uint8_t state)
97 {
98         if (led == 0) {
99                 if (state) {
100                         PORTD |= _BV(PD4);
101                         // PORTC |= _BV(PC5);
102                         led_bitmap |= 1;
103                 } else {
104                         PORTD &= ~_BV(PD4);
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         // temporary LED
173         DDRD |= _BV(PD4);
174
175         // set up the timer
176         TCCR1A = 0;
177         TCCR1B = _BV(CS12)|_BV(CS10); // CLK/1024
178
179         // enable interrupts
180         sei();
181
182         while(1) {
183                 uint8_t trig;
184                 for (trig = 0; trig < N_TRIGGERS; trig++) {
185                         uint16_t now;
186                         do_measurement(trig);
187                         now = TCNT1;
188                         while (TCNT1-now < 200)
189                                 modbus_poll();
190                 }
191
192                 eval_bitmaps();
193 //              led_set(0,
194 //                      distances[4] > 100 || distances[11] > 100);
195         }
196 }
197