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