diff --git a/hw/application_fpga/fw/tk1/main.c b/hw/application_fpga/fw/tk1/main.c index 70e29c27..877ce26a 100644 --- a/hw/application_fpga/fw/tk1/main.c +++ b/hw/application_fpga/fw/tk1/main.c @@ -412,12 +412,16 @@ int main(void) /*@+mustfreeonly@*/ ctx.use_uss = FALSE; + uint8_t mode = 0; + uint8_t mode_bytes_left = 0; + scramble_ram(); for (;;) { switch (state) { case FW_STATE_INITIAL: - if (readcommand(&hdr, cmd, state) == -1) { + if (readcommand(&hdr, cmd, state, &mode, + &mode_bytes_left) == -1) { state = FW_STATE_FAIL; break; } @@ -426,7 +430,8 @@ int main(void) break; case FW_STATE_LOADING: - if (readcommand(&hdr, cmd, state) == -1) { + if (readcommand(&hdr, cmd, state, &mode, + &mode_bytes_left) == -1) { state = FW_STATE_FAIL; break; } diff --git a/hw/application_fpga/fw/tk1/proto.c b/hw/application_fpga/fw/tk1/proto.c index 4acbce48..7ed07112 100644 --- a/hw/application_fpga/fw/tk1/proto.c +++ b/hw/application_fpga/fw/tk1/proto.c @@ -22,7 +22,8 @@ static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len); static int parseframe(uint8_t b, struct frame_header *hdr); static void write(uint8_t *buf, size_t nbytes); -static int read(uint8_t *buf, size_t bufsize, size_t nbytes); +static int read(uint8_t *buf, size_t bufsize, size_t nbytes, uint8_t *mode, + uint8_t *mode_bytes_left); static int bytelen(enum cmdlen cmdlen); static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, @@ -31,12 +32,13 @@ static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, return (id << 5) | (endpoint << 3) | (status << 2) | len; } -int readcommand(struct frame_header *hdr, uint8_t *cmd, int state) +int readcommand(struct frame_header *hdr, uint8_t *cmd, int state, + uint8_t *mode, uint8_t *mode_bytes_left) { uint8_t in = 0; set_led((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE); - in = readbyte(); + in = readbyte(mode, mode_bytes_left); if (parseframe(in, hdr) == -1) { htif_puts("Couldn't parse header\n"); @@ -45,7 +47,7 @@ int readcommand(struct frame_header *hdr, uint8_t *cmd, int state) (void)memset(cmd, 0, CMDLEN_MAXBYTES); // Now we know the size of the cmd frame, read it all - if (read(cmd, CMDLEN_MAXBYTES, hdr->len) != 0) { + if (read(cmd, CMDLEN_MAXBYTES, hdr->len, mode, mode_bytes_left) != 0) { htif_puts("read: buffer overrun\n"); return -1; } @@ -115,6 +117,10 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf) nbytes = bytelen(len); + // Mode Protocol Header + writebyte(MODE_CDC); + writebyte(2); + // Frame Protocol Header writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len)); @@ -122,7 +128,19 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf) writebyte(rspcode); nbytes--; - write(buf, nbytes); + while (nbytes > 0) { + // Limit transfers to 64 bytes (2 byte header + 62 byte data) to + // fit in a single USB frame. + size_t tx_count = nbytes > 62 ? 62 : nbytes; + // Mode Protocol Header + writebyte(MODE_CDC); + writebyte(tx_count & 0xff); + + // Data + write(buf, tx_count); + nbytes -= tx_count; + buf += tx_count; + } } void writebyte(uint8_t b) @@ -142,23 +160,40 @@ static void write(uint8_t *buf, size_t nbytes) } } -uint8_t readbyte(void) +uint8_t readbyte_(void) { for (;;) { if (*can_rx) { - return *rx; + uint32_t b = *rx; + return b; + } + } +} + +uint8_t readbyte(uint8_t *mode, uint8_t *mode_bytes_left) +{ + if (*mode_bytes_left == 0) { + *mode = readbyte_(); + if (*mode != MODE_CDC) { + htif_puts("We only support MODE_CDC\n"); + } else { + *mode_bytes_left = readbyte_(); } } + uint8_t b = readbyte_(); + *mode_bytes_left -= 1; + return b; } -static int read(uint8_t *buf, size_t bufsize, size_t nbytes) +static int read(uint8_t *buf, size_t bufsize, size_t nbytes, uint8_t *mode, + uint8_t *mode_bytes_left) { if (nbytes > bufsize) { return -1; } for (int n = 0; n < nbytes; n++) { - buf[n] = readbyte(); + buf[n] = readbyte(mode, mode_bytes_left); } return 0; diff --git a/hw/application_fpga/fw/tk1/proto.h b/hw/application_fpga/fw/tk1/proto.h index 1c13c5c4..57f463d7 100644 --- a/hw/application_fpga/fw/tk1/proto.h +++ b/hw/application_fpga/fw/tk1/proto.h @@ -8,6 +8,11 @@ #ifndef PROTO_H #define PROTO_H +enum mode { + MODE_CDC = 0x40, + MODE_HID = 0x80, +}; + enum endpoints { DST_HW_IFPGA, DST_HW_AFPGA, @@ -52,7 +57,8 @@ struct frame_header { /*@ -exportlocal @*/ void writebyte(uint8_t b); -uint8_t readbyte(void); +uint8_t readbyte(uint8_t *mode, uint8_t *mode_bytes_left); void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf); -int readcommand(struct frame_header *hdr, uint8_t *cmd, int state); +int readcommand(struct frame_header *hdr, uint8_t *cmd, int state, + uint8_t *mode, uint8_t *mode_bytes_left); #endif