]> git.tdb.fi Git - model-railway-devices.git/blobdiff - firmware/s88w-t.c
Add some utility functions for interfacing with hardware
[model-railway-devices.git] / firmware / s88w-t.c
index e88a1f509eb6fc24aec4c4a8e05e83bce6a4fd7e..e394d603032fe07b14047f554abc633afb451c7a 100644 (file)
@@ -24,48 +24,55 @@ activate.
 
 #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);
-void write_serial(uint8_t);
 uint8_t hexdigit(uint8_t);
+uint8_t decode_hex(uint8_t);
 
-volatile uint8_t state = 0;
+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;
 
 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 = 0x20;   // 00100000
+       DDRB = 0x20;   // 00000000
        PORTB = 0x3F;  // 00111111
 
-       // 9600 baud, 8N1
-       UBRR0H = 0;
-       UBRR0L = 103;
-       UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);
-       UCSR0B = BIT(RXEN0) | BIT(TXEN0);
-
-       // 0.5 Hz (CK/1024, TOP=31250)
-       TCCR1A = 0;
-       TCCR1B = BIT(WGM12) | BIT(CS12) | BIT(CS10);
-       OCR1AH = 122;
-       OCR1AL = 18;
-       TIMSK1 = BIT(OCIE1A);
+       serial_init(9600);
+       serial_set_callback(receive);
+       timer_init(1, 2);
+       timer_set_callback(send_state);
 
        sei();
 
        while(1)
        {
                uint8_t i;
-               uint8_t input = 0;
-               uint8_t valid = 0xFF;
+               uint16_t input = 0;
+               uint16_t valid = 0xFFF;
 
                for(i=0; i<100; ++i)
                {
-                       uint8_t pins;
+                       uint16_t pins;
 
-                       pins = ~((PIND>>2) | (PINB<<6));
+                       pins = ~((PIND>>2) | ((PINB&0x3F)<<6));
                        if(i==0)
                                input = pins;
                        valid &= ~(pins^input);
@@ -73,6 +80,7 @@ int main()
 
                input &= valid;
                input |= state&~valid;
+               input &= (1<<(nibbles*4))-1;
 
                if(input!=state)
                {
@@ -84,28 +92,64 @@ int main()
        return 0;
 }
 
-ISR(TIMER1_COMPA_vect)
+void receive(uint8_t c)
 {
-       send_state();
+       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;
+       }
 }
 
 void send_state(void)
 {
-       write_serial(':');
-       write_serial(hexdigit(state>>4));
-       write_serial(hexdigit(state&0xF));
-}
-
-void write_serial(uint8_t c)
-{
-       while(!(UCSR0A&(1<<UDRE0))) ;
-       UDR0 = c;
+       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('.');
 }
 
 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;
+}