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>
37 #include "mm_switch.h"
41 #define MON(val) setpin(PIN_DRIVE, val)
43 #define MON(xx) ({0;})
48 * Lookup decoder number.
51 static uint8_t lookup_decoder(uint8_t mm_byte
)
88 static uint8_t lookup_command(uint8_t mm_byte
)
104 static void mm_switch_init(void)
106 /* Get rid of the 1/8 clock prescaler */
107 CLKPR
= (1 << CLKPCE
);
110 GIMSK
|= _BV(PCIE
); /* Enable pin change interrupt */
111 PCMSK
= _BV(PCINT4
); /* PB4, Rail sense input */
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 */
118 /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
119 OCR0A
= 91; /* Prescaler 8 is used */
121 /* Timer 1 for timeout */
122 /* We set it to 1024us by prescaler 64 and running full 256 */
124 TIMSK
|= _BV(TOIE1
); /* Overflow interrupt */
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
;
134 /* We will shift from right to left.
135 * XXXXXXXX XX XXXXXXXX
136 * shift_decoder shift_zero shift_sub
138 * The bits 7 downto 2 of shift_zero are ignored.
141 volatile uint8_t bitno
= 0;
143 static void trigger(void)
145 setpin(PIN_DRIVE
, 1);
147 setpin(PIN_DRIVE
, 0);
153 FIRST_SLOW_SAMPLE
, /* If clock arrives, we stay on the fast path! */
160 static enum recstate recstate
= IDLE
;
162 static inline void shift(uint8_t value
)
168 if (shift_sub
& 0x80)
176 ISR(TIMER0_COMPA_vect
) {
178 static uint8_t patience
= 0;
181 case FIRST_FAST_SAMPLE
:
182 recstate
= FIRST_SLOW_SAMPLE
;
183 TSTART_CLK_TO_SAMPLE_FAST
; /* Will not run out in fast! */
186 case FIRST_SLOW_SAMPLE
:
190 recstate
= SLOW_WAIT_FOR_CLOCK
;
191 TSTART_CLK_TO_SAMPLE_SLOW
;
195 recstate
= FAST_WAIT_FOR_CLOCK
;
196 TSTART_CLK_TO_SAMPLE_FAST
;
199 case FAST_WAIT_FOR_CLOCK
: /* A timeout! */
202 TSTART_CLK_TO_SAMPLE_FAST
;
209 case SLOW_WAIT_FOR_CLOCK
:
212 TSTART_CLK_TO_SAMPLE_SLOW
;
223 if (bitno
== 18) { /* Save first received word */
224 shift_sub_first
= shift_sub
;
225 shift_decoder_first
= shift_decoder
;
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
)
237 /* Congratulations, we have a valid command */
238 if (recstate
== FAST_WAIT_FOR_CLOCK
) {
240 mm_switch_command(decoder
, command
);
276 /* Pin change interrupt vector */
277 void mm_pinchange_handler(void)
279 static uint8_t sense_last
;
281 if (MM_SENSE
== sense_last
)
283 sense_last
= MM_SENSE
;
290 recstate
= FIRST_FAST_SAMPLE
;
291 TSTART_CLK_TO_SAMPLE_FAST
;
293 case FIRST_SLOW_SAMPLE
:
294 recstate
= FAST_SAMPLE
;
295 TSTART_CLK_TO_SAMPLE_FAST
;
297 case FAST_WAIT_FOR_CLOCK
:
298 recstate
= FAST_SAMPLE
;
299 TSTART_CLK_TO_SAMPLE_FAST
;
301 case SLOW_WAIT_FOR_CLOCK
:
302 recstate
= SLOW_SAMPLE
;
303 TSTART_CLK_TO_SAMPLE_SLOW
;
307 case FIRST_FAST_SAMPLE
:
315 /******************************************************************************