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