tillitis-key/hw/application_fpga/fw/tk1/proto.c

196 lines
3.5 KiB
C
Raw Normal View History

2022-09-19 02:51:11 -04:00
/*
2023-02-18 10:16:46 -05:00
* Copyright (C) 2022, 2023 - Tillitis AB
2022-09-19 02:51:11 -04:00
* SPDX-License-Identifier: GPL-2.0-only
*/
#include "proto.h"
2022-10-20 08:50:21 -04:00
#include "../tk1_mem.h"
2023-03-24 06:47:30 -04:00
#include "assert.h"
#include "led.h"
2022-09-19 02:51:11 -04:00
#include "lib.h"
#include "state.h"
2022-09-19 02:51:11 -04:00
#include "types.h"
// clang-format off
2022-10-20 08:50:21 -04:00
static volatile uint32_t *can_rx = (volatile uint32_t *)TK1_MMIO_UART_RX_STATUS;
static volatile uint32_t *rx = (volatile uint32_t *)TK1_MMIO_UART_RX_DATA;
static volatile uint32_t *can_tx = (volatile uint32_t *)TK1_MMIO_UART_TX_STATUS;
static volatile uint32_t *tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA;
2022-09-19 02:51:11 -04:00
// clang-format on
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);
2023-03-24 06:47:30 -04:00
static int bytelen(enum cmdlen cmdlen);
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
enum cmdlen len)
2022-09-19 02:51:11 -04:00
{
return (id << 5) | (endpoint << 3) | (status << 2) | len;
}
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state)
{
2023-03-16 08:51:24 -04:00
uint8_t in = 0;
2023-03-16 09:25:17 -04:00
set_led((state == FW_STATE_LOADING) ? LED_BLACK : LED_WHITE);
in = readbyte();
if (parseframe(in, hdr) == -1) {
htif_puts("Couldn't parse header\n");
return -1;
}
(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) {
htif_puts("read: buffer overrun\n");
return -1;
}
// Is it for us?
if (hdr->endpoint != DST_FW) {
htif_puts("Message not meant for us\n");
return -1;
}
return 0;
}
static int parseframe(uint8_t b, struct frame_header *hdr)
2022-09-19 02:51:11 -04:00
{
if ((b & 0x80) != 0) {
// Bad version
return -1;
}
if ((b & 0x4) != 0) {
// Must be 0
return -1;
}
hdr->id = (b & 0x60) >> 5;
hdr->endpoint = (b & 0x18) >> 3;
2023-03-24 06:47:30 -04:00
hdr->len = bytelen(b & 0x3);
2022-09-19 02:51:11 -04:00
return 0;
}
// Send a firmware reply with a frame header, response code rspcode and
// following data in buf
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
{
2023-03-16 08:51:24 -04:00
size_t nbytes = 0;
enum cmdlen len = 0; // length covering (rspcode + length of buf)
2022-09-19 02:51:11 -04:00
switch (rspcode) {
case FW_RSP_NAME_VERSION:
len = LEN_32;
break;
case FW_RSP_LOAD_APP:
2022-09-19 02:51:11 -04:00
len = LEN_4;
break;
case FW_RSP_LOAD_APP_DATA:
len = LEN_4;
break;
case FW_RSP_LOAD_APP_DATA_READY:
2023-03-24 06:47:30 -04:00
len = LEN_128;
2022-09-19 02:51:11 -04:00
break;
2022-11-21 08:19:09 -05:00
case FW_RSP_GET_UDI:
len = LEN_32;
break;
2022-09-19 02:51:11 -04:00
default:
htif_puts("fwreply(): Unknown response code: 0x");
htif_puthex(rspcode);
htif_lf();
2022-09-19 02:51:11 -04:00
return;
}
2023-03-24 06:47:30 -04:00
nbytes = bytelen(len);
2022-09-19 02:51:11 -04:00
// Frame Protocol Header
writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len));
// FW protocol header
writebyte(rspcode);
nbytes--;
write(buf, nbytes);
}
void writebyte(uint8_t b)
{
for (;;) {
if (*can_tx) {
*tx = b;
return;
}
}
}
static void write(uint8_t *buf, size_t nbytes)
2022-09-19 02:51:11 -04:00
{
for (int i = 0; i < nbytes; i++) {
writebyte(buf[i]);
}
}
uint8_t readbyte(void)
2022-09-19 02:51:11 -04:00
{
for (;;) {
if (*can_rx) {
return *rx;
}
}
}
static int read(uint8_t *buf, size_t bufsize, size_t nbytes)
2022-09-19 02:51:11 -04:00
{
if (nbytes > bufsize) {
return -1;
}
2022-09-19 02:51:11 -04:00
for (int n = 0; n < nbytes; n++) {
buf[n] = readbyte();
}
return 0;
2022-09-19 02:51:11 -04:00
}
2023-03-24 06:47:30 -04:00
// bytelen returns the number of bytes a cmdlen takes
static int bytelen(enum cmdlen cmdlen)
{
int len;
switch (cmdlen) {
case LEN_1:
len = 1;
break;
case LEN_4:
len = 4;
break;
case LEN_32:
len = 32;
break;
case LEN_128:
len = 128;
break;
default:
// Shouldn't happen
assert(1 == 2);
}
return len;
}