fw: Minimal CDC implementation of new framing protocol

Throwing away mode and length from incoming data. Adding mode and
length to outgoing data.

Splitting responses into frames small enough for the USB<->UART
transceiver to handle.
This commit is contained in:
Mikael Ågren 2024-09-16 14:26:12 +02:00
parent f9feb2e74d
commit 2f4298930c
No known key found for this signature in database
GPG Key ID: E02DA3D397792C46
3 changed files with 59 additions and 13 deletions

View File

@ -412,12 +412,16 @@ int main(void)
/*@+mustfreeonly@*/ /*@+mustfreeonly@*/
ctx.use_uss = FALSE; ctx.use_uss = FALSE;
uint8_t mode = 0;
uint8_t mode_bytes_left = 0;
scramble_ram(); scramble_ram();
for (;;) { for (;;) {
switch (state) { switch (state) {
case FW_STATE_INITIAL: case FW_STATE_INITIAL:
if (readcommand(&hdr, cmd, state) == -1) { if (readcommand(&hdr, cmd, state, &mode,
&mode_bytes_left) == -1) {
state = FW_STATE_FAIL; state = FW_STATE_FAIL;
break; break;
} }
@ -426,7 +430,8 @@ int main(void)
break; break;
case FW_STATE_LOADING: case FW_STATE_LOADING:
if (readcommand(&hdr, cmd, state) == -1) { if (readcommand(&hdr, cmd, state, &mode,
&mode_bytes_left) == -1) {
state = FW_STATE_FAIL; state = FW_STATE_FAIL;
break; break;
} }

View File

@ -22,7 +22,8 @@ static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
enum cmdlen len); enum cmdlen len);
static int parseframe(uint8_t b, struct frame_header *hdr); static int parseframe(uint8_t b, struct frame_header *hdr);
static void write(uint8_t *buf, size_t nbytes); 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 int bytelen(enum cmdlen cmdlen);
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, 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; 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; uint8_t in = 0;
set_led((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE); set_led((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE);
in = readbyte(); in = readbyte(mode, mode_bytes_left);
if (parseframe(in, hdr) == -1) { if (parseframe(in, hdr) == -1) {
htif_puts("Couldn't parse header\n"); 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); (void)memset(cmd, 0, CMDLEN_MAXBYTES);
// Now we know the size of the cmd frame, read it all // 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"); htif_puts("read: buffer overrun\n");
return -1; return -1;
} }
@ -115,6 +117,10 @@ void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
nbytes = bytelen(len); nbytes = bytelen(len);
// Mode Protocol Header
writebyte(MODE_CDC);
writebyte(2);
// Frame Protocol Header // Frame Protocol Header
writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len)); 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); writebyte(rspcode);
nbytes--; 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) 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 (;;) { for (;;) {
if (*can_rx) { if (*can_rx) {
return *rx; uint32_t b = *rx;
return b;
} }
} }
} }
static int read(uint8_t *buf, size_t bufsize, size_t nbytes) 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, uint8_t *mode,
uint8_t *mode_bytes_left)
{ {
if (nbytes > bufsize) { if (nbytes > bufsize) {
return -1; return -1;
} }
for (int n = 0; n < nbytes; n++) { for (int n = 0; n < nbytes; n++) {
buf[n] = readbyte(); buf[n] = readbyte(mode, mode_bytes_left);
} }
return 0; return 0;

View File

@ -8,6 +8,11 @@
#ifndef PROTO_H #ifndef PROTO_H
#define PROTO_H #define PROTO_H
enum mode {
MODE_CDC = 0x40,
MODE_HID = 0x80,
};
enum endpoints { enum endpoints {
DST_HW_IFPGA, DST_HW_IFPGA,
DST_HW_AFPGA, DST_HW_AFPGA,
@ -52,7 +57,8 @@ struct frame_header {
/*@ -exportlocal @*/ /*@ -exportlocal @*/
void writebyte(uint8_t b); 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); 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 #endif