123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- /*
- * 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);
- }
- 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 interrupt flag if set */
- TIFR1 = (1 << ICF1);
- /* Clear timer counter */
- TCNT1 = 0;
- /*
- * Input capture noise canceler on, normal mode; not counting yet
- */
- tccr1b = (1 << ICNC1) + (0 << CS10);
- if (!(PIND & (1 << 4)))
- tccr1b |= 1 << ICES1;
- TCCR1B = tccr1b;
- }
- static uint16_t bytes;
- void fmrx_set_speed(uint32_t baudrate)
- {
- uint8_t prescale = 1; /* No prescaling */
- /* Enable prescaler for low baud rates to reduce wraparound */
- if (baudrate < 976) {
- baudrate <<= 3; /* ... for calculation purposes ... */
- prescale++; /* Prescale by 8 */
- }
- one_bit_lo = F_CPU / (4 * baudrate);
- one_bit_hi = 3 * one_bit_lo;
- bytes = 0;
- TCCR1B = (TCCR1B & ~7) | prescale;
- }
- /* 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;
- 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 */
- return;
- } else if (delta < one_bit_hi) {
- /* A data bit edge */
- data |= (1 << 15);
- } else {
- /* Clock edge */
- last_edge = edge;
- if (bytes) {
- if (--bits == 0) {
- uint8_t outbyte = data >> 8;
- 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;
- }
- }
|