]> git.tdb.fi Git - model-railway-devices.git/blob - firmware/s88w-r.c
019897483cc63b2b36dc1f6cc79cf151e4064f72
[model-railway-devices.git] / firmware / 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 receive(uint8_t);
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                 b_pins = PINB;
71                 d_pins = PIND;
72
73                 if(d_pins&BIT(CLOCK))
74                 {
75                         if(!clock_high)
76                         {
77                                 if(d_pins&BIT(LOAD))
78                                 {
79                                         offset = 0;
80                                         bits = latch[0];
81                                         n_bits = 8;
82                                 }
83                                 else
84                                 {
85                                         bits >>= 1;
86                                         if(!--n_bits)
87                                         {
88                                                 ++offset;
89                                                 bits = latch[offset];
90                                                 n_bits = 8;
91                                         }
92                                 }
93
94                                 if(bits&1)
95                                         PORTD |= BIT(DATA_OUT);
96                                 else
97                                         PORTD &= ~BIT(DATA_OUT);
98
99                                 clock_high = 1;
100                         }
101                 }
102                 else if(clock_high)
103                         clock_high = 0;
104
105                 if(d_pins&BIT(RESET))
106                 {
107                         uint8_t i;
108                         for(i=0; i<128; ++i)
109                                 latch[i] = input[i];
110                 }
111
112                 if(b_pins&BIT(LCD_DISABLE))
113                 {
114                         if(lcd_enabled)
115                         {
116                                 lcd_enabled = 0;
117
118                                 lcd_clear();
119                         }
120                 }
121                 else if(!lcd_enabled)
122                 {
123                         lcd_enabled = 1;
124                         log_row = 0;
125                         log_col = 0;
126
127                         lcd_clear();
128                         for(i=0; i<20; ++i)
129                                 lcd_write(hexdigit(input[9-i/2]>>(4-i%2*4)));
130                         lcd_gotoxy(0, 1);
131                         lcd_write(255);
132                 }
133         }
134 }
135
136 void receive(uint8_t c)
137 {
138         if(rx_fill==0xFF)
139         {
140                 if(c==':')
141                         rx_fill = 0;
142         }
143         else if(c=='.')
144         {
145                 if(rx_fill>=4)
146                 {
147                         uint16_t offset;
148                         uint8_t nibbles;
149                         uint8_t i;
150
151                         offset = (decode_hex(rx_buf[0])<<8) | (decode_hex(rx_buf[1])<<4) | decode_hex(rx_buf[2]);
152                         nibbles = (offset&3);
153                         offset >>= 2;
154                         if(rx_fill>3+nibbles)
155                         {
156                                 for(i=0; i<=nibbles; ++i)
157                                 {
158                                         uint16_t j = offset+nibbles-i;
159                                         uint8_t shift = 4*(j&1);
160                                         uint8_t bits = decode_hex(rx_buf[3+i]);
161                                         input[j/2] = (input[j/2]&~(0xF<<shift)) | (bits<<shift);
162                                         latch[j/2] = input[j/2];
163                                 }
164
165                                 if(lcd_enabled)
166                                 {
167                                         lcd_gotoxy(19-offset-nibbles, 0);
168                                         for(i=0; i<=nibbles; ++i)
169                                                 lcd_write(rx_buf[3+i]);
170                                 }
171                         }
172                 }
173                 rx_fill = 0xFF;
174         }
175         else
176         {
177                 if(rx_fill<sizeof(rx_buf))
178                         rx_buf[rx_fill++] = c;
179                 else
180                         rx_fill = 0xFF;
181         }
182
183         if(lcd_enabled)
184         {
185                 lcd_gotoxy(log_col, 1+log_row);
186                 lcd_write(c);
187                 ++log_col;
188                 if(log_col>=20)
189                 {
190                         log_col = 0;
191                         ++log_row;
192                         if(log_row>=3)
193                                 log_row = 0;
194                         lcd_gotoxy(log_col, 1+log_row);
195                 }
196                 lcd_write(255);
197         }
198 }
199
200 SERIAL_SET_CALLBACK(receive)
201
202 uint8_t hexdigit(uint8_t n)
203 {
204         n &= 0xF;
205         if(n<10)
206                 return '0'+n;
207         else
208                 return 'A'+(n-0xA);
209 }
210
211 uint8_t decode_hex(uint8_t c)
212 {
213         if(c>='0' && c<='9')
214                 return c-'0';
215         else if(c>='A' && c<='F')
216                 return 0xA+(c-'A');
217         else
218                 return 0;
219 }