trennfix/sw: Some cleanup
[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"
af5fd980 35#include "mm_lookup.h"
54de37bf 36
af5fd980 37#define LED _PIN(PORTB, PORTB2)
54de37bf
PH
38#define SENSE _PIN(PORTB, PORTB4)
39#define DRIVE _PIN(PORTB, PORTB3)
40#define BTN _PIN(PORTB, PB1)
41
42#define SIGIN (!PINVAL(SENSE))
af5fd980 43#define BTN_PRESSED (!PINVAL(BTN))
54de37bf
PH
44
45// #define DEBUG_TIMEOUT
54de37bf
PH
46#ifdef DEBUG_TIMEOUT
47#define MON_TIMEOUT(val) setpin(DRIVE, val)
48#else
49#define MON_TIMEOUT(xx) ({0;})
50#endif
51
af5fd980
PH
52uint8_t EEMEM ee_our_decoder;
53uint8_t EEMEM ee_our_key;
54de37bf
PH
54
55static void setup_hw(void)
56{
57 /* Get rid of the 1/8 clock prescaler */
58 CLKPR = (1 << CLKPCE);
59 CLKPR = 0;
60
61 INPUT_PIN(SENSE);
62 INPUT_PIN(BTN);
63 OUTPUT_PIN(DRIVE);
64 OUTPUT_PIN(LED);
65 setpin(BTN, 1); /* Need pullup */
66 _delay_ms(1); /* Let the line rise */
67
68
69 GIMSK |= _BV(PCIE); /* Enable pin change interrupt */
70 PCMSK = _BV(PCINT4); /* PB4, Rail sense input */
71
72 TCCR0A = 0; /* This is normal mode */
73 TCCR0B = 0; /* Timer off */
74 TIMSK |= _BV(OCIE0A); /* Get a match interrupt */
75 TIMSK |= _BV(TOV0); /* Overflow interrupt */
76
77 /* We need 13 + 45 us delay, That's 464 clocks @8MHz*/
78 OCR0A = 91; /* Prescaler 8 is used */
79
80 /* Timer 1 for timeout */
81 /* We set it to 1024us by prescaler 64 and running full 256 */
82 TCCR1 = 7;
83 TIMSK |= _BV(TOIE1); /* Overflow interrupt */
84}
85
86static uint8_t ctr = 0;
87
88static volatile uint8_t shift_sub;
89static volatile uint8_t shift_zero;
90static volatile uint8_t shift_decoder;
91static volatile uint8_t shift_sub_first;
92static volatile uint8_t shift_decoder_first;
93
94/* We will shift from right to left.
95 * XXXXXXXX XX XXXXXXXX
96 * shift_decoder shift_zero shift_sub
97 *
98 * The bits 7 downto 2 of shift_zero are ignored.
99 */
100
101#define STOP_TIMER0 (TCCR0B = 0)
102
103volatile uint8_t bitno = 0;
104
105
106static void zero(void)
107{
108 setpin(LED, 1);
109 _delay_ms(20);
110 setpin(LED, 0);
111 _delay_ms(980);
112 GIFR |= _BV(PCIF);
113}
114
115
116static void one(void)
117{
118 setpin(LED, 1);
119 _delay_ms(20);
120 setpin(LED, 0);
121 _delay_ms(160);
122 setpin(LED, 1);
123 _delay_ms(20);
124 setpin(LED, 0);
125 _delay_ms(800);
126 GIFR |= _BV(PCIF);
127}
128
129static void trigger(void)
130{
af5fd980 131 return;
54de37bf
PH
132 setpin(DRIVE, 1);
133 _delay_us(20);
134 setpin(DRIVE, 0);
135}
136
137static volatile uint8_t our_decoder = 3;
138static volatile uint8_t our_key = 5;
139static volatile uint8_t learn_mode = 0;
af5fd980 140static volatile uint8_t drive_on = 0;
54de37bf
PH
141
142ISR(TIMER0_COMPA_vect) {
143
144 STOP_TIMER0;
145
146 shift_decoder <<= 1;
147 if (shift_zero & 2)
148 shift_decoder |= 1;
149 shift_zero <<= 1;
150 if (shift_sub & 0x80)
151 shift_zero |= 1;
152 shift_sub <<= 1;
153 if (SIGIN)
154 shift_sub |= 1;
155
156 bitno++;
157
158 if (bitno == 18) { /* Save first received word */
159 shift_sub_first = shift_sub;
160 shift_decoder_first = shift_decoder;
161 } else if (bitno == 36) {
162
163 if ((shift_sub == shift_sub_first) &&
164 (shift_decoder == shift_decoder_first)) {
af5fd980
PH
165 uint8_t decoder = lookup_decoder(shift_decoder);
166 uint8_t command = lookup_command(shift_sub);
54de37bf
PH
167 if (decoder) {
168 /* Congratulations, we have a valid command */
169 trigger();
170
171 if (learn_mode) {
172 if (command) {
173 our_decoder = decoder;
174 our_key = command;
175 learn_mode = 0;
af5fd980
PH
176 eeprom_write_byte(&ee_our_decoder, our_decoder);
177 eeprom_write_byte(&ee_our_key, our_key);
54de37bf
PH
178 }
179 } else {
54de37bf
PH
180 if (decoder == our_decoder) {
181 if (command == our_key)
af5fd980 182 drive_on = 1;
54de37bf 183 if (command == 0)
af5fd980 184 drive_on = 0;
54de37bf
PH
185 }
186 }
187 }
188 }
189 }
190}
191
192#define START_TIMER0 ({TCNT0 = 0; TCCR0B = 2;})
193#define START_TIMER1 ({TCNT1 = 1; TCCR1 = 7; GTCCR |= 2;})
194#define STOP_TIMER1 ({TCCR1 = 0; TCNT1 = 1;})
195
196ISR(TIM1_OVF_vect)
197{
198 STOP_TIMER1;
199 // if (!SIGIN)
200 // setpin(LED, 1);
201 bitno = 0;
202 MON_TIMEOUT(1);
203}
204
205ISR(TIM0_OVF_vect)
206{
207 while(1) {
208 setpin(LED, 1);
209 _delay_ms(30);
210 setpin(LED, 1);
211 _delay_ms(30);
212 }
213
214}
215
216/* Shortest element seen 184 clocks */
217/* Officially 208 clocks */
218/* (1 + 7) * 208 clocks */
219
220/* Pin change interrupt vector */
221ISR(PCINT0_vect)
222{
223 START_TIMER1;
224 MON_TIMEOUT(0);
225
226 if (SIGIN) {
227 START_TIMER0;
228 }
229}
230
231
232
233/******************************************************************************
234 *
235 * main() - The main routine
236 *
237 */
238
239int main(void) {
af5fd980
PH
240 uint8_t duty = 30;
241 uint8_t old_drive = 0;
54de37bf 242 setup_hw();
af5fd980
PH
243 our_decoder = eeprom_read_byte(&ee_our_decoder);
244 our_key = eeprom_read_byte(&ee_our_key);
245 if (our_decoder == 0xff)
246 learn_mode = 1;
54de37bf 247 sei();
af5fd980 248 uint8_t i;
54de37bf
PH
249 while (1) {
250 if (!learn_mode) {
af5fd980
PH
251 if (old_drive == 0 && drive_on) {
252 setpin(DRIVE, 1);
253 _delay_ms(100);
254 }
255 old_drive = drive_on;
256 setpin(DRIVE, drive_on);
257 for (i = 0; i < duty; i++)
258 _delay_us(4);
259 for (i = 0; i < (255 - duty); i++) {
260 setpin(DRIVE, 0);
261 _delay_us(4);
262 }
263
54de37bf
PH
264 if (!PINVAL(BTN))
265 learn_mode = 1;
266 } else {
267 setpin(LED, 1);
268 _delay_ms(30);
269 setpin(LED, 0);
270 _delay_ms(600);
271 }
272
273/* Main loop here */
274 }
275 return 0;
276}
277
278/******************************************************************************
279 * The end :-)
280 */