]> git.tdb.fi Git - model-railway-devices.git/blobdiff - s88w/s88w-t.c
Reorganize the directory structure
[model-railway-devices.git] / s88w / s88w-t.c
diff --git a/s88w/s88w-t.c b/s88w/s88w-t.c
new file mode 100644 (file)
index 0000000..692eac5
--- /dev/null
@@ -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 <avr/io.h>
+#include <avr/interrupt.h>
+#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<sizeof(rx_buf))
+                       rx_buf[rx_fill++] = c;
+               else
+                       rx_fill = 0xFF;
+       }
+}
+
+SERIAL_SET_CALLBACK(receive)
+
+void send_state(void)
+{
+       uint8_t i;
+
+       serial_write(':');
+       serial_write(hexdigit(offset>>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;
+}