trennfix/sw: Single timer version
[eisenbahn.git] / trennfix / sw / mm_switch.c
1 /******************************************************************************
2 *
3 * Trennfix firmware - mm_switch.c
4 *
5 * Maerklin Motorola switch command receiver
6 *
7 * Copyright (C) 2017 Philipp Hachtmann
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 *****************************************************************************/
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <avr/io.h>
29 #include <avr/eeprom.h>
30 #include <avr/interrupt.h>
31 #include <avr/pgmspace.h>
32
33 #include <util/delay.h>
34 #include <stdint.h>
35
36 #include "hardware.h"
37 #include "mm_switch.h"
38
39 #define DEBUG_TIMEOUT
40 #ifdef DEBUG_TIMEOUT
41 #define MON(val) setpin(PIN_DRIVE, val)
42 #else
43 #define MON(xx) ({0;})
44 #endif
45
46
47 /*
48 * Lookup decoder number.
49 *
50 */
51 static uint8_t lookup_decoder(uint8_t mm_byte)
52 {
53 switch(mm_byte) {
54 /* 0x00 is invalid */
55 case 0xc0: return 1;
56 case 0x80: return 2;
57 case 0x30: return 3;
58 case 0xf0: return 4;
59 case 0xb0: return 5;
60 case 0x20: return 6;
61 case 0xe0: return 7;
62 case 0xa0: return 8;
63
64 case 0x0c: return 9;
65 case 0xcc: return 10;
66 case 0x8c: return 11;
67 case 0x3c: return 12;
68 case 0xfc: return 13;
69 case 0xbc: return 14;
70 case 0x2c: return 15;
71 case 0xec: return 16;
72 case 0xac: return 17;
73
74 case 0x08: return 18;
75 case 0xc8: return 19;
76 case 0x88: return 20;
77 case 0x38: return 21;
78 case 0xf8: return 22;
79 case 0xb8: return 23;
80 case 0x28: return 24;
81 case 0xe8: return 25;
82
83 default:
84 return 0;
85 }
86 }
87
88 static uint8_t lookup_command(uint8_t mm_byte)
89 {
90 switch(mm_byte) {
91 case 0xc3: return 1;
92 case 0x03: return 2;
93 case 0xf3: return 3;
94 case 0x33: return 4;
95 case 0xcf: return 5;
96 case 0x0f: return 6;
97 case 0xff: return 7;
98 case 0x3f: return 8;
99 default:
100 return 0;
101 }
102 }
103
104 static void mm_switch_init(void)
105 {
106 /* Get rid of the 1/8 clock prescaler */
107 CLKPR = (1 << CLKPCE);
108 CLKPR = 0;
109
110 GIMSK |= _BV(PCIE); /* Enable pin change interrupt */
111 PCMSK = _BV(PCINT4); /* PB4, Rail sense input */
112
113 TCCR0A = 0; /* This is normal mode */
114 TCCR0B = 0; /* Timer off */
115 TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
116 TIMSK |= _BV(TOV0); /* Overflow interrupt */
117
118 /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
119 OCR0A = 91; /* Prescaler 8 is used */
120
121 /* Timer 1 for timeout */
122 /* We set it to 1024us by prescaler 64 and running full 256 */
123 TCCR1 = 7;
124 TIMSK |= _BV(TOIE1); /* Overflow interrupt */
125 }
126
127
128 static volatile uint8_t shift_sub;
129 static volatile uint8_t shift_zero;
130 static volatile uint8_t shift_decoder;
131 static volatile uint8_t shift_sub_first;
132 static volatile uint8_t shift_decoder_first;
133
134 /* We will shift from right to left.
135 * XXXXXXXX XX XXXXXXXX
136 * shift_decoder shift_zero shift_sub
137 *
138 * The bits 7 downto 2 of shift_zero are ignored.
139 */
140
141 volatile uint8_t bitno = 0;
142
143 static void trigger(void)
144 {
145 setpin(PIN_DRIVE, 1);
146 _delay_us(10);
147 setpin(PIN_DRIVE, 0);
148 }
149
150 enum recstate {
151 IDLE = 0,
152 FIRST_FAST_SAMPLE,
153 FIRST_SLOW_SAMPLE, /* If clock arrives, we stay on the fast path! */
154 FAST_SAMPLE,
155 FAST_WAIT_FOR_CLOCK,
156 SLOW_SAMPLE,
157 SLOW_WAIT_FOR_CLOCK,
158 };
159
160 static enum recstate recstate = IDLE;
161
162 static inline void shift(uint8_t value)
163 {
164 shift_decoder <<= 1;
165 if (shift_zero & 2)
166 shift_decoder |= 1;
167 shift_zero <<= 1;
168 if (shift_sub & 0x80)
169 shift_zero |= 1;
170 shift_sub <<= 1;
171 if (value)
172 shift_sub |= 1;
173 }
174
175
176 ISR(TIMER0_COMPA_vect) {
177
178 static uint8_t patience = 0;
179
180 switch(recstate) {
181 case FIRST_FAST_SAMPLE:
182 recstate = FIRST_SLOW_SAMPLE;
183 TSTART_CLK_TO_SAMPLE_FAST; /* Will not run out in fast! */
184 break;
185
186 case FIRST_SLOW_SAMPLE:
187 bitno = 0;
188
189 case SLOW_SAMPLE:
190 recstate = SLOW_WAIT_FOR_CLOCK;
191 TSTART_CLK_TO_SAMPLE_SLOW;
192 break;
193
194 case FAST_SAMPLE:
195 recstate = FAST_WAIT_FOR_CLOCK;
196 TSTART_CLK_TO_SAMPLE_FAST;
197 break;
198
199 case FAST_WAIT_FOR_CLOCK: /* A timeout! */
200 if (patience) {
201 patience--;
202 TSTART_CLK_TO_SAMPLE_FAST;
203 return;
204 }
205 recstate = IDLE;
206 TSTOP;
207 return;
208
209 case SLOW_WAIT_FOR_CLOCK:
210 if (patience) {
211 patience--;
212 TSTART_CLK_TO_SAMPLE_SLOW;
213 return;
214 }
215 TSTOP;
216 recstate = IDLE;
217 return;
218 }
219
220 shift(MM_SENSE);
221 bitno++;
222
223 if (bitno == 18) { /* Save first received word */
224 shift_sub_first = shift_sub;
225 shift_decoder_first = shift_decoder;
226 patience = 18;
227
228 }
229 if (bitno == 36) {
230 if ((shift_sub == shift_sub_first) &&
231 (shift_decoder == shift_decoder_first)) {
232 uint8_t decoder = lookup_decoder(shift_decoder);
233 uint8_t command = lookup_command(shift_sub);
234 if (recstate == SLOW_WAIT_FOR_CLOCK)
235 trigger();
236 if (decoder) {
237 /* Congratulations, we have a valid command */
238 if (recstate == FAST_WAIT_FOR_CLOCK) {
239 // trigger();
240 mm_switch_command(decoder, command);
241 }
242 }
243 }
244 }
245 }
246
247 ISR(BADISR_vect)
248 {
249 while(1) {
250 /*
251 setpin(PIN_LED, 1);
252 _delay_ms(30);
253 setpin(PIN_LED, 0);
254 _delay_ms(30);
255 setpin(PIN_LED, 1);
256 _delay_ms(30);
257 setpin(PIN_LED, 0);
258 _delay_ms(2000);
259 */
260 }
261 }
262
263 ISR(TIM0_OVF_vect)
264 {
265 return;
266 while(1) {
267 setpin(PIN_LED, 1);
268 _delay_ms(30);
269 setpin(PIN_LED, 0);
270 _delay_ms(300);
271 }
272
273 }
274
275
276 /* Pin change interrupt vector */
277 void mm_pinchange_handler(void)
278 {
279 static uint8_t sense_last;
280
281 if (MM_SENSE == sense_last)
282 return;
283 sense_last = MM_SENSE;
284 if (!sense_last)
285 return;
286
287 switch(recstate) {
288 case IDLE:
289 bitno = 0;
290 recstate = FIRST_FAST_SAMPLE;
291 TSTART_CLK_TO_SAMPLE_FAST;
292 break;
293 case FIRST_SLOW_SAMPLE:
294 recstate = FAST_SAMPLE;
295 TSTART_CLK_TO_SAMPLE_FAST;
296 break;
297 case FAST_WAIT_FOR_CLOCK:
298 recstate = FAST_SAMPLE;
299 TSTART_CLK_TO_SAMPLE_FAST;
300 break;
301 case SLOW_WAIT_FOR_CLOCK:
302 recstate = SLOW_SAMPLE;
303 TSTART_CLK_TO_SAMPLE_SLOW;
304 break;
305
306 /* Not expected */
307 case FIRST_FAST_SAMPLE:
308 case FAST_SAMPLE:
309 case SLOW_SAMPLE:
310 default:
311 break;
312 }
313 }
314
315 /******************************************************************************
316 * The end :-)
317 */
318
319
320