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