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