main.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * USB (CDC-ACM) <-> I2C bridge, ATmega8U2 @ 16 MHz.
  3. *
  4. * Request frame (host -> device), several frames may be concatenated freely:
  5. * A5 01 addr wlen rlen wdata[wlen] I2C transaction (7-bit addr, wlen/rlen <= 32)
  6. * A5 02 n set SCL delay (0 = fastest, default 4 ~ 400 kHz)
  7. * A5 03 ping
  8. * A5 04 bus recovery
  9. * Reply (device -> host), one per request, in order:
  10. * status [payload]
  11. * status: 0 OK, 1 NACK on address, 2 NACK on data, 3 bus error/timeout,
  12. * 0x10 unknown op, 0x11 bad length
  13. * payload: XFER -> rlen bytes (only if status==0); PING -> proto, maxlen
  14. * Bytes outside a frame are ignored (so ModemManager "AT" probes are harmless).
  15. */
  16. #include <avr/io.h>
  17. #include <avr/wdt.h>
  18. #include <string.h>
  19. #include "usb.h"
  20. #include "i2c.h"
  21. #define MAGIC 0xA5
  22. #define MAXLEN 32
  23. #define PROTO 1
  24. enum { OP_XFER = 1, OP_SPEED = 2, OP_PING = 3, OP_RECOVER = 4, OP_LINES = 5 };
  25. enum { ST_BAD_OP = 0x10, ST_BAD_LEN = 0x11 };
  26. static uint8_t txb[USB_PACKET];
  27. static uint8_t txn;
  28. static void flush(void)
  29. {
  30. if (txn) { usb_tx(txb, txn); txn = 0; }
  31. }
  32. static uint8_t *reply_begin(uint8_t len) /* reserve len bytes in the tx buffer */
  33. {
  34. if (txn + len > USB_PACKET) flush();
  35. uint8_t *p = &txb[txn];
  36. txn += len;
  37. return p;
  38. }
  39. static void reply1(uint8_t st) { *reply_begin(1) = st; }
  40. /* ---- frame parser ---- */
  41. static uint8_t fbuf[4 + MAXLEN];
  42. static uint8_t fn;
  43. static bool in_frame;
  44. static void frame_done(void) { in_frame = false; fn = 0; }
  45. static void feed(uint8_t b)
  46. {
  47. if (!in_frame) {
  48. if (b == MAGIC) { in_frame = true; fn = 0; }
  49. return;
  50. }
  51. fbuf[fn++] = b;
  52. uint8_t need;
  53. switch (fbuf[0]) {
  54. case OP_XFER:
  55. if (fn < 4) return;
  56. if (fbuf[2] > MAXLEN || fbuf[3] > MAXLEN) { reply1(ST_BAD_LEN); frame_done(); return; }
  57. need = 4 + fbuf[2];
  58. break;
  59. case OP_SPEED:
  60. case OP_LINES: need = 2; break;
  61. case OP_PING:
  62. case OP_RECOVER: need = 1; break;
  63. default: reply1(ST_BAD_OP); frame_done(); return;
  64. }
  65. if (fn < need) return;
  66. switch (fbuf[0]) {
  67. case OP_XFER: {
  68. uint8_t rlen = fbuf[3];
  69. uint8_t *p = reply_begin(1 + rlen); /* reserve worst case, trim on error */
  70. uint8_t st = i2c_xfer(fbuf[1] & 0x7F, &fbuf[4], fbuf[2], p + 1, rlen);
  71. p[0] = st;
  72. if (st != I2C_OK) txn -= rlen;
  73. break; }
  74. case OP_SPEED: i2c_set_delay(fbuf[1]); reply1(0); break;
  75. case OP_PING: { uint8_t *p = reply_begin(3); p[0] = 0; p[1] = PROTO; p[2] = MAXLEN; break; }
  76. case OP_RECOVER: reply1(i2c_recover()); break;
  77. case OP_LINES: { uint8_t *p = reply_begin(2); p[0] = 0; p[1] = i2c_lines(fbuf[1]); break; }
  78. }
  79. frame_done();
  80. }
  81. int main(void)
  82. {
  83. MCUSR = 0;
  84. wdt_disable();
  85. CLKPR = 0x80; CLKPR = 0; /* full 16 MHz, no prescaler */
  86. i2c_init();
  87. usb_init();
  88. TCCR0B = (1 << CS02) | (1 << CS00); /* clk/1024: overflow every ~16.4 ms */
  89. uint8_t idle = 0;
  90. uint8_t rx[USB_PACKET];
  91. for (;;) {
  92. usb_task();
  93. uint8_t n = usb_rx(rx);
  94. if (n) {
  95. idle = 0;
  96. for (uint8_t i = 0; i < n; i++) feed(rx[i]);
  97. flush(); /* one IN packet for the whole OUT packet */
  98. }
  99. if (TIFR0 & (1 << TOV0)) { /* resync if a frame stalls ~100 ms */
  100. TIFR0 = (1 << TOV0);
  101. if (in_frame && ++idle > 6) frame_done();
  102. }
  103. }
  104. }