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