]> git.tdb.fi Git - r2c2.git/blob - firmware/ctrl.c
Halt all trains in various unexpected situations
[r2c2.git] / firmware / ctrl.c
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2010  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <avr/io.h>
9 #include <avr/interrupt.h>
10
11 #define BIT(n) (1<<(n))
12 #define NOP() __asm__("nop");
13
14 uint8_t digits[11] =
15 {
16         0x3F,
17         0x06,
18         0x5B,
19         0x4F,
20         0x66,
21         0x6D,
22         0x7D,
23         0x07,
24         0x7F,
25         0x6F,
26         0x40
27 };
28
29 uint16_t read_input(void);
30 uint16_t read_input_filtered(void);
31 void write_serial(uint8_t);
32 void write_7seg(uint8_t);
33
34 uint8_t speed = 0;
35 uint16_t funcs = 0;
36 volatile uint8_t ticks = 0;
37 volatile uint8_t rx_buf[3];
38 volatile uint8_t rx_fill = 0;
39
40 ISR(TIMER1_COMPA_vect)
41 {
42         if(ticks<255)
43                 ++ticks;
44 }
45
46 ISR(USART_RX_vect)
47 {
48         uint8_t c = UDR0;
49         if(rx_fill==0)
50         {
51                 if(c=='A' || c=='S')
52                         rx_buf[rx_fill++] = c;
53         }
54         else
55         {
56                 rx_buf[rx_fill++] = c;
57                 if(rx_buf[0]=='A' && rx_fill==3)
58                 {
59                         uint8_t n = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
60                         write_7seg(n/10);
61                         write_7seg(n%10);
62                         rx_fill = 0;
63                 }
64                 else if(rx_buf[0]=='S' && rx_fill==3)
65                 {
66                         speed = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
67                         rx_fill = 0;
68                 }
69         }
70 }
71
72 int main()
73 {
74         uint16_t state = 0;
75
76         DDRD = 0x02;   // 00000010
77         PORTD = 0xFC;  // 11111100
78         DDRB = 0x3F;   // 00111111
79         PORTB = 0x0F;  // 00001111
80
81         write_7seg(10);
82         write_7seg(10);
83
84         // 9600 baud, 8N1
85         UBRR0H = 0;
86         UBRR0L = 103;
87         UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);
88         UCSR0B = BIT(RXEN0) | BIT(TXEN0) | BIT(RXCIE0);
89
90         TCCR1A = 0;
91         TCCR1B = BIT(WGM12) | BIT(CS12);
92         OCR1AH = 24;
93         OCR1AL = 106;
94         TIMSK1 = BIT(OCIE1A);
95
96         sei();
97
98         while(1)
99         {
100                 uint16_t toggled;
101                 uint8_t i;
102                 uint16_t input;
103
104                 input = read_input_filtered();
105                 input ^= 0xFFFC;
106
107                 toggled = state^input;
108                 state = input;
109
110                 if((toggled&3)==2 && (state&1))
111                 {
112                         uint8_t action = 0;
113                         if(state&2)
114                         {
115                                 if(speed<14)
116                                 {
117                                         ++speed;
118                                         action = 1;
119                                 }
120                         }
121                         else
122                         {
123                                 if(speed>0)
124                                 {
125                                         --speed;
126                                         action = 1;
127                                 }
128                                 else if(ticks>10)
129                                         action = 2;
130                         }
131
132                         if(action==1)
133                         {
134                                 write_serial('S');
135                                 write_serial('0'+speed/10);
136                                 write_serial('0'+speed%10);
137                         }
138                         else if(action==2)
139                                 write_serial('R');
140
141                         ticks = 0;
142                 }
143
144                 for(i=0; i<14; ++i)
145                 {
146                         uint16_t bit = 4<<i;
147                         if(toggled&~state&bit)
148                         {
149                                 if(i==0)
150                                         write_serial('N');
151                                 else if(i==1)
152                                         write_serial('P');
153                                 else
154                                 {
155                                         uint8_t f = i-2;
156                                         uint16_t fbit = 1<<f;
157                                         funcs ^= fbit;
158                                         write_serial((funcs&fbit) ? 'H' : 'L');
159                                         write_serial('0'+f);
160                                 }
161                         }
162                 }
163         }
164 }
165
166 uint16_t read_input(void)
167 {
168         uint8_t row;
169         uint16_t input = 0;
170
171         for(row=0; row<4; ++row)
172         {
173                 uint8_t pins;
174
175                 PORTB = (PORTB|0x0F)&~(1<<row);
176                 NOP();
177                 NOP();
178                 NOP();
179                 NOP();
180                 NOP();
181                 NOP();
182                 pins = PIND>>2;
183                 input |= pins&3;
184                 input |= (pins&0x3C)<<(row*4);
185         }
186
187         return input;
188 }
189
190 uint16_t read_input_filtered(void)
191 {
192         uint16_t valid = 0xFFFF;
193         uint16_t prev;
194         uint16_t input;
195         uint8_t i;
196
197         prev = read_input();
198         for(i=0; i<20; ++i)
199         {
200                 input = read_input();
201                 valid &= ~(input^prev);
202                 prev = input;
203         }
204
205         return input&valid;
206 }
207
208 void write_serial(uint8_t c)
209 {
210         while(!(UCSR0A&(1<<UDRE0))) ;
211         UDR0 = c;
212 }
213
214 void write_7seg(uint8_t n)
215 {
216         uint8_t segs = ~digits[n];
217         uint8_t i;
218         for(i=0; i<8; ++i)
219         {
220                 PORTB &= ~0x20;
221                 if(segs&0x80)
222                         PORTB |= 0x10;
223                 else
224                         PORTB &= ~0x10;
225                 PORTB |= 0x20;
226                 segs <<= 1;
227         }
228 }