fmtx.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Transmit an FM-modulated signal using the USART in SPI master mode.
  3. * As per ABC standard, this signal is transmitted MSB first.
  4. */
  5. #include "usbcas.h"
  6. #define BIT_PATTERN_LEN_LG2 2
  7. #define BITS_PER_PATTERN_BYTE (8 >> BIT_PATTERN_LEN_LG2)
  8. #define PATTERN_BIT_MASK ((1 << BITS_PER_PATTERN_BYTE) - 1)
  9. #include "fmpat.h"
  10. static void fmtx_set_speed(uint8_t divisor);
  11. /* Post-block silent pause, in pattern times */
  12. static unsigned int block_pause(uint8_t blktype, uint8_t divisor)
  13. {
  14. if (blktype == 0) /* data block */
  15. return 362 << BIT_PATTERN_LEN_LG2;
  16. else /* header block */
  17. return (3*362) << BIT_PATTERN_LEN_LG2;
  18. }
  19. /* Triple buffer: one being transmitted, one being received, and one ready. */
  20. static struct cas_block block[3];
  21. #define TX_BUSY 0
  22. #define TX_IDLE (1 << TXC1)
  23. /* Disable the TX ISR */
  24. static inline ATTR_ALWAYS_INLINE void fmtx_disable(void)
  25. {
  26. UCSR1B &= ~(1 << UDRIE1);
  27. }
  28. static uint8_t parity;
  29. /*
  30. * Send stuff if we have anything to send
  31. */
  32. ISR(USART1_UDRE_vect)
  33. {
  34. static uint8_t tx_data, tx_bits;
  35. static unsigned int tx_offset; /* Offset into current buffer */
  36. static struct cas_block *blk = &block[0];
  37. uint8_t pattern;
  38. while (!tx_bits) {
  39. if (!blk->ready || !motor_relay()) {
  40. /* Hold the line for one pattern time, then idle */
  41. UCSR1A = TX_IDLE;
  42. UDR1 = parity;
  43. fmtx_disable(); /* Nothing left to do */
  44. return;
  45. } else if (blk->divisor) {
  46. fmtx_set_speed(blk->divisor);
  47. blk->divisor = 0;
  48. } else if (tx_offset < sizeof blk->data) {
  49. tx_data = ((const uint8_t *)&blk->data)[tx_offset++];
  50. tx_bits = 8;
  51. } else if (blk->pause) {
  52. /* Interblock silence; hold the line */
  53. UCSR1A = TX_IDLE;
  54. UDR1 = parity;
  55. blk->pause--;
  56. return;
  57. } else {
  58. blk->ready = false; /* Free buffer */
  59. blk = blk->next;
  60. tx_offset = 0;
  61. }
  62. }
  63. /* Actual data bits available */
  64. pattern = fm_pat[tx_data & PATTERN_BIT_MASK] ^ parity;
  65. tx_data >>= BITS_PER_PATTERN_BYTE;
  66. parity = -((int8_t)pattern < 0);
  67. tx_bits -= BITS_PER_PATTERN_BYTE;
  68. UCSR1A = TX_IDLE;
  69. UDR1 = pattern;
  70. }
  71. /*
  72. * Synchronize transmitter before reconfiguration
  73. */
  74. void fmtx_drain(void)
  75. {
  76. /* Wait until input queue is idle and we have had at least one output */
  77. while ((UCSR1B & (1 << UDRIE1)) || !(UCSR1A & TX_IDLE))
  78. do_usb_tasks();
  79. }
  80. static inline uint16_t divisor_to_ubrr(uint8_t divisor)
  81. {
  82. uint16_t ubrr;
  83. if (!divisor)
  84. divisor = CAS_DIVISOR_ABC80;
  85. #if F_CPU != 16000000
  86. #error "Assuming F_CPU is 16 MHz"
  87. #endif
  88. ubrr = ((uint16_t)divisor << (8-BIT_PATTERN_LEN_LG2))/3 - 1;
  89. if (ubrr > 4095)
  90. ubrr = 4095;
  91. return ubrr;
  92. }
  93. static void fmtx_set_speed(uint8_t divisor)
  94. {
  95. if (!divisor)
  96. divisor = CAS_DIVISOR_ABC80;
  97. parity = 0xff; /* We start out with a high idle */
  98. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  99. PORTD |= 0x28; /* Drive data and clock high while idle */
  100. UCSR1B = 0; /* Disable transmitter and ISR */
  101. /*
  102. * SPI master mode, mode 1, LSB first
  103. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  104. * is 1 when idle and the TXLED is OFF.
  105. */
  106. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  107. /* UBRR must be zero when the transmitter is enabled */
  108. UBRR1 = 0;
  109. /* Enable transmitter, but not receiver and not the ISR (yet) */
  110. UCSR1B = (1 << TXEN1);
  111. /* Configure baud rate */
  112. UBRR1 = divisor_to_ubrr(divisor);
  113. /*
  114. * Enable transmitter ISR (which probably will immediately
  115. * go to idle...)
  116. */
  117. fmtx_enable();
  118. }
  119. static enum rx_state {
  120. rx_amp, /* Waiting for & */
  121. rx_cmd, /* & received */
  122. rx_filename, /* Getting filename */
  123. rx_num, /* Getting numeric arguments */
  124. rx_data, /* Receiving data */
  125. rx_idle = rx_num /* Root state */
  126. } rx_state;
  127. static unsigned int rx_blk_cnt;
  128. static struct cas_block *rx_blk;
  129. void fmtx_init(void)
  130. {
  131. int i;
  132. /* Fill in the invariant part of the block buffers */
  133. memset(block, 0, sizeof block);
  134. block[0].next = &block[1];
  135. block[1].next = &block[2];
  136. block[2].next = &block[0];
  137. rx_blk = &block[0];
  138. rx_state = rx_idle;
  139. for (i = 0; i <= 2; i++) {
  140. memset(block[i].data.sync, 0x16, sizeof block[i].data.sync);
  141. block[i].data.stx = 0x02;
  142. block[i].data.etx = 0x03;
  143. }
  144. fmtx_set_speed(CAS_DIVISOR_ABC80);
  145. }
  146. bool fmtx_full(void)
  147. {
  148. return rx_blk->ready;
  149. }
  150. static void fmtx_wait_for_free_buffer(void)
  151. {
  152. while (rx_blk->ready)
  153. do_usb_tasks();
  154. }
  155. static enum rx_state setup_block(unsigned int blkno)
  156. {
  157. uint8_t blktype;
  158. rx_blk->data.blkno = blkno;
  159. blktype = -(blkno == -1U);
  160. rx_blk->data.blktype = blktype;
  161. rx_blk->pause = block_pause(blktype, rx_blk->divisor);
  162. /* Initialize checksum */
  163. rx_blk->data.csum = 0x03 /* ETX is part of the checksum */
  164. + blktype + (uint8_t)blkno + (uint8_t)(blkno >> 8);
  165. return rx_data;
  166. }
  167. static uint16_t checksum_range(const uint8_t *data, unsigned int len)
  168. {
  169. uint16_t csum = 0;
  170. while (len--)
  171. csum += *data++;
  172. return csum;
  173. }
  174. #define MAX_ARGS 4
  175. static enum rx_state do_cmd(uint8_t cmd, const uint16_t *arg)
  176. {
  177. switch (cmd) {
  178. case 'U':
  179. /* Firmware update, kick us to boot loader */
  180. /* &U */
  181. go_to_bootloader();
  182. return rx_idle;
  183. case 'R':
  184. /* Set receive baudrate divisor */
  185. /* &R divisor */
  186. fmtx_wait_for_free_buffer();
  187. rx_blk->divisor = arg[0];
  188. return rx_idle;
  189. case 'H':
  190. /* Send header block */
  191. /* &H */
  192. rx_blk_cnt = 1;
  193. return setup_block(-1);
  194. case 'D':
  195. /* Send data block */
  196. /* &D blocknr */
  197. rx_blk_cnt = 1;
  198. return setup_block(arg[0]);
  199. case 'F':
  200. {
  201. uint8_t divisor;
  202. /* Send file */
  203. /* &F filename,blocks[,divisor] */
  204. setup_block(-1);
  205. rx_blk_cnt = arg[0];
  206. rx_blk->divisor = CAS_DIVISOR_ABC80; /* Header always slow */
  207. divisor = arg[1];
  208. if (divisor == CAS_DIVISOR_ABC80)
  209. divisor = 0;
  210. rx_blk->data.hdr.divisor = divisor;
  211. memset(rx_blk->data.hdr.zero, 0, sizeof rx_blk->data.hdr.zero);
  212. rx_blk->data.hdr.nblocks = rx_blk_cnt;
  213. /* Checksum filename and divisor */
  214. rx_blk->data.csum += checksum_range(rx_blk->data.data, 12);
  215. rx_blk->data.csum += (uint8_t)rx_blk_cnt
  216. + (uint8_t)(rx_blk_cnt >> 8);
  217. rx_blk->ready = true;
  218. rx_blk = rx_blk->next;
  219. if (!rx_blk_cnt)
  220. return rx_idle;
  221. if (divisor) {
  222. fmtx_wait_for_free_buffer();
  223. rx_blk->divisor = divisor;
  224. }
  225. return rx_data;
  226. }
  227. default:
  228. return rx_idle; /* Unknown/unimplemented command */
  229. }
  230. }
  231. void fmtx_recv_byte(uint8_t byte)
  232. {
  233. static uint8_t cmd; /* Command byte */
  234. static uint8_t ctr; /* State-specific counter */
  235. static uint16_t arg[4];
  236. switch (rx_state) {
  237. case rx_amp:
  238. if (byte == '&')
  239. rx_state = rx_cmd;
  240. break;
  241. case rx_cmd:
  242. ctr = 0;
  243. memset(arg, 0, sizeof arg);
  244. cmd = byte;
  245. if (byte == 'F') {
  246. memset(rx_blk->data.hdr.filename, ' ',
  247. sizeof rx_blk->data.hdr.filename);
  248. rx_state = rx_filename;
  249. } else if (byte > ' ' && byte <= '~')
  250. rx_state = rx_num;
  251. else
  252. rx_state = rx_idle;
  253. break;
  254. case rx_filename:
  255. switch (byte) {
  256. case '\n':
  257. ctr = 0;
  258. rx_state = do_cmd(cmd, arg);
  259. break;
  260. case '.':
  261. memset(rx_blk->data.hdr.filename+8, ' ', 3);
  262. ctr = 8;
  263. break;
  264. case ':':
  265. ctr = 0;
  266. break;
  267. case ',':
  268. rx_state = rx_num;
  269. break;
  270. default:
  271. if (byte <= ' ' || byte > '~' || ctr >= 11)
  272. break;
  273. if (byte & 0x40)
  274. byte &= ~0x20; /* Upper case */
  275. rx_blk->data.hdr.filename[ctr++] = byte;
  276. break;
  277. }
  278. break;
  279. case rx_num:
  280. if (byte == '\n') {
  281. ctr = 0;
  282. rx_state = do_cmd(cmd, arg);
  283. break;
  284. } else if (byte == ',') {
  285. ctr++;
  286. } else if (ctr < MAX_ARGS) {
  287. byte -= '0';
  288. if (byte < 10)
  289. arg[ctr] = arg[ctr]*10 + byte;
  290. }
  291. break;
  292. case rx_data:
  293. rx_blk->data.data[ctr++] = byte;
  294. rx_blk->data.csum += byte;
  295. if (ctr >= 253) {
  296. uint16_t nextblk = rx_blk->data.blkno + 1;
  297. rx_blk->ready = true;
  298. rx_blk = rx_blk->next;
  299. fmtx_enable();
  300. if (--rx_blk_cnt) {
  301. fmtx_wait_for_free_buffer();
  302. setup_block(nextblk);
  303. } else {
  304. rx_state = rx_idle;
  305. }
  306. }
  307. break;
  308. }
  309. }