fmrx.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Receive an FM-modulated signal by using a timer with input capture
  3. */
  4. #include "usbcas.h"
  5. static uint16_t one_bit_lo, one_bit_hi; /* Range for an edge being a "1" */
  6. static inline void fmrx_led_on(void)
  7. {
  8. PORTB &= ~(1 << 0);
  9. }
  10. static inline void fmrx_led_off(void)
  11. {
  12. PORTB |= (1 << 0);
  13. }
  14. static void say(const char *str)
  15. {
  16. #if 0
  17. char c;
  18. while ((c = *str++))
  19. fmrx_recv_byte(c);
  20. #endif
  21. }
  22. void fmrx_init(void)
  23. {
  24. uint8_t tccr1b;
  25. /* ICP1/PD4 is input, with pullup */
  26. DDRD &= ~(1 << 4);
  27. PORTD |= (1 << 4);
  28. /* PB0 is RXLED */
  29. DDRB |= (1 << 0);
  30. fmrx_led_off();
  31. /* Stop counter */
  32. TCCR1B = 0;
  33. /* Normal mode, no comparators */
  34. TCCR1A = 0;
  35. /* Enable interrupts on input capture */
  36. TIMSK1 = (1 << ICIE1);
  37. /* Clear timer counter */
  38. TCNT1 = 0;
  39. /*
  40. * Input capture noise canceler on, no prescaler, normal mode;
  41. * start timer
  42. */
  43. tccr1b = (1 << ICNC1) + (1 << CS10);
  44. if (!(PIND & (1 << 4)))
  45. tccr1b |= 1 << ICES1;
  46. TCCR1B = tccr1b;
  47. }
  48. static uint16_t bytes;
  49. void fmrx_set_speed(uint32_t baudrate)
  50. {
  51. char msg[256];
  52. one_bit_lo = F_CPU / (4 * baudrate);
  53. one_bit_hi = 3 * one_bit_lo;
  54. bytes = 0;
  55. sprintf(msg, "\r\nbaudrate = %lu\r\n"
  56. "one_bit_lo = %u\r\n"
  57. "one_bit_hi = %u\r\n",
  58. baudrate, one_bit_lo, one_bit_hi);
  59. say(msg);
  60. }
  61. /* We "hunt" for a block until we find this bit pattern; same as ABC800 */
  62. #define CAS_SYNC_PATTERN 0x0216 /* SYNC + STX */
  63. #define CAS_BLOCK_LEN (1+2+253+1+2) /* type+num+data+ETX+checksum */
  64. /* Interrupt routine for edge capture */
  65. ISR(TIMER1_CAPT_vect)
  66. {
  67. static uint16_t last_edge;
  68. static uint16_t data;
  69. static uint8_t bits;
  70. char tbuf[16];
  71. uint16_t edge, delta;
  72. TCCR1B ^= (1 << ICES1); /* Next edge -> opposite polarity */
  73. edge = ICR1;
  74. delta = edge - last_edge;
  75. if (delta < one_bit_lo) {
  76. /* Early edge, no action */
  77. say("E");
  78. return;
  79. } else if (delta < one_bit_hi) {
  80. say("D");
  81. /* A data bit edge */
  82. data |= (1 << 15);
  83. } else {
  84. say("C");
  85. /* Clock edge */
  86. last_edge = edge;
  87. if (bytes) {
  88. if (--bits == 0) {
  89. uint8_t outbyte = data >> 8;
  90. sprintf(tbuf, "<%02x>", outbyte);
  91. say(tbuf);
  92. fmrx_recv_byte(outbyte);
  93. data = 0; /* To avoid false sync */
  94. bits = 8;
  95. if (--bytes == 0)
  96. fmrx_led_off();
  97. }
  98. } else {
  99. sprintf(tbuf, "[%04x]", data);
  100. say(tbuf);
  101. if (data == CAS_SYNC_PATTERN) {
  102. bits = 8;
  103. bytes = CAS_BLOCK_LEN;
  104. fmrx_led_on();
  105. }
  106. }
  107. data >>= 1;
  108. }
  109. sprintf(tbuf, "%u ", delta);
  110. say(tbuf);
  111. }