/* $Id$ This file is part of R²C² 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 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; }