/* * 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" */ void fmrx_init(void) { /* 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); } static uint16_t bytes; void fmrx_set_speed(uint32_t baudrate) { one_bit_lo = F_CPU / (4 * baudrate); one_bit_hi = 3 * one_bit_lo; bytes = 0; } /* We "hunt" for a block until we find this bit pattern; same as ABC800 */ #define CAS_SYNC_PATTERN 0x0216 #define CAS_BLOCK_LEN (1+1+2+253+1+2) /* STX+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; uint16_t edge, delta; TCCR1B ^= (1 << ICES1); /* Next edge -> opposite polarity */ edge = ICR1; delta = edge - last_edge; last_edge = edge; if (delta < one_bit_lo) { /* Early edge, no action */ return; } else if (delta < one_bit_hi) { /* A data bit edge */ data |= 1; } else { /* Clock edge */ if (bytes) { if (--bits == 0) { fmrx_recv_byte(data); data = 0; /* To avoid false sync */ bits = 8; bytes--; } } else if (data == CAS_SYNC_PATTERN) { bits = 8; bytes = CAS_BLOCK_LEN; } data <<= 1; } }