]> git.tdb.fi Git - model-railway-devices.git/blob - s88w/s88w-r.c
f94a1be0e0e1038f128c844d5219270d0d6694a8
[model-railway-devices.git] / s88w / s88w-r.c
1 /*
2 Firmware for wireless S88 receiver module
3
4 S88 pinout:
5 1 - DATA
6 2 - GND
7 3 - CLOCK
8 4 - LOAD
9 5 - RESET
10 6 - POWER
11
12 ATMega pinout:
13 D0 - serial RX
14 D1 - serial TX
15 D2 - S88 DATA
16 D3 - S88 CLOCK
17 D4 - S88 LOAD
18 D5 - S88 RESET
19 */
20
21 #include <avr/io.h>
22 #include <avr/interrupt.h>
23 #include "lcd.h"
24 #include "serial.h"
25 #include "delay.h"
26
27 #define DATA_OUT PORTD2
28 #define CLOCK    PIND3
29 #define LOAD     PIND4
30 #define RESET    PIND5
31
32 #define LCD_DISABLE PINB4
33
34 #define BIT(n)   (1<<(n))
35
36 void check_input();
37 uint8_t hexdigit(uint8_t);
38 uint8_t decode_hex(uint8_t);
39
40 uint8_t clock_high = 0;
41 uint8_t rx_buf[7];
42 uint8_t rx_fill = 0xFF;
43 uint8_t input[128] = { 0 };
44 uint8_t latch[128] = { 0 };
45 uint8_t output[128] = { 0 };
46 uint8_t out_offset = 0;
47 uint8_t out_bits = 0;
48 uint8_t out_fill = 0;
49 volatile uint8_t load_pos = 0xFF;
50 volatile uint8_t reset_pos = 0xFF;
51 uint8_t lcd_enabled = 0;
52 uint8_t log_row = 0;
53 uint8_t log_col = 0;
54
55 int main()
56 {
57         DDRD = 0x06;   // 00000110
58         PORTD = 0xC0;  // 11000000
59         DDRB = 0x20;   // 00100000
60         PORTB = 0x1F;  // 00011111
61         PCMSK2 = BIT(PCINT19) | BIT(PCINT21);
62         PCICR = BIT(PCIE2);
63
64         serial_init(9600);
65         lcd_init();
66
67         sei();
68
69         while(1)
70         {
71                 uint8_t i;
72
73                 check_input();
74
75                 i = load_pos;
76                 if(i!=0xFF)
77                 {
78                         output[i] = latch[i];
79                         if(++i>=sizeof(input))
80                                 i = 0xFF;
81                         load_pos = i;
82                 }
83
84                 i = reset_pos;
85                 if(i!=0xFF)
86                 {
87                         latch[i] = input[i];
88                         if(++i>=sizeof(input))
89                                 i = 0xFF;
90                         reset_pos = i;
91                 }
92
93                 if(PINB&BIT(LCD_DISABLE))
94                 {
95                         if(lcd_enabled)
96                         {
97                                 lcd_enabled = 0;
98
99                                 lcd_clear();
100                         }
101                 }
102                 else if(!lcd_enabled)
103                 {
104                         lcd_enabled = 1;
105                         log_row = 0;
106                         log_col = 0;
107
108                         lcd_clear();
109                         for(i=0; i<20; ++i)
110                                 lcd_write(hexdigit(input[9-i/2]>>(4-i%2*4)));
111                         lcd_gotoxy(0, 1);
112                         lcd_write(255);
113                 }
114         }
115 }
116
117 void check_input()
118 {
119         uint8_t c;
120         if(!serial_read_available())
121                 return;
122
123         c = serial_read();
124         if(rx_fill==0xFF)
125         {
126                 if(c==':')
127                         rx_fill = 0;
128         }
129         else if(c=='.')
130         {
131                 if(rx_fill>=4)
132                 {
133                         uint16_t offset;
134                         uint8_t nibbles;
135                         uint8_t i;
136
137                         offset = (decode_hex(rx_buf[0])<<8) | (decode_hex(rx_buf[1])<<4) | decode_hex(rx_buf[2]);
138                         nibbles = (offset&3);
139                         offset >>= 2;
140                         if(rx_fill>3+nibbles)
141                         {
142                                 for(i=0; i<=nibbles; ++i)
143                                 {
144                                         uint16_t j = offset+nibbles-i;
145                                         uint8_t shift = 4*(j&1);
146                                         uint8_t bits = decode_hex(rx_buf[3+i]);
147                                         input[j/2] = (input[j/2]&~(0xF<<shift)) | (bits<<shift);
148                                         latch[j/2] |= input[j/2];
149                                 }
150
151                                 if(lcd_enabled)
152                                 {
153                                         lcd_gotoxy(19-offset-nibbles, 0);
154                                         for(i=0; i<=nibbles; ++i)
155                                                 lcd_write(rx_buf[3+i]);
156                                 }
157                         }
158                 }
159                 rx_fill = 0xFF;
160         }
161         else
162         {
163                 if(rx_fill<sizeof(rx_buf))
164                         rx_buf[rx_fill++] = c;
165                 else
166                         rx_fill = 0xFF;
167         }
168
169         if(lcd_enabled)
170         {
171                 lcd_gotoxy(log_col, 1+log_row);
172                 lcd_write(c);
173                 ++log_col;
174                 if(log_col>=20)
175                 {
176                         log_col = 0;
177                         ++log_row;
178                         if(log_row>=3)
179                                 log_row = 0;
180                         lcd_gotoxy(log_col, 1+log_row);
181                 }
182                 lcd_write(255);
183         }
184 }
185
186 uint8_t hexdigit(uint8_t n)
187 {
188         n &= 0xF;
189         if(n<10)
190                 return '0'+n;
191         else
192                 return 'A'+(n-0xA);
193 }
194
195 uint8_t decode_hex(uint8_t c)
196 {
197         if(c>='0' && c<='9')
198                 return c-'0';
199         else if(c>='A' && c<='F')
200                 return 0xA+(c-'A');
201         else
202                 return 0;
203 }
204
205 ISR(PCINT2_vect)
206 {
207         uint8_t d = PIND;
208         if(d&BIT(CLOCK))
209         {
210                 if(!clock_high)
211                 {
212                         if(d&BIT(LOAD))
213                         {
214                                 out_offset = 0;
215                                 out_bits = latch[0];
216                                 out_fill = 8;
217                                 load_pos = 0;
218                         }
219
220                         if(out_bits&1)
221                                 PORTD |= BIT(DATA_OUT);
222                         else
223                                 PORTD &= ~BIT(DATA_OUT);
224
225                         out_bits >>= 1;
226                         if(!--out_fill)
227                         {
228                                 ++out_offset;
229                                 out_bits = output[out_offset];
230                                 out_fill = 8;
231                         }
232
233                         clock_high = 1;
234                 }
235         }
236         else
237                 clock_high = 0;
238
239         if(d&BIT(RESET))
240                 reset_pos = 0;
241 }