trennfix/sw: More versatile file structure
[eisenbahn.git] / trennfix / sw / mm / src / mm_switch.c
CommitLineData
70095677
PH
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
93cb14d4
PH
36#include <config/hardware.h>
37#include <mm/mm_switch.h>
70095677 38
93cb14d4
PH
39/*
40 * Private data types
41 */
42
43enum recstate {
44 IDLE = 0,
45 FIRST_FAST_SAMPLE,
46 FIRST_SLOW_SAMPLE, /* If clock arrives, we stay on the fast path! */
47 FAST_SAMPLE,
48 FAST_WAIT_FOR_CLOCK,
49 SLOW_SAMPLE,
50 SLOW_WAIT_FOR_CLOCK,
51};
70095677
PH
52
53/*
93cb14d4
PH
54 *
55 * Check for stuff we need
70095677
PH
56 *
57 */
93cb14d4
PH
58#if !defined(MM_TSTART_FAST) || !defined(MM_TSTART_SLOW) || !defined(MM_TSTOP) \
59 || !defined(MM_SENSE) || !defined(MM_TIMER_INT_VECT)
56b25f8b 60
93cb14d4 61#error Missing timer start macro MM_TSTART_FAST!
56b25f8b 62
93cb14d4
PH
63#endif
64
65/*
66 * Private global variables
67 */
68static volatile uint8_t shift_command;
69static volatile uint8_t shift_function;
70static volatile uint8_t shift_address;
71static enum recstate recstate = IDLE;
72volatile uint8_t bitno = 0;
73
74
75/*
76 * Lookup trinary nibble
77 *
78 * This was implemented using a switch statement before.
79 * Changing the lookup to a table did only add two bytes
80 * of memory and saved ca. 50 bytes program memory.
81 */
82static const uint8_t nibble_table[16]={
83 [0x0] = 0,
84 [0xc] = 1,
85 [0x8] = 2,
86 [0x3] = 3,
87 [0xf] = 4,
88 [0xb] = 5,
89 [0x2] = 6,
90 [0xe] = 7,
91 [0xa] = 8
92};
93#define lookup_nibble(nibble) nibble_table[nibble & 0xf]
94
70095677
PH
95static uint8_t lookup_decoder(uint8_t mm_byte)
96{
56b25f8b
PH
97 uint8_t low;
98 uint8_t high;
99 if (mm_byte == 0)
93cb14d4 100 return 80;
56b25f8b
PH
101 low = lookup_nibble(mm_byte >> 4);
102 high = lookup_nibble(mm_byte & 0xf);
103 if (!low)
70095677 104 return 0;
56b25f8b 105 return 9 * high + low;
70095677
PH
106}
107
108static uint8_t lookup_command(uint8_t mm_byte)
109{
110 switch(mm_byte) {
111 case 0xc3: return 1;
112 case 0x03: return 2;
113 case 0xf3: return 3;
114 case 0x33: return 4;
115 case 0xcf: return 5;
116 case 0x0f: return 6;
117 case 0xff: return 7;
118 case 0x3f: return 8;
119 default:
120 return 0;
121 }
122}
123
70095677
PH
124/* We will shift from right to left.
125 * XXXXXXXX XX XXXXXXXX
56b25f8b 126 * shift_address shift_function shift_command
70095677 127 *
56b25f8b 128 * The bits 7 downto 2 of shift_function are ignored.
70095677
PH
129 */
130
70095677
PH
131static inline void shift(uint8_t value)
132{
56b25f8b
PH
133 shift_address <<= 1;
134 if (shift_function & 2)
135 shift_address |= 1;
136 shift_function <<= 1;
137 if (shift_command & 0x80)
138 shift_function |= 1;
139 shift_command <<= 1;
70095677 140 if (value)
56b25f8b 141 shift_command |= 1;
70095677
PH
142}
143
93cb14d4
PH
144ISR(MM_TIMER_INT_VECT) {
145 static uint8_t tolerated_timeouts = 0;
70095677 146
93cb14d4
PH
147 static volatile uint8_t shift_command_first;
148 static volatile uint8_t shift_function_first;
149 static volatile uint8_t shift_address_first;
150 uint8_t address;
151 uint8_t command;
152
153#ifdef MM_FILTER_REPEATED
56b25f8b
PH
154 static uint8_t address_last = 0xff;
155 static uint8_t function_last = 0xff;
156 static uint8_t command_last = 0xff;
93cb14d4 157#endif
70095677
PH
158
159 switch(recstate) {
160 case FIRST_FAST_SAMPLE:
161 recstate = FIRST_SLOW_SAMPLE;
93cb14d4 162 MM_TSTART_FAST; /* Will not run out in fast! */
70095677
PH
163 break;
164
165 case FIRST_SLOW_SAMPLE:
166 bitno = 0;
167
168 case SLOW_SAMPLE:
169 recstate = SLOW_WAIT_FOR_CLOCK;
93cb14d4 170 MM_TSTART_SLOW;
70095677
PH
171 break;
172
173 case FAST_SAMPLE:
174 recstate = FAST_WAIT_FOR_CLOCK;
93cb14d4 175 MM_TSTART_FAST;
70095677
PH
176 break;
177
178 case FAST_WAIT_FOR_CLOCK: /* A timeout! */
93cb14d4
PH
179 if (tolerated_timeouts) {
180 tolerated_timeouts--;
181 MM_TSTART_FAST;
70095677
PH
182 return;
183 }
184 recstate = IDLE;
93cb14d4 185 MM_TSTOP;
70095677
PH
186 return;
187
188 case SLOW_WAIT_FOR_CLOCK:
93cb14d4
PH
189 if (tolerated_timeouts) {
190 tolerated_timeouts--;
191 MM_TSTART_SLOW;
70095677
PH
192 return;
193 }
56b25f8b 194 default:
93cb14d4 195 MM_TSTOP;
70095677
PH
196 recstate = IDLE;
197 return;
198 }
199
200 shift(MM_SENSE);
201 bitno++;
56b25f8b 202
70095677 203 if (bitno == 18) { /* Save first received word */
93cb14d4
PH
204 shift_address_first = shift_address;
205 shift_function_first = shift_function;
206 shift_command_first = shift_command;
70095677 207
93cb14d4 208 tolerated_timeouts = 18;
70095677 209 }
56b25f8b 210
70095677 211 if (bitno == 36) {
56b25f8b 212 if ((shift_command == shift_command_first) &&
93cb14d4
PH
213 (shift_address == shift_address_first) &&
214 (shift_function == shift_function_first)) {
215
216#ifdef MM_FILTER_REPEATED
56b25f8b
PH
217 if ((shift_address != address_last) || (shift_command != command_last) ||
218 shift_function != function_last) {
93cb14d4
PH
219#endif
220 address = lookup_decoder(shift_address);
56b25f8b
PH
221
222 if (recstate == SLOW_WAIT_FOR_CLOCK) {
93cb14d4
PH
223 mm_switch_drive(address, shift_function, shift_command);
224 } else if (recstate == FAST_WAIT_FOR_CLOCK) {
225 command = lookup_command(shift_command);
226 mm_switch_command(address, command);
70095677 227 }
93cb14d4 228#ifdef MM_FILTER_REPEATED
70095677 229 }
93cb14d4
PH
230 address_last = shift_address;
231 function_last = shift_function;
232 command_last = shift_command;
233#endif
70095677 234 }
56b25f8b 235
70095677
PH
236 }
237}
238
56b25f8b
PH
239//void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t command);
240
70095677
PH
241ISR(BADISR_vect)
242{
243 while(1) {
244 /*
245 setpin(PIN_LED, 1);
246 _delay_ms(30);
247 setpin(PIN_LED, 0);
248 _delay_ms(30);
249 setpin(PIN_LED, 1);
250 _delay_ms(30);
251 setpin(PIN_LED, 0);
252 _delay_ms(2000);
253 */
254 }
255}
256
257ISR(TIM0_OVF_vect)
258{
259 return;
260 while(1) {
56b25f8b 261 setpin(PIN_LED, 1);
70095677
PH
262 _delay_ms(30);
263 setpin(PIN_LED, 0);
264 _delay_ms(300);
265 }
266
267}
268
70095677
PH
269/* Pin change interrupt vector */
270void mm_pinchange_handler(void)
271{
272 static uint8_t sense_last;
273
274 if (MM_SENSE == sense_last)
275 return;
276 sense_last = MM_SENSE;
277 if (!sense_last)
278 return;
56b25f8b 279
70095677
PH
280 switch(recstate) {
281 case IDLE:
282 bitno = 0;
283 recstate = FIRST_FAST_SAMPLE;
93cb14d4 284 MM_TSTART_FAST;
70095677
PH
285 break;
286 case FIRST_SLOW_SAMPLE:
287 recstate = FAST_SAMPLE;
93cb14d4 288 MM_TSTART_FAST;
70095677
PH
289 break;
290 case FAST_WAIT_FOR_CLOCK:
291 recstate = FAST_SAMPLE;
93cb14d4 292 MM_TSTART_FAST;
70095677
PH
293 break;
294 case SLOW_WAIT_FOR_CLOCK:
295 recstate = SLOW_SAMPLE;
93cb14d4 296 MM_TSTART_SLOW;
70095677
PH
297 break;
298
299 /* Not expected */
300 case FIRST_FAST_SAMPLE:
301 case FAST_SAMPLE:
302 case SLOW_SAMPLE:
303 default:
304 break;
305 }
306}
307
93cb14d4
PH
308void __attribute__((weak))mm_switch_drive(uint8_t decoder, uint8_t function,
309 uint8_t command)
310{
311 while(1);
312}
313
314void __attribute__((weak))mm_switch_command(uint8_t address, uint8_t command)
315{
316}
317
318
70095677
PH
319/******************************************************************************
320 * The end :-)
321 */
322
323
324