]> git.tdb.fi Git - model-railway-devices.git/blob - firmware/s88w-r.c
d2a21092adc82756ad6b99b545dff4e19e64637f
[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 LCD_DISABLE PINB4
38
39 #define BIT(n)   (1<<(n))
40
41 void receive(uint8_t);
42 uint8_t hexdigit(uint8_t);
43 uint8_t decode_hex(uint8_t);
44
45 volatile uint8_t rx_buf[7];
46 volatile uint8_t rx_fill = 0xFF;
47 volatile uint8_t input[128] = { 0 };
48 volatile uint8_t latch[128] = { 0 };
49 volatile uint8_t lcd_enabled = 0;
50 uint8_t log_row = 0;
51 uint8_t log_col = 0;
52
53 int main()
54 {
55         uint8_t clock_high = 0;
56         uint8_t bits = 0;
57         uint8_t n_bits = 8;
58         uint8_t offset = 0;
59         uint8_t i;
60
61         DDRD = 0x06;   // 00000110
62         PORTD = 0xC0;  // 11000000
63         DDRB = 0x20;   // 00100000
64         PORTB = 0x1F;  // 00011111
65
66         serial_init(9600);
67         lcd_init();
68
69         sei();
70
71         while(1)
72         {
73                 uint8_t b_pins, d_pins;
74
75                 b_pins = PINB;
76                 d_pins = PIND;
77
78                 if(d_pins&BIT(CLOCK))
79                 {
80                         if(!clock_high)
81                         {
82                                 if(d_pins&BIT(LOAD))
83                                 {
84                                         offset = 0;
85                                         bits = latch[0];
86                                         n_bits = 8;
87                                 }
88                                 else
89                                 {
90                                         bits >>= 1;
91                                         if(!--n_bits)
92                                         {
93                                                 ++offset;
94                                                 bits = latch[offset];
95                                                 n_bits = 8;
96                                         }
97                                 }
98
99                                 if(bits&1)
100                                         PORTD |= BIT(DATA_OUT);
101                                 else
102                                         PORTD &= ~BIT(DATA_OUT);
103
104                                 clock_high = 1;
105                         }
106                 }
107                 else if(clock_high)
108                         clock_high = 0;
109
110                 if(d_pins&BIT(RESET))
111                 {
112                         uint8_t i;
113                         for(i=0; i<128; ++i)
114                                 latch[i] = input[i];
115                 }
116
117                 if(b_pins&BIT(LCD_DISABLE))
118                 {
119                         if(lcd_enabled)
120                         {
121                                 lcd_enabled = 0;
122
123                                 lcd_clear();
124                         }
125                 }
126                 else if(!lcd_enabled)
127                 {
128                         lcd_enabled = 1;
129                         log_row = 0;
130                         log_col = 0;
131
132                         lcd_clear();
133                         for(i=0; i<20; ++i)
134                                 lcd_write(hexdigit(input[9-i/2]>>(4-i%2*4)));
135                         lcd_gotoxy(0, 1);
136                         lcd_write(255);
137                 }
138         }
139 }
140
141 void receive(uint8_t c)
142 {
143         if(rx_fill==0xFF)
144         {
145                 if(c==':')
146                         rx_fill = 0;
147         }
148         else if(c=='.')
149         {
150                 if(rx_fill>=4)
151                 {
152                         uint16_t offset;
153                         uint8_t nibbles;
154                         uint8_t i;
155
156                         offset = (decode_hex(rx_buf[0])<<8) | (decode_hex(rx_buf[1])<<4) | decode_hex(rx_buf[2]);
157                         nibbles = (offset&3);
158                         offset >>= 2;
159                         if(rx_fill>3+nibbles)
160                         {
161                                 for(i=0; i<=nibbles; ++i)
162                                 {
163                                         uint16_t j = offset+nibbles-i;
164                                         uint8_t shift = 4*(j&1);
165                                         uint8_t bits = decode_hex(rx_buf[3+i]);
166                                         input[j/2] = (input[j/2]&~(0xF<<shift)) | (bits<<shift);
167                                         latch[j/2] = input[j/2];
168                                 }
169
170                                 if(lcd_enabled)
171                                 {
172                                         lcd_gotoxy(19-offset-nibbles, 0);
173                                         for(i=0; i<=nibbles; ++i)
174                                                 lcd_write(rx_buf[3+i]);
175                                 }
176                         }
177                 }
178                 rx_fill = 0xFF;
179         }
180         else
181         {
182                 if(rx_fill<sizeof(rx_buf))
183                         rx_buf[rx_fill++] = c;
184                 else
185                         rx_fill = 0xFF;
186         }
187
188         if(lcd_enabled)
189         {
190                 lcd_gotoxy(log_col, 1+log_row);
191                 lcd_write(c);
192                 ++log_col;
193                 if(log_col>=20)
194                 {
195                         log_col = 0;
196                         ++log_row;
197                         if(log_row>=3)
198                                 log_row = 0;
199                         lcd_gotoxy(log_col, 1+log_row);
200                 }
201                 lcd_write(255);
202         }
203 }
204
205 SERIAL_SET_CALLBACK(receive)
206
207 uint8_t hexdigit(uint8_t n)
208 {
209         n &= 0xF;
210         if(n<10)
211                 return '0'+n;
212         else
213                 return 'A'+(n-0xA);
214 }
215
216 uint8_t decode_hex(uint8_t c)
217 {
218         if(c>='0' && c<='9')
219                 return c-'0';
220         else if(c>='A' && c<='F')
221                 return 0xA+(c-'A');
222         else
223                 return 0;
224 }