--- /dev/null
+/* $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 receiver module
+
+S88 pinout:
+1 - DATA
+2 - GND
+3 - CLOCK
+4 - LOAD
+5 - RESET
+6 - POWER
+
+ATMega pinout:
+D0 - serial RX
+D1 - serial TX
+D2 - S88 DATA
+D3 - S88 CLOCK
+D4 - S88 LOAD
+D5 - S88 RESET
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#define DATA_OUT PORTD2
+#define CLOCK PIND3
+#define LOAD PIND4
+#define RESET PIND5
+
+#define BIT(n) (1<<(n))
+
+uint8_t decode_hex(uint8_t);
+
+volatile uint8_t rx_buf[3];
+volatile uint8_t rx_fill = 0;
+volatile uint8_t input = 0;
+volatile uint8_t latch = 0;
+
+int main()
+{
+ uint8_t clock_high = 0;
+ uint8_t bits = 0;
+
+ DDRD = 0x06; // 00000110
+ PIND = 0xC0; // 11000000
+ DDRB = 0x20; // 00100000
+ PINB = 0x1F; // 00011111
+
+ // 9600 baud, 8N1
+ UBRR0H = 0;
+ UBRR0L = 103;
+ UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);
+ UCSR0B = BIT(RXEN0) | BIT(TXEN0) | BIT(RXCIE0);
+
+ sei();
+
+ while(1)
+ {
+ uint8_t d_pins;
+
+ d_pins = PIND;
+
+ if(d_pins&BIT(CLOCK))
+ {
+ if(!clock_high)
+ {
+ if(d_pins&BIT(LOAD))
+ bits = latch;
+ else
+ bits >>= 1;
+
+ if(bits&1)
+ PORTD |= BIT(DATA_OUT);
+ else
+ PORTD &= ~BIT(DATA_OUT);
+
+ clock_high = 1;
+ }
+ }
+ else if(clock_high)
+ clock_high = 0;
+
+ if(d_pins&BIT(RESET))
+ latch = input;
+ }
+}
+
+ISR(USART_RX_vect)
+{
+ uint8_t c = UDR0;
+ if(rx_fill==0)
+ {
+ if(c==':')
+ rx_buf[rx_fill++] = c;
+ }
+ else
+ {
+ rx_buf[rx_fill++] = c;
+ if(rx_buf[0]==':' && rx_fill==3)
+ {
+ input = (decode_hex(rx_buf[1])<<4) | decode_hex(rx_buf[2]);
+ latch |= input;
+ rx_fill = 0;
+ }
+ }
+}
+
+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;
+}