+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+
+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
+
+Inputs are pulled high by internal pull-up resistors. Connect to GND to
+activate.
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#define BIT(n) (1<<(n))
+
+void send_state(void);
+void write_serial(uint8_t);
+uint8_t hexdigit(uint8_t);
+
+volatile uint8_t state = 0;
+
+int main()
+{
+ DDRD = 0x02; // 00000010
+ PORTD = 0xFC; // 11111100
+ DDRB = 0x20; // 00100000
+ 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);
+
+ sei();
+
+ while(1)
+ {
+ uint8_t i;
+ uint8_t input = 0;
+ uint8_t valid = 0xFF;
+
+ for(i=0; i<100; ++i)
+ {
+ uint8_t pins;
+
+ pins = ~((PIND>>2) | (PINB<<6));
+ if(i==0)
+ input = pins;
+ valid &= ~(pins^input);
+ }
+
+ input &= valid;
+ input |= state&~valid;
+
+ if(input!=state)
+ {
+ state = input;
+ send_state();
+ }
+ }
+
+ return 0;
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ send_state();
+}
+
+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 hexdigit(uint8_t n)
+{
+ if(n<10)
+ return '0'+n;
+ else
+ return 'A'+(n-0xA);
+}