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