trennfix/sw: Temporary
[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
52 static uint8_t lookup_nibble(uint8_t mm_nibble)
53 {
54 switch(mm_nibble) {
55 case 0x0: return 0;
56 case 0xc: return 1;
57 case 0x8: return 2;
58 case 0x3: return 3;
59 case 0xf: return 4;
60 case 0xb: return 5;
61 case 0x2: return 6;
62 case 0xe: return 7;
63 case 0xa: return 8;
64 default: return 0;
65 }
66 return 0;
67 }
68
69 static uint8_t lookup_decoder(uint8_t mm_byte)
70 {
71 uint8_t low;
72 uint8_t high;
73 if (mm_byte == 0)
74 return 100;
75 low = lookup_nibble(mm_byte >> 4);
76 high = lookup_nibble(mm_byte & 0xf);
77 if (!low)
78 return 0;
79 return 9 * high + low;
80 }
81
82 static uint8_t lookup_command(uint8_t mm_byte)
83 {
84 switch(mm_byte) {
85 case 0xc3: return 1;
86 case 0x03: return 2;
87 case 0xf3: return 3;
88 case 0x33: return 4;
89 case 0xcf: return 5;
90 case 0x0f: return 6;
91 case 0xff: return 7;
92 case 0x3f: return 8;
93 default:
94 return 0;
95 }
96 }
97
98
99 static __attribute__((unused)) void mm_switch_init(void)
100 {
101 /* Get rid of the 1/8 clock prescaler */
102 CLKPR = (1 << CLKPCE);
103 CLKPR = 0;
104
105 GIMSK |= _BV(PCIE); /* Enable pin change interrupt */
106 PCMSK = _BV(PCINT4); /* PB4, Rail sense input */
107
108 TCCR0A = 0; /* This is normal mode */
109 TCCR0B = 0; /* Timer off */
110 TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
111 TIMSK |= _BV(TOV0); /* Overflow interrupt */
112
113 /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
114 OCR0A = 91; /* Prescaler 8 is used */
115
116 /* Timer 1 for timeout */
117 /* We set it to 1024us by prescaler 64 and running full 256 */
118 TCCR1 = 7;
119 TIMSK |= _BV(TOIE1); /* Overflow interrupt */
120 }
121
122 static volatile uint8_t shift_command;
123 static volatile uint8_t shift_function;
124 static volatile uint8_t shift_address;
125 static volatile uint8_t shift_command_first;
126 static volatile uint8_t shift_address_first;
127
128 /* We will shift from right to left.
129 * XXXXXXXX XX XXXXXXXX
130 * shift_address shift_function shift_command
131 *
132 * The bits 7 downto 2 of shift_function are ignored.
133 */
134
135 volatile uint8_t bitno = 0;
136
137 static void __attribute__((unused)) trigger(void)
138 {
139 setpin(PIN_DRIVE, 1);
140 _delay_us(4);
141 setpin(PIN_DRIVE, 0);
142 _delay_us(4);
143 }
144
145 enum recstate {
146 IDLE = 0,
147 FIRST_FAST_SAMPLE,
148 FIRST_SLOW_SAMPLE, /* If clock arrives, we stay on the fast path! */
149 FAST_SAMPLE,
150 FAST_WAIT_FOR_CLOCK,
151 SLOW_SAMPLE,
152 SLOW_WAIT_FOR_CLOCK,
153 };
154
155 static enum recstate recstate = IDLE;
156
157 static inline void shift(uint8_t value)
158 {
159 shift_address <<= 1;
160 if (shift_function & 2)
161 shift_address |= 1;
162 shift_function <<= 1;
163 if (shift_command & 0x80)
164 shift_function |= 1;
165 shift_command <<= 1;
166 if (value)
167 shift_command |= 1;
168 }
169
170
171 ISR(TIMER0_COMPA_vect) {
172 static uint8_t patience = 0;
173 static uint8_t address_last = 0xff;
174 static uint8_t function_last = 0xff;
175 static uint8_t command_last = 0xff;
176
177 switch(recstate) {
178 case FIRST_FAST_SAMPLE:
179 recstate = FIRST_SLOW_SAMPLE;
180 TSTART_CLK_TO_SAMPLE_FAST; /* Will not run out in fast! */
181 break;
182
183 case FIRST_SLOW_SAMPLE:
184 bitno = 0;
185
186 case SLOW_SAMPLE:
187 recstate = SLOW_WAIT_FOR_CLOCK;
188 TSTART_CLK_TO_SAMPLE_SLOW;
189 break;
190
191 case FAST_SAMPLE:
192 recstate = FAST_WAIT_FOR_CLOCK;
193 TSTART_CLK_TO_SAMPLE_FAST;
194 break;
195
196 case FAST_WAIT_FOR_CLOCK: /* A timeout! */
197 if (patience) {
198 patience--;
199 TSTART_CLK_TO_SAMPLE_FAST;
200 return;
201 }
202 recstate = IDLE;
203 TSTOP;
204 return;
205
206 case SLOW_WAIT_FOR_CLOCK:
207 if (patience) {
208 patience--;
209 TSTART_CLK_TO_SAMPLE_SLOW;
210 return;
211 }
212 default:
213 TSTOP;
214 recstate = IDLE;
215 return;
216 }
217
218 shift(MM_SENSE);
219 bitno++;
220
221 if (bitno == 18) { /* Save first received word */
222 shift_command_first = shift_command;
223 shift_address_first = shift_address;
224 patience = 18;
225
226 }
227
228 if (bitno == 36) {
229 if ((shift_command == shift_command_first) &&
230 (shift_address == shift_address_first)) {
231 if ((shift_address != address_last) || (shift_command != command_last) ||
232 shift_function != function_last) {
233
234 uint8_t addr = lookup_decoder(shift_address);
235
236 if (recstate == SLOW_WAIT_FOR_CLOCK) {
237 mm_switch_drive(addr, shift_function, shift_command);
238 }
239
240
241 if (recstate == FAST_WAIT_FOR_CLOCK && addr) {
242 uint8_t command = lookup_command(shift_command);
243 /* Congratulations, we have a valid command */
244 mm_switch_command(addr, command);
245 }
246 }
247 address_last = shift_address;
248 function_last = shift_function;
249 command_last = shift_command;
250 }
251
252 }
253 }
254
255 //void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t command);
256
257 ISR(BADISR_vect)
258 {
259 while(1) {
260 /*
261 setpin(PIN_LED, 1);
262 _delay_ms(30);
263 setpin(PIN_LED, 0);
264 _delay_ms(30);
265 setpin(PIN_LED, 1);
266 _delay_ms(30);
267 setpin(PIN_LED, 0);
268 _delay_ms(2000);
269 */
270 }
271 }
272
273 ISR(TIM0_OVF_vect)
274 {
275 return;
276 while(1) {
277 setpin(PIN_LED, 1);
278 _delay_ms(30);
279 setpin(PIN_LED, 0);
280 _delay_ms(300);
281 }
282
283 }
284
285
286 /* Pin change interrupt vector */
287 void mm_pinchange_handler(void)
288 {
289 static uint8_t sense_last;
290
291 if (MM_SENSE == sense_last)
292 return;
293 sense_last = MM_SENSE;
294 if (!sense_last)
295 return;
296
297 switch(recstate) {
298 case IDLE:
299 bitno = 0;
300 recstate = FIRST_FAST_SAMPLE;
301 TSTART_CLK_TO_SAMPLE_FAST;
302 break;
303 case FIRST_SLOW_SAMPLE:
304 recstate = FAST_SAMPLE;
305 TSTART_CLK_TO_SAMPLE_FAST;
306 break;
307 case FAST_WAIT_FOR_CLOCK:
308 recstate = FAST_SAMPLE;
309 TSTART_CLK_TO_SAMPLE_FAST;
310 break;
311 case SLOW_WAIT_FOR_CLOCK:
312 recstate = SLOW_SAMPLE;
313 TSTART_CLK_TO_SAMPLE_SLOW;
314 break;
315
316 /* Not expected */
317 case FIRST_FAST_SAMPLE:
318 case FAST_SAMPLE:
319 case SLOW_SAMPLE:
320 default:
321 break;
322 }
323 }
324
325 /******************************************************************************
326 * The end :-)
327 */
328
329
330