]> git.tdb.fi Git - model-railway-devices.git/blob - firmware/s88w-t.c
Add some utility functions for interfacing with hardware
[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
21 Inputs are pulled high by internal pull-up resistors.  Connect to GND to
22 activate.
23 */
24
25 #include <avr/io.h>
26 #include <avr/interrupt.h>
27 #include "eeprom.h"
28 #include "serial.h"
29 #include "timer.h"
30
31 #define BIT(n) (1<<(n))
32
33 void receive(uint8_t);
34 void send_state(void);
35 uint8_t hexdigit(uint8_t);
36 uint8_t decode_hex(uint8_t);
37
38 uint8_t rx_buf[4];
39 uint8_t rx_fill = 0xFF;
40 volatile uint8_t nibbles = 2;
41 volatile uint8_t offset = 0;
42 volatile uint16_t state = 0;
43
44 int main()
45 {
46         if(eeprom_read(0)==0xA5)
47         {
48                 offset = eeprom_read(1)<<8;
49                 offset |= eeprom_read(2);
50                 nibbles = eeprom_read(3);
51         }
52
53         DDRD = 0x02;   // 00000010
54         PORTD = 0xFC;  // 11111100
55         DDRB = 0x20;   // 00000000
56         PORTB = 0x3F;  // 00111111
57
58         serial_init(9600);
59         serial_set_callback(receive);
60         timer_init(1, 2);
61         timer_set_callback(send_state);
62
63         sei();
64
65         while(1)
66         {
67                 uint8_t i;
68                 uint16_t input = 0;
69                 uint16_t valid = 0xFFF;
70
71                 for(i=0; i<100; ++i)
72                 {
73                         uint16_t pins;
74
75                         pins = ~((PIND>>2) | ((PINB&0x3F)<<6));
76                         if(i==0)
77                                 input = pins;
78                         valid &= ~(pins^input);
79                 }
80
81                 input &= valid;
82                 input |= state&~valid;
83                 input &= (1<<(nibbles*4))-1;
84
85                 if(input!=state)
86                 {
87                         state = input;
88                         send_state();
89                 }
90         }
91
92         return 0;
93 }
94
95 void receive(uint8_t c)
96 {
97         if(rx_fill==0xFF)
98         {
99                 if(c==':')
100                         rx_fill = 0;
101         }
102         else if(c=='.')
103         {
104                 if(rx_buf[0]=='S' && rx_fill==4)
105                 {
106                         offset = (decode_hex(rx_buf[1])<<8) | (decode_hex(rx_buf[2])<<4) | decode_hex(rx_buf[3]);
107                         nibbles = (offset&3)+1;
108                         offset &= 0xFFC;
109
110                         eeprom_write(0, 0xA5);
111                         eeprom_write(1, offset>>8);
112                         eeprom_write(2, offset);
113                         eeprom_write(3, nibbles);
114                 }
115                 rx_fill = 0xFF;
116         }
117         else
118         {
119                 if(rx_fill<sizeof(rx_buf))
120                         rx_buf[rx_fill++] = c;
121                 else
122                         rx_fill = 0xFF;
123         }
124 }
125
126 void send_state(void)
127 {
128         uint8_t i;
129         serial_write(':');
130         serial_write(hexdigit(offset>>8));
131         serial_write(hexdigit(offset>>4));
132         serial_write(hexdigit(offset|(nibbles-1)));
133         for(i=nibbles; i--;)
134                 serial_write(hexdigit(state>>(i*4)));
135         serial_write('.');
136 }
137
138 uint8_t hexdigit(uint8_t n)
139 {
140         n &= 0xF;
141         if(n<10)
142                 return '0'+n;
143         else
144                 return 'A'+(n-0xA);
145 }
146
147 uint8_t decode_hex(uint8_t c)
148 {
149         if(c>='0' && c<='9')
150                 return c-'0';
151         else if(c>='A' && c<='F')
152                 return 0xA+(c-'A');
153         else
154                 return 0;
155 }