Commit | Line | Data |
---|---|---|
54de37bf PH |
1 | /****************************************************************************** |
2 | * | |
3 | * Trennfix firmware - main.c | |
4 | * | |
5 | * Copyright (C) 2017 Philipp Hachtmann | |
6 | * | |
7 | * This program is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation, either version 3 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | * | |
20 | *****************************************************************************/ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | ||
26 | #include <avr/io.h> | |
27 | #include <avr/eeprom.h> | |
28 | #include <avr/interrupt.h> | |
29 | #include <avr/pgmspace.h> | |
30 | ||
31 | #include <util/delay.h> | |
32 | #include <stdint.h> | |
33 | ||
34 | #include "pin_magic.h" | |
af5fd980 | 35 | #include "mm_lookup.h" |
54de37bf | 36 | |
af5fd980 | 37 | #define LED _PIN(PORTB, PORTB2) |
54de37bf PH |
38 | #define SENSE _PIN(PORTB, PORTB4) |
39 | #define DRIVE _PIN(PORTB, PORTB3) | |
40 | #define BTN _PIN(PORTB, PB1) | |
41 | ||
42 | #define SIGIN (!PINVAL(SENSE)) | |
af5fd980 | 43 | #define BTN_PRESSED (!PINVAL(BTN)) |
54de37bf PH |
44 | |
45 | // #define DEBUG_TIMEOUT | |
54de37bf PH |
46 | #ifdef DEBUG_TIMEOUT |
47 | #define MON_TIMEOUT(val) setpin(DRIVE, val) | |
48 | #else | |
49 | #define MON_TIMEOUT(xx) ({0;}) | |
50 | #endif | |
51 | ||
af5fd980 PH |
52 | uint8_t EEMEM ee_our_decoder; |
53 | uint8_t EEMEM ee_our_key; | |
54de37bf PH |
54 | |
55 | static void setup_hw(void) | |
56 | { | |
57 | /* Get rid of the 1/8 clock prescaler */ | |
58 | CLKPR = (1 << CLKPCE); | |
59 | CLKPR = 0; | |
60 | ||
61 | INPUT_PIN(SENSE); | |
62 | INPUT_PIN(BTN); | |
63 | OUTPUT_PIN(DRIVE); | |
64 | OUTPUT_PIN(LED); | |
65 | setpin(BTN, 1); /* Need pullup */ | |
66 | _delay_ms(1); /* Let the line rise */ | |
67 | ||
68 | ||
69 | GIMSK |= _BV(PCIE); /* Enable pin change interrupt */ | |
70 | PCMSK = _BV(PCINT4); /* PB4, Rail sense input */ | |
71 | ||
72 | TCCR0A = 0; /* This is normal mode */ | |
73 | TCCR0B = 0; /* Timer off */ | |
74 | TIMSK |= _BV(OCIE0A); /* Get a match interrupt */ | |
75 | TIMSK |= _BV(TOV0); /* Overflow interrupt */ | |
76 | ||
77 | /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/ | |
78 | OCR0A = 91; /* Prescaler 8 is used */ | |
79 | ||
80 | /* Timer 1 for timeout */ | |
81 | /* We set it to 1024us by prescaler 64 and running full 256 */ | |
82 | TCCR1 = 7; | |
83 | TIMSK |= _BV(TOIE1); /* Overflow interrupt */ | |
84 | } | |
85 | ||
86 | static uint8_t ctr = 0; | |
87 | ||
88 | static volatile uint8_t shift_sub; | |
89 | static volatile uint8_t shift_zero; | |
90 | static volatile uint8_t shift_decoder; | |
91 | static volatile uint8_t shift_sub_first; | |
92 | static volatile uint8_t shift_decoder_first; | |
93 | ||
94 | /* We will shift from right to left. | |
95 | * XXXXXXXX XX XXXXXXXX | |
96 | * shift_decoder shift_zero shift_sub | |
97 | * | |
98 | * The bits 7 downto 2 of shift_zero are ignored. | |
99 | */ | |
100 | ||
101 | #define STOP_TIMER0 (TCCR0B = 0) | |
102 | ||
103 | volatile uint8_t bitno = 0; | |
104 | ||
105 | ||
106 | static void zero(void) | |
107 | { | |
108 | setpin(LED, 1); | |
109 | _delay_ms(20); | |
110 | setpin(LED, 0); | |
111 | _delay_ms(980); | |
112 | GIFR |= _BV(PCIF); | |
113 | } | |
114 | ||
115 | ||
116 | static void one(void) | |
117 | { | |
118 | setpin(LED, 1); | |
119 | _delay_ms(20); | |
120 | setpin(LED, 0); | |
121 | _delay_ms(160); | |
122 | setpin(LED, 1); | |
123 | _delay_ms(20); | |
124 | setpin(LED, 0); | |
125 | _delay_ms(800); | |
126 | GIFR |= _BV(PCIF); | |
127 | } | |
128 | ||
129 | static void trigger(void) | |
130 | { | |
af5fd980 | 131 | return; |
54de37bf PH |
132 | setpin(DRIVE, 1); |
133 | _delay_us(20); | |
134 | setpin(DRIVE, 0); | |
135 | } | |
136 | ||
137 | static volatile uint8_t our_decoder = 3; | |
138 | static volatile uint8_t our_key = 5; | |
139 | static volatile uint8_t learn_mode = 0; | |
af5fd980 | 140 | static volatile uint8_t drive_on = 0; |
54de37bf PH |
141 | |
142 | ISR(TIMER0_COMPA_vect) { | |
143 | ||
144 | STOP_TIMER0; | |
145 | ||
146 | shift_decoder <<= 1; | |
147 | if (shift_zero & 2) | |
148 | shift_decoder |= 1; | |
149 | shift_zero <<= 1; | |
150 | if (shift_sub & 0x80) | |
151 | shift_zero |= 1; | |
152 | shift_sub <<= 1; | |
153 | if (SIGIN) | |
154 | shift_sub |= 1; | |
155 | ||
156 | bitno++; | |
157 | ||
158 | if (bitno == 18) { /* Save first received word */ | |
159 | shift_sub_first = shift_sub; | |
160 | shift_decoder_first = shift_decoder; | |
161 | } else if (bitno == 36) { | |
162 | ||
163 | if ((shift_sub == shift_sub_first) && | |
164 | (shift_decoder == shift_decoder_first)) { | |
af5fd980 PH |
165 | uint8_t decoder = lookup_decoder(shift_decoder); |
166 | uint8_t command = lookup_command(shift_sub); | |
54de37bf PH |
167 | if (decoder) { |
168 | /* Congratulations, we have a valid command */ | |
169 | trigger(); | |
170 | ||
171 | if (learn_mode) { | |
172 | if (command) { | |
173 | our_decoder = decoder; | |
174 | our_key = command; | |
175 | learn_mode = 0; | |
af5fd980 PH |
176 | eeprom_write_byte(&ee_our_decoder, our_decoder); |
177 | eeprom_write_byte(&ee_our_key, our_key); | |
54de37bf PH |
178 | } |
179 | } else { | |
54de37bf PH |
180 | if (decoder == our_decoder) { |
181 | if (command == our_key) | |
af5fd980 | 182 | drive_on = 1; |
54de37bf | 183 | if (command == 0) |
af5fd980 | 184 | drive_on = 0; |
54de37bf PH |
185 | } |
186 | } | |
187 | } | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
192 | #define START_TIMER0 ({TCNT0 = 0; TCCR0B = 2;}) | |
193 | #define START_TIMER1 ({TCNT1 = 1; TCCR1 = 7; GTCCR |= 2;}) | |
194 | #define STOP_TIMER1 ({TCCR1 = 0; TCNT1 = 1;}) | |
195 | ||
196 | ISR(TIM1_OVF_vect) | |
197 | { | |
198 | STOP_TIMER1; | |
199 | // if (!SIGIN) | |
200 | // setpin(LED, 1); | |
201 | bitno = 0; | |
202 | MON_TIMEOUT(1); | |
203 | } | |
204 | ||
205 | ISR(TIM0_OVF_vect) | |
206 | { | |
207 | while(1) { | |
208 | setpin(LED, 1); | |
209 | _delay_ms(30); | |
210 | setpin(LED, 1); | |
211 | _delay_ms(30); | |
212 | } | |
213 | ||
214 | } | |
215 | ||
216 | /* Shortest element seen 184 clocks */ | |
217 | /* Officially 208 clocks */ | |
218 | /* (1 + 7) * 208 clocks */ | |
219 | ||
220 | /* Pin change interrupt vector */ | |
221 | ISR(PCINT0_vect) | |
222 | { | |
223 | START_TIMER1; | |
224 | MON_TIMEOUT(0); | |
225 | ||
226 | if (SIGIN) { | |
227 | START_TIMER0; | |
228 | } | |
229 | } | |
230 | ||
231 | ||
232 | ||
233 | /****************************************************************************** | |
234 | * | |
235 | * main() - The main routine | |
236 | * | |
237 | */ | |
238 | ||
239 | int main(void) { | |
af5fd980 PH |
240 | uint8_t duty = 30; |
241 | uint8_t old_drive = 0; | |
54de37bf | 242 | setup_hw(); |
af5fd980 PH |
243 | our_decoder = eeprom_read_byte(&ee_our_decoder); |
244 | our_key = eeprom_read_byte(&ee_our_key); | |
245 | if (our_decoder == 0xff) | |
246 | learn_mode = 1; | |
54de37bf | 247 | sei(); |
af5fd980 | 248 | uint8_t i; |
54de37bf PH |
249 | while (1) { |
250 | if (!learn_mode) { | |
af5fd980 PH |
251 | if (old_drive == 0 && drive_on) { |
252 | setpin(DRIVE, 1); | |
253 | _delay_ms(100); | |
254 | } | |
255 | old_drive = drive_on; | |
256 | setpin(DRIVE, drive_on); | |
257 | for (i = 0; i < duty; i++) | |
258 | _delay_us(4); | |
259 | for (i = 0; i < (255 - duty); i++) { | |
260 | setpin(DRIVE, 0); | |
261 | _delay_us(4); | |
262 | } | |
263 | ||
54de37bf PH |
264 | if (!PINVAL(BTN)) |
265 | learn_mode = 1; | |
266 | } else { | |
267 | setpin(LED, 1); | |
268 | _delay_ms(30); | |
269 | setpin(LED, 0); | |
270 | _delay_ms(600); | |
271 | } | |
272 | ||
273 | /* Main loop here */ | |
274 | } | |
275 | return 0; | |
276 | } | |
277 | ||
278 | /****************************************************************************** | |
279 | * The end :-) | |
280 | */ |