]> git.tdb.fi Git - model-railway-devices.git/blob - s88w/s88w-t.c
Drop the pretense of C89, put declarations where they make sense
[model-railway-devices.git] / s88w / s88w-t.c
1 /*
2 Firmware for wireless S88 transmitter module
3
4 ATMega pinout:
5 D0 - serial RX
6 D1 - serial TX
7 D2 - input 1
8 D3 - input 2
9 D4 - input 3
10 D5 - input 4
11 D6 - input 5
12 D7 - input 6
13 B0 - input 7
14 B1 - input 8
15 B2 - input 9
16 B3 - input 10
17 B4 - input 11
18 B5 - input 12
19
20 Inputs are pulled high by internal pull-up resistors.  Connect to GND to
21 activate.
22
23 The module can be configured by sending a string of form ":Shhh." over the
24 serial port, where hhh is a hex number.  Lower two bits indicate the number of
25 inputs (00=4, 01=8, 10=12, 11=16) and upper ten bits indicate offset of lowest
26 input in multiples of 4 bits.  At the moment there are no provisions for
27 having 16 physical inputs.
28
29 Example: ":S016." would configure the module to have 12 inputs at offset 20.
30 */
31
32 #include <avr/io.h>
33 #include <avr/interrupt.h>
34 #include "eeprom.h"
35 #include "serial.h"
36 #include "timer.h"
37
38 #define BIT(n) (1<<(n))
39
40 void receive(uint8_t);
41 void send_state(void);
42 uint8_t hexdigit(uint8_t);
43 uint8_t decode_hex(uint8_t);
44
45 uint8_t rx_buf[4];
46 uint8_t rx_fill = 0xFF;
47 volatile uint8_t nibbles = 2;
48 volatile uint8_t offset = 0;
49 volatile uint16_t state = 0;
50 volatile uint8_t time_since_send = 0;
51
52 int main()
53 {
54         if(eeprom_read(0)==0xA5)
55         {
56                 offset = eeprom_read(1)<<8;
57                 offset |= eeprom_read(2);
58                 nibbles = eeprom_read(3);
59         }
60
61         DDRD = 0x02;   // 00000010
62         PORTD = 0xFC;  // 11111100
63         DDRB = 0x00;   // 00000000
64         PORTB = 0x3F;  // 00111111
65
66         serial_init(9600);
67         timer_start_hz(1, 100, 1);
68
69         sei();
70
71         while(1)
72         {
73                 uint16_t input = 0;
74                 uint16_t valid = 0xFFF;
75
76                 for(uint8_t i=0; i<100; ++i)
77                 {
78                         uint16_t pins = 0;
79                         for(uint8_t j=0; j<100; ++j)
80                                 pins |= ~((PIND>>2) | ((PINB&0x3F)<<6));
81
82                         if(i==0)
83                                 input = pins;
84
85                         valid &= ~(pins^input);
86                 }
87
88                 input &= valid;
89                 input |= state&~valid;
90                 input &= (1<<(nibbles*4))-1;
91
92                 if(input!=state && time_since_send>5)
93                 {
94                         state = input;
95                         send_state();
96                 }
97         }
98
99         return 0;
100 }
101
102 void receive(uint8_t c)
103 {
104         if(rx_fill==0xFF)
105         {
106                 if(c==':')
107                         rx_fill = 0;
108         }
109         else if(c=='.')
110         {
111                 if(rx_buf[0]=='S' && rx_fill==4)
112                 {
113                         offset = (decode_hex(rx_buf[1])<<8) | (decode_hex(rx_buf[2])<<4) | decode_hex(rx_buf[3]);
114                         nibbles = (offset&3)+1;
115                         offset &= 0xFFC;
116
117                         eeprom_write(0, 0xA5);
118                         eeprom_write(1, offset>>8);
119                         eeprom_write(2, offset);
120                         eeprom_write(3, nibbles);
121                 }
122                 rx_fill = 0xFF;
123         }
124         else
125         {
126                 if(rx_fill<sizeof(rx_buf))
127                         rx_buf[rx_fill++] = c;
128                 else
129                         rx_fill = 0xFF;
130         }
131 }
132
133 SERIAL_SET_CALLBACK(receive)
134
135 void send_state(void)
136 {
137         serial_write(':');
138         serial_write(hexdigit(offset>>8));
139         serial_write(hexdigit(offset>>4));
140         serial_write(hexdigit(offset|(nibbles-1)));
141         for(uint8_t i=nibbles; i--;)
142                 serial_write(hexdigit(state>>(i*4)));
143         serial_write('.');
144
145         time_since_send = 0;
146 }
147
148 void timer(void)
149 {
150         ++time_since_send;
151         if(time_since_send>200)
152                 send_state();
153 }
154
155 TIMER_SET_CALLBACK(1, timer)
156
157 uint8_t hexdigit(uint8_t n)
158 {
159         n &= 0xF;
160         if(n<10)
161                 return '0'+n;
162         else
163                 return 'A'+(n-0xA);
164 }
165
166 uint8_t decode_hex(uint8_t c)
167 {
168         if(c>='0' && c<='9')
169                 return c-'0';
170         else if(c>='A' && c<='F')
171                 return 0xA+(c-'A');
172         else
173                 return 0;
174 }