X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=s88w%2Fs88w-t.c;fp=s88w%2Fs88w-t.c;h=692eac5f6f3e6310c4ba8f8d0fdddb34faf68083;hb=9c37d18b9c70fdb70dfec453398c4649e9e57586;hp=0000000000000000000000000000000000000000;hpb=49b6b6ad84ec47b4f9eb9ef131975cc5b72372a2;p=model-railway-devices.git diff --git a/s88w/s88w-t.c b/s88w/s88w-t.c new file mode 100644 index 0000000..692eac5 --- /dev/null +++ b/s88w/s88w-t.c @@ -0,0 +1,177 @@ +/* +Firmware for wireless S88 transmitter module + +ATMega pinout: +D0 - serial RX +D1 - serial TX +D2 - input 1 +D3 - input 2 +D4 - input 3 +D5 - input 4 +D6 - input 5 +D7 - input 6 +B0 - input 7 +B1 - input 8 +B2 - input 9 +B3 - input 10 +B4 - input 11 +B5 - input 12 + +Inputs are pulled high by internal pull-up resistors. Connect to GND to +activate. + +The module can be configured by sending a string of form ":Shhh." over the +serial port, where hhh is a hex number. Lower two bits indicate the number of +inputs (00=4, 01=8, 10=12, 11=16) and upper ten bits indicate offset of lowest +input in multiples of 4 bits. At the moment there are no provisions for +having 16 physical inputs. + +Example: ":S016." would configure the module to have 12 inputs at offset 20. +*/ + +#include +#include +#include "eeprom.h" +#include "serial.h" +#include "timer.h" + +#define BIT(n) (1<<(n)) + +void receive(uint8_t); +void send_state(void); +uint8_t hexdigit(uint8_t); +uint8_t decode_hex(uint8_t); + +uint8_t rx_buf[4]; +uint8_t rx_fill = 0xFF; +volatile uint8_t nibbles = 2; +volatile uint8_t offset = 0; +volatile uint16_t state = 0; +volatile uint8_t time_since_send = 0; + +int main() +{ + if(eeprom_read(0)==0xA5) + { + offset = eeprom_read(1)<<8; + offset |= eeprom_read(2); + nibbles = eeprom_read(3); + } + + DDRD = 0x02; // 00000010 + PORTD = 0xFC; // 11111100 + DDRB = 0x00; // 00000000 + PORTB = 0x3F; // 00111111 + + serial_init(9600); + timer_start_hz(1, 100, 1); + + sei(); + + while(1) + { + uint8_t i, j; + uint16_t input = 0; + uint16_t valid = 0xFFF; + + for(i=0; i<100; ++i) + { + uint16_t pins = 0; + for(j=0; j<100; ++j) + pins |= ~((PIND>>2) | ((PINB&0x3F)<<6)); + + if(i==0) + input = pins; + + valid &= ~(pins^input); + } + + input &= valid; + input |= state&~valid; + input &= (1<<(nibbles*4))-1; + + if(input!=state && time_since_send>5) + { + state = input; + send_state(); + } + } + + return 0; +} + +void receive(uint8_t c) +{ + if(rx_fill==0xFF) + { + if(c==':') + rx_fill = 0; + } + else if(c=='.') + { + if(rx_buf[0]=='S' && rx_fill==4) + { + offset = (decode_hex(rx_buf[1])<<8) | (decode_hex(rx_buf[2])<<4) | decode_hex(rx_buf[3]); + nibbles = (offset&3)+1; + offset &= 0xFFC; + + eeprom_write(0, 0xA5); + eeprom_write(1, offset>>8); + eeprom_write(2, offset); + eeprom_write(3, nibbles); + } + rx_fill = 0xFF; + } + else + { + if(rx_fill>8)); + serial_write(hexdigit(offset>>4)); + serial_write(hexdigit(offset|(nibbles-1))); + for(i=nibbles; i--;) + serial_write(hexdigit(state>>(i*4))); + serial_write('.'); + + time_since_send = 0; +} + +void timer(void) +{ + ++time_since_send; + if(time_since_send>200) + send_state(); +} + +TIMER_SET_CALLBACK(1, timer) + +uint8_t hexdigit(uint8_t n) +{ + n &= 0xF; + if(n<10) + return '0'+n; + else + return 'A'+(n-0xA); +} + +uint8_t decode_hex(uint8_t c) +{ + if(c>='0' && c<='9') + return c-'0'; + else if(c>='A' && c<='F') + return 0xA+(c-'A'); + else + return 0; +}