/* * Receive an FM-modulated signal by using a timer with input capture */ #include "usbcas.h" static uint16_t one_bit_lo, one_bit_hi; /* Range for an edge being a "1" */ static inline void fmrx_led_on(void) { PORTB &= ~(1 << 0); } static inline void fmrx_led_off(void) { PORTB |= (1 << 0); } static void say(const char *str) { #if 0 char c; while ((c = *str++)) fmrx_recv_byte(c); #endif } void fmrx_init(void) { uint8_t tccr1b; /* ICP1/PD4 is input, with pullup */ DDRD &= ~(1 << 4); PORTD |= (1 << 4); /* PB0 is RXLED */ DDRB |= (1 << 0); fmrx_led_off(); /* Stop counter */ TCCR1B = 0; /* Normal mode, no comparators */ TCCR1A = 0; /* Enable interrupts on input capture */ TIMSK1 = (1 << ICIE1); /* Clear timer counter */ TCNT1 = 0; /* * Input capture noise canceler on, no prescaler, normal mode; * start timer */ tccr1b = (1 << ICNC1) + (1 << CS10); if (!(PIND & (1 << 4))) tccr1b |= 1 << ICES1; TCCR1B = tccr1b; } static uint16_t bytes; void fmrx_set_speed(uint32_t baudrate) { char msg[256]; one_bit_lo = F_CPU / (4 * baudrate); one_bit_hi = 3 * one_bit_lo; bytes = 0; sprintf(msg, "\r\nbaudrate = %lu\r\n" "one_bit_lo = %u\r\n" "one_bit_hi = %u\r\n", baudrate, one_bit_lo, one_bit_hi); say(msg); } /* We "hunt" for a block until we find this bit pattern; same as ABC800 */ #define CAS_SYNC_PATTERN 0x0216 /* SYNC + STX */ #define CAS_BLOCK_LEN (1+2+253+1+2) /* type+num+data+ETX+checksum */ /* Interrupt routine for edge capture */ ISR(TIMER1_CAPT_vect) { static uint16_t last_edge; static uint16_t data; static uint8_t bits; char tbuf[16]; uint16_t edge, delta; TCCR1B ^= (1 << ICES1); /* Next edge -> opposite polarity */ edge = ICR1; delta = edge - last_edge; if (delta < one_bit_lo) { /* Early edge, no action */ say("E"); return; } else if (delta < one_bit_hi) { say("D"); /* A data bit edge */ data |= (1 << 15); } else { say("C"); /* Clock edge */ last_edge = edge; if (bytes) { if (--bits == 0) { uint8_t outbyte = data >> 8; sprintf(tbuf, "<%02x>", outbyte); say(tbuf); fmrx_recv_byte(outbyte); data = 0; /* To avoid false sync */ bits = 8; if (--bytes == 0) fmrx_led_off(); } } else { sprintf(tbuf, "[%04x]", data); say(tbuf); if (data == CAS_SYNC_PATTERN) { bits = 8; bytes = CAS_BLOCK_LEN; fmrx_led_on(); } } data >>= 1; } sprintf(tbuf, "%u ", delta); say(tbuf); }