2b09e5cbeaf5dda4d387f85b7f488fd0373b8b3e
1 /******************************************************************************
3 * Trennfix firmware - mm_switch.c
5 * Maerklin Motorola switch command receiver
7 * Copyright (C) 2017 Philipp Hachtmann
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.
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.
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/>.
22 *****************************************************************************/
29 #include <avr/eeprom.h>
30 #include <avr/interrupt.h>
31 #include <avr/pgmspace.h>
33 #include <util/delay.h>
36 #include <config/hardware.h>
37 #include <mm/mm_switch.h>
46 FIRST_SLOW_SAMPLE
, /* If clock arrives, we stay on the fast path! */
55 * Check for stuff we need
58 #if !defined(MM_TSTART_FAST) || !defined(MM_TSTART_SLOW) || !defined(MM_TSTOP) \
59 || !defined(MM_SENSE) || !defined(MM_TIMER_INT_VECT)
61 #error Missing timer start macro MM_TSTART_FAST!
66 * Private global variables
68 static volatile uint8_t shift_command
;
69 static volatile uint8_t shift_function
;
70 static volatile uint8_t shift_address
;
71 static enum recstate recstate
= IDLE
;
72 volatile uint8_t bitno
= 0;
76 * Lookup trinary nibble
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.
82 static const uint8_t nibble_table
[16]={
93 #define lookup_nibble(nibble) nibble_table[nibble & 0xf]
95 static uint8_t lookup_decoder(uint8_t mm_byte
)
101 low
= lookup_nibble(mm_byte
>> 4);
102 high
= lookup_nibble(mm_byte
& 0xf);
105 return 9 * high
+ low
;
108 static uint8_t lookup_command(uint8_t mm_byte
)
124 /* We will shift from right to left.
125 * XXXXXXXX XX XXXXXXXX
126 * shift_address shift_function shift_command
128 * The bits 7 downto 2 of shift_function are ignored.
131 static inline void shift(uint8_t value
)
134 if (shift_function
& 2)
136 shift_function
<<= 1;
137 if (shift_command
& 0x80)
144 ISR(MM_TIMER_INT_VECT
) {
145 static uint8_t tolerated_timeouts
= 0;
147 static volatile uint8_t shift_command_first
;
148 static volatile uint8_t shift_function_first
;
149 static volatile uint8_t shift_address_first
;
153 #ifdef MM_FILTER_REPEATED
154 static uint8_t address_last
= 0xff;
155 static uint8_t function_last
= 0xff;
156 static uint8_t command_last
= 0xff;
160 case FIRST_FAST_SAMPLE
:
161 recstate
= FIRST_SLOW_SAMPLE
;
162 MM_TSTART_FAST
; /* Will not run out in fast! */
165 case FIRST_SLOW_SAMPLE
:
169 recstate
= SLOW_WAIT_FOR_CLOCK
;
174 recstate
= FAST_WAIT_FOR_CLOCK
;
178 case FAST_WAIT_FOR_CLOCK
: /* A timeout! */
179 if (tolerated_timeouts
) {
180 tolerated_timeouts
--;
188 case SLOW_WAIT_FOR_CLOCK
:
189 if (tolerated_timeouts
) {
190 tolerated_timeouts
--;
203 if (bitno
== 18) { /* Save first received word */
204 shift_address_first
= shift_address
;
205 shift_function_first
= shift_function
;
206 shift_command_first
= shift_command
;
208 tolerated_timeouts
= 18;
212 if ((shift_command
== shift_command_first
) &&
213 (shift_address
== shift_address_first
) &&
214 (shift_function
== shift_function_first
)) {
216 #ifdef MM_FILTER_REPEATED
217 if ((shift_address
!= address_last
) || (shift_command
!= command_last
) ||
218 shift_function
!= function_last
) {
220 address
= lookup_decoder(shift_address
);
222 if (recstate
== SLOW_WAIT_FOR_CLOCK
) {
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
);
228 #ifdef MM_FILTER_REPEATED
230 address_last
= shift_address
;
231 function_last
= shift_function
;
232 command_last
= shift_command
;
239 //void __attribute((weak)) mm_switch_drive(uint8_t address, uint8_t function, uint8_t command);
269 /* Pin change interrupt vector */
270 void mm_pinchange_handler(void)
272 static uint8_t sense_last
;
274 if (MM_SENSE
== sense_last
)
276 sense_last
= MM_SENSE
;
283 recstate
= FIRST_FAST_SAMPLE
;
286 case FIRST_SLOW_SAMPLE
:
287 recstate
= FAST_SAMPLE
;
290 case FAST_WAIT_FOR_CLOCK
:
291 recstate
= FAST_SAMPLE
;
294 case SLOW_WAIT_FOR_CLOCK
:
295 recstate
= SLOW_SAMPLE
;
300 case FIRST_FAST_SAMPLE
:
308 void __attribute__((weak
))mm_switch_drive(uint8_t decoder
, uint8_t function
,
314 void __attribute__((weak
))mm_switch_command(uint8_t address
, uint8_t command
)
319 /******************************************************************************