]> git.tdb.fi Git - model-railway-devices.git/blob - firmware/s88w-r.c
Support multiple timers (currently 0 and 1)
[model-railway-devices.git] / firmware / s88w-r.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 Firmware for wireless S88 receiver module
8
9 S88 pinout:
10 1 - DATA
11 2 - GND
12 3 - CLOCK
13 4 - LOAD
14 5 - RESET
15 6 - POWER
16
17 ATMega pinout:
18 D0 - serial RX
19 D1 - serial TX
20 D2 - S88 DATA
21 D3 - S88 CLOCK
22 D4 - S88 LOAD
23 D5 - S88 RESET
24 */
25
26 #include <avr/io.h>
27 #include <avr/interrupt.h>
28 #include "lcd.h"
29 #include "serial.h"
30 #include "delay.h"
31
32 #define DATA_OUT PORTD2
33 #define CLOCK    PIND3
34 #define LOAD     PIND4
35 #define RESET    PIND5
36
37 #define BIT(n)   (1<<(n))
38
39 void receive(uint8_t);
40 uint8_t hexdigit(uint8_t);
41 uint8_t decode_hex(uint8_t);
42
43 volatile uint8_t rx_buf[7];
44 volatile uint8_t rx_fill = 0xFF;
45 volatile uint8_t input[128] = { 0 };
46 volatile uint8_t latch[128] = { 0 };
47 uint8_t log_pos = 0;
48
49 int main()
50 {
51         uint8_t clock_high = 0;
52         uint8_t bits = 0;
53         uint8_t n_bits = 8;
54         uint8_t offset = 0;
55         uint8_t i;
56
57         DDRD = 0x06;   // 00000110
58         PORTD = 0xC0;  // 11000000
59         DDRB = 0x20;   // 00100000
60         PORTB = 0x1F;  // 00011111
61
62         serial_init(9600);
63         lcd_init();
64
65         sei();
66
67         lcd_clear();
68         for(i=0; i<20; ++i)
69                 lcd_write('0');
70
71         while(1)
72         {
73                 uint8_t d_pins;
74
75                 d_pins = PIND;
76
77                 if(d_pins&BIT(CLOCK))
78                 {
79                         if(!clock_high)
80                         {
81                                 if(d_pins&BIT(LOAD))
82                                 {
83                                         offset = 0;
84                                         bits = latch[0];
85                                         n_bits = 8;
86                                 }
87                                 else
88                                 {
89                                         bits >>= 1;
90                                         if(!--n_bits)
91                                         {
92                                                 ++offset;
93                                                 bits = latch[offset];
94                                                 n_bits = 8;
95                                         }
96                                 }
97
98                                 if(bits&1)
99                                         PORTD |= BIT(DATA_OUT);
100                                 else
101                                         PORTD &= ~BIT(DATA_OUT);
102
103                                 clock_high = 1;
104                         }
105                 }
106                 else if(clock_high)
107                         clock_high = 0;
108
109                 if(d_pins&BIT(RESET))
110                 {
111                         uint8_t i;
112                         for(i=0; i<128; ++i)
113                                 latch[i] = input[i];
114                 }
115         }
116 }
117
118 void receive(uint8_t c)
119 {
120         if(rx_fill==0xFF)
121         {
122                 if(c==':')
123                         rx_fill = 0;
124         }
125         else if(c=='.')
126         {
127                 if(rx_fill>=4)
128                 {
129                         uint16_t offset;
130                         uint8_t nibbles;
131                         uint8_t i;
132
133                         offset = (decode_hex(rx_buf[0])<<8) | (decode_hex(rx_buf[1])<<4) | decode_hex(rx_buf[2]);
134                         nibbles = (offset&3);
135                         offset >>= 2;
136                         if(rx_fill>3+nibbles)
137                         {
138                                 for(i=0; i<=nibbles; ++i)
139                                 {
140                                         uint16_t j = offset+nibbles-i;
141                                         uint8_t shift = 4*(j&1);
142                                         uint8_t bits = decode_hex(rx_buf[3+i]);
143                                         input[j/2] = (input[j/2]&~(0xF<<shift)) | (bits<<shift);
144                                         latch[j/2] = input[j/2];
145                                 }
146
147                                 lcd_gotoxy(19-offset-nibbles, 0);
148                                 for(i=0; i<=nibbles; ++i)
149                                         lcd_write(rx_buf[3+i]);
150                                 log_pos |= 0x80;
151                         }
152                 }
153                 rx_fill = 0xFF;
154         }
155         else
156         {
157                 if(rx_fill<sizeof(rx_buf))
158                         rx_buf[rx_fill++] = c;
159                 else
160                         rx_fill = 0xFF;
161         }
162
163         lcd_gotoxy(log_pos%20, 1+log_pos/20);
164         lcd_write(c);
165         ++log_pos;
166         if(log_pos>=60)
167                 log_pos = 0;
168         if(log_pos%20==0)
169                 lcd_gotoxy(log_pos%20, 1+log_pos/20);
170         lcd_write(255);
171 }
172
173 SERIAL_SET_CALLBACK(receive)
174
175 uint8_t hexdigit(uint8_t n)
176 {
177         n &= 0xF;
178         if(n<10)
179                 return '0'+n;
180         else
181                 return 'A'+(n-0xA);
182 }
183
184 uint8_t decode_hex(uint8_t c)
185 {
186         if(c>='0' && c<='9')
187                 return c-'0';
188         else if(c>='A' && c<='F')
189                 return 0xA+(c-'A');
190         else
191                 return 0;
192 }