summaryrefslogtreecommitdiff
path: root/cmd/sbc_harness
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-23 15:21:09 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-10-23 15:21:09 -0600
commite7378b9f9b122e05baebce387fe9c3844c0736b6 (patch)
treece921a21811cb4ded792f61f2d933cf4e8f87a96 /cmd/sbc_harness
parent9940877f4bb44bc69fecf7fb5afcf3cbab90f088 (diff)
wip
Diffstat (limited to 'cmd/sbc_harness')
-rw-r--r--cmd/sbc_harness/CMakeLists.txt3
-rw-r--r--cmd/sbc_harness/hw/w5500.c145
-rw-r--r--cmd/sbc_harness/hw/w5500.h18
-rw-r--r--cmd/sbc_harness/main.c30
4 files changed, 119 insertions, 77 deletions
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt
index 201b378..54553f0 100644
--- a/cmd/sbc_harness/CMakeLists.txt
+++ b/cmd/sbc_harness/CMakeLists.txt
@@ -15,8 +15,9 @@ target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config
target_include_directories(sbc_harness PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(sbc_harness
pico_stdlib
- hardware_spi
+ hardware_flash
hardware_gpio
+ hardware_spi
libmisc
libusb
diff --git a/cmd/sbc_harness/hw/w5500.c b/cmd/sbc_harness/hw/w5500.c
index b95ad88..ab1ac19 100644
--- a/cmd/sbc_harness/hw/w5500.c
+++ b/cmd/sbc_harness/hw/w5500.c
@@ -122,7 +122,7 @@ static COROUTINE w5500_irq_cr(void *_chip) {
for (uint8_t socknum = 0; socknum < 8; socknum++) {
if (!(sockmask & (1<<socknum)))
continue;
- struct _w5500_listener *listener = &chip->listeners[socknum];
+ struct _w5500_tcp_listener *listener = &chip->listeners[socknum];
uint8_t sockintr = w5500ll_read_sock_reg(chip->spidev, socknum, interrupt);
@@ -144,19 +144,19 @@ static COROUTINE w5500_irq_cr(void *_chip) {
/* init() *********************************************************************/
-static implements_net_conn *w5500_accept(implements_net_listener *_listener);
-static ssize_t w5500_read(implements_net_conn *conn, void *buf, size_t count);
-static ssize_t w5500_write(implements_net_conn *conn, void *buf, size_t count);
-static int w5500_close(implements_net_conn *conn, bool rd, bool wr);
+static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *listener);
+static ssize_t w5500_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count);
+static ssize_t w5500_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count);
+static int w5500_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr);
-static struct net_listener_vtable w5500_listener_vtable = {
- .accept = w5500_accept,
+static struct net_stream_listener_vtable w5500_tcp_listener_vtable = {
+ .accept = w5500_tcp_accept,
};
-static struct net_conn_vtable w5500_conn_vtable = {
- .read = w5500_read,
- .write = w5500_write,
- .close = w5500_close,
+static struct net_stream_conn_vtable w5500_tcp_conn_vtable = {
+ .read = w5500_tcp_read,
+ .write = w5500_tcp_write,
+ .close = w5500_tcp_close,
};
static struct w5500 *w5500_chips[CONFIG_W5500_NUM] = {0};
@@ -183,13 +183,13 @@ void _w5500_init(struct w5500 *chip,
.next_local_port = CONFIG_W5500_LOCAL_PORT_MIN,
};
for (uint8_t i = 0; i < 8; i++) {
- chip->listeners[i] = (struct _w5500_listener){
+ chip->listeners[i] = (struct _w5500_tcp_listener){
/* const-after-init */
- .vtable = &w5500_listener_vtable,
+ .vtable = &w5500_tcp_listener_vtable,
.socknum = i,
.active_conn = {
/* const-after-init */
- .vtable = &w5500_conn_vtable,
+ .vtable = &w5500_tcp_conn_vtable,
/* mutable */
.read_open = false,
.write_open = false,
@@ -219,24 +219,44 @@ void _w5500_init(struct w5500 *chip,
/* chip methods ***************************************************************/
static inline void w5500_post_reset(struct w5500 *chip, struct net_eth_addr addr) {
+ /* The W5500 does not have a built-in MAC address, we must
+ * provide one. */
w5500ll_write_common_reg(chip->spidev, eth_addr, addr);
- /* The RP2040 needs a 1/sys_clk hysteresis between interrupts for us
- * to notice them. At the maximum-rated clock-rate of 133MHz, that
- * means 7.5ns (but the sbc-harness overclocks the RP2040, so we
- * could get away with even shorter).
+ /* The RP2040 needs a 1/sys_clk hysteresis between interrupts
+ * for us to notice them. At the maximum-rated clock-rate of
+ * 133MHz, that means 7.5ns (but the sbc-harness overclocks
+ * the RP2040, so we could get away with even shorter).
*
- * The hysteresis is (intlevel+1)*4/(150MHz) (if intlevel is
- * non-zero), or (intlevel+1)*26.7ns; so even the shortest-possible
- * hysteresis much larger than necessary for us. */
+ * If intlevel is non-zero, then the hysteresis is
+ * (intlevel+1)*4/(150MHz), or (intlevel+1)*26.7ns; so even
+ * the shortest-possible hysteresis much larger than necessary
+ * for us. */
w5500ll_write_common_reg(chip->spidev, intlevel, uint16be_marshal(1));
- /* This implementation does not care about any of the chip-level
- * interrupts. */
+ /* This implementation does not care about any of the
+ * chip-level interrupts. */
w5500ll_write_common_reg(chip->spidev, chip_interrupt_mask, 0);
- /* This implementation cares about interrupts for each socket. */
+ /* This implementation cares about interrupts for each
+ * socket. */
w5500ll_write_common_reg(chip->spidev, sock_interrupt_mask, 0xFF);
+
+ /* Configure retry/timeout.
+ *
+ * timeout_arp = 0.1ms * retry_time * (retry_count+1)
+ *
+ * retry_count
+ * timeout_tcp = 0.1ms * retry_time * Σ 2^min(n, floor(1+log_2(65535/retry_time)))
+ * n=0
+ *
+ * For retry_time=2000, retry_count=3, this means
+ *
+ * timeout_arp = 0.8s
+ * timeout_tcp = 3.0s
+ */
+ w5500ll_write_common_reg(chip->spidev, retry_time, uint16be_marshal(2000));
+ w5500ll_write_common_reg(chip->spidev, retry_count, 3);
}
void w5500_hard_reset(struct w5500 *chip, struct net_eth_addr addr) {
@@ -263,8 +283,8 @@ void w5500_netcfg(struct w5500 *chip, struct w5500_netcfg cfg) {
w5500ll_write_common_reg(chip->spidev, ip_addr, cfg.addr);
}
-implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum,
- uint16_t port) {
+implements_net_stream_listener *w5500_tcp_listen(struct w5500 *chip, uint8_t socknum,
+ uint16_t port) {
assert(chip);
assert(socknum < 8);
assert(port);
@@ -275,13 +295,13 @@ implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum,
return &chip->listeners[socknum];
}
-/* listener methods ***********************************************************/
+/* tcp_listener methods *******************************************************/
-static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) {
+static struct w5500 *w5500_tcp_listener_chip(struct _w5500_tcp_listener *listener) {
assert(listener);
assert(listener->socknum < 8);
- struct _w5500_listener *sock0 = &listener[-listener->socknum];
+ struct _w5500_tcp_listener *sock0 = &listener[-listener->socknum];
assert(sock0);
struct w5500 *chip =
((void *)sock0) - offsetof(struct w5500, listeners);
@@ -289,9 +309,9 @@ static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) {
return chip;
}
-static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t cmd) {
+static inline void w5500_tcp_listener_cmd(struct _w5500_tcp_listener *listener, uint8_t cmd) {
assert(listener);
- struct w5500 *chip = w5500_listener_chip(listener);
+ struct w5500 *chip = w5500_tcp_listener_chip(listener);
uint8_t socknum = listener->socknum;
cr_mutex_lock(&listener->cmd_mu);
@@ -301,12 +321,12 @@ static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t
cr_mutex_unlock(&listener->cmd_mu);
}
-static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) {
+static inline void w5500_tcp_listener_cmd_close(struct _w5500_tcp_listener *listener) {
assert(listener);
- struct w5500 *chip = w5500_listener_chip(listener);
+ struct w5500 *chip = w5500_tcp_listener_chip(listener);
uint8_t socknum = listener->socknum;
- w5500_listener_cmd(listener, CMD_CLOSE);
+ w5500_tcp_listener_cmd(listener, CMD_CLOSE);
w5500ll_write_sock_reg(chip->spidev, socknum, interrupt, 0xFF);
while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_CLOSED)
cr_yield();
@@ -314,27 +334,27 @@ static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) {
listener->active_conn.read_open = listener->active_conn.write_open = false;
}
-#define ASSERT_LISTENER() \
- struct _w5500_listener *self = \
- VCALL_SELF(struct _w5500_listener, \
- implements_net_listener, _self); \
- struct w5500 *chip = w5500_listener_chip(self); \
+#define ASSERT_LISTENER() \
+ struct _w5500_tcp_listener *self = \
+ VCALL_SELF(struct _w5500_tcp_listener, \
+ implements_net_stream_listener, _self); \
+ struct w5500 *chip = w5500_tcp_listener_chip(self); \
uint8_t socknum = self->socknum;
-static implements_net_conn *w5500_accept(implements_net_listener *_self) {
+static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *_self) {
ASSERT_LISTENER();
restart:
/* Mimics socket.c:socket(). */
- w5500_listener_cmd_close(self);
+ w5500_tcp_listener_cmd_close(self);
w5500ll_write_sock_reg(chip->spidev, socknum, mode, SOCKMODE_TCP);
w5500ll_write_sock_reg(chip->spidev, socknum, local_port, uint16be_marshal(self->port));
- w5500_listener_cmd(self, CMD_OPEN);
+ w5500_tcp_listener_cmd(self, CMD_OPEN);
while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_TCP_INIT)
cr_yield();
/* Mimics socket.c:listen(). */
- w5500_listener_cmd(self, CMD_LISTEN);
+ w5500_tcp_listener_cmd(self, CMD_LISTEN);
for (;;) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
switch (state) {
@@ -356,31 +376,32 @@ static implements_net_conn *w5500_accept(implements_net_listener *_self) {
/* conn methods ***************************************************************/
-static struct _w5500_listener *w5500_conn_listener(struct _w5500_conn *conn) {
+static struct _w5500_tcp_listener *w5500_tcp_conn_listener(struct _w5500_tcp_conn *conn) {
assert(conn);
- struct _w5500_listener *list =
- ((void *)conn) - offsetof(struct _w5500_listener, active_conn);
+ struct _w5500_tcp_listener *list =
+ ((void *)conn) - offsetof(struct _w5500_tcp_listener, active_conn);
return list;
}
#define ASSERT_CONN() \
- struct _w5500_conn *self = \
- VCALL_SELF(struct _w5500_conn, implements_net_conn, _self); \
- struct _w5500_listener *listener = w5500_conn_listener(self); \
- struct w5500 *chip = w5500_listener_chip(listener); \
+ struct _w5500_tcp_conn *self = \
+ VCALL_SELF(struct _w5500_tcp_conn, implements_net_stream_conn, _self); \
+ struct _w5500_tcp_listener *listener = w5500_tcp_conn_listener(self); \
+ struct w5500 *chip = w5500_tcp_listener_chip(listener); \
uint8_t socknum = listener->socknum;
-static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) {
+static ssize_t w5500_tcp_write(implements_net_stream_conn *_self, void *buf, size_t count) {
ASSERT_CONN();
assert(buf);
assert(count);
- /* What we really want is to pause until we receive an ACK
- * for some data we just queued, so that we can line up some
- * new data to keep the buffer full. But that's not what SEND_FINIAIUI, the
- * SEND_FINISHED interrupt doesn't fire until we receive the
- * *last* ACK for the data, when the buffer is entirely empty.
+ /* What we really want is to pause until we receive an ACK for
+ * some data we just queued, so that we can line up some new
+ * data to keep the buffer full. But that's not what
+ * SEND_FINIAIUI, the SEND_FINISHED interrupt doesn't fire
+ * until we receive the *last* ACK for the data, when the
+ * buffer is entirely empty.
*
* Which means we basically have to busy-poll for space in the
* buffer becoming available.
@@ -416,13 +437,13 @@ static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count)
w5500ll_write_sock_reg(chip->spidev, socknum, tx_write_pointer, uint16be_marshal(ptr+freesize));
/* Submit the queue. */
- w5500_listener_cmd(listener, CMD_SEND);
+ w5500_tcp_listener_cmd(listener, CMD_SEND);
done += freesize;
}
return done;
}
-static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) {
+static ssize_t w5500_tcp_read(implements_net_stream_conn *_self, void *buf, size_t count) {
ASSERT_CONN();
assert(buf);
assert(count);
@@ -452,20 +473,20 @@ static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) {
w5500ll_read(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, RX), &((char *)buf)[done], avail);
w5500ll_write_sock_reg(chip->spidev, socknum, rx_read_pointer, uint16be_marshal(ptr+avail));
- w5500_listener_cmd(listener, CMD_RECV);
+ w5500_tcp_listener_cmd(listener, CMD_RECV);
done += avail;
}
return done;
}
-static int w5500_close(implements_net_conn *_self, bool rd, bool wr) {
+static int w5500_tcp_close(implements_net_stream_conn *_self, bool rd, bool wr) {
ASSERT_CONN();
if (rd)
self->read_open = false;
if (wr && self->write_open) {
- w5500_listener_cmd(listener, CMD_DISCON);
+ w5500_tcp_listener_cmd(listener, CMD_DISCON);
while (self->write_open) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
switch (state) {
@@ -473,7 +494,7 @@ static int w5500_close(implements_net_conn *_self, bool rd, bool wr) {
self->write_open = false;
/* Can still read */
if (!self->read_open)
- w5500_listener_cmd_close(listener);
+ w5500_tcp_listener_cmd_close(listener);
break;
case STATE_CLOSED:
self->write_open = false;
diff --git a/cmd/sbc_harness/hw/w5500.h b/cmd/sbc_harness/hw/w5500.h
index d0c8d48..cf28579 100644
--- a/cmd/sbc_harness/hw/w5500.h
+++ b/cmd/sbc_harness/hw/w5500.h
@@ -13,21 +13,19 @@
#include "hw/spi.h"
-struct _w5500_listener;
-
-struct _w5500_conn {
+struct _w5500_tcp_conn {
/* const-after-init */
- implements_net_conn;
+ implements_net_stream_conn;
/* mutable */
bool read_open;
bool write_open;
};
-struct _w5500_listener {
+struct _w5500_tcp_listener {
/* const-after-init */
- implements_net_listener;
+ implements_net_stream_listener;
uint8_t socknum;
- struct _w5500_conn active_conn;
+ struct _w5500_tcp_conn active_conn;
/* mutable */
uint16_t port;
@@ -43,7 +41,7 @@ struct w5500 {
/* mutable */
uint16_t next_local_port;
- struct _w5500_listener listeners[8];
+ struct _w5500_tcp_listener listeners[8];
cr_sema_t intr;
};
@@ -91,7 +89,7 @@ struct w5500_netcfg {
*/
void w5500_netcfg(struct w5500 *self, struct w5500_netcfg cfg);
-implements_net_listener *w5500_listen(struct w5500 *self, uint8_t socknum,
- uint16_t port);
+implements_net_stream_listener *w5500_listen(struct w5500 *self, uint8_t socknum,
+ uint16_t port);
#endif /* _HW_W5500_H_ */
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c
index c6df8f5..8ecc56c 100644
--- a/cmd/sbc_harness/main.c
+++ b/cmd/sbc_harness/main.c
@@ -7,9 +7,11 @@
#include <string.h> /* for strlen() */
#include <stdio.h> /* for printf() */
#include "pico/stdlib.h"
+#include "hardware/flash.h"
#include <libcr/coroutine.h>
#include <libusb/usb_common.h>
+#include <libmisc/hash.h>
#include "hw/rp2040_hwspi.h"
#include "hw/w5500.h"
@@ -32,9 +34,23 @@ COROUTINE hello_world_cr(void *_chan) {
}
int main() {
- /* initialization */
+ /* initialization *****************************************************/
stdio_uart_init();
+ /* NOR flash chips have a (bog-?)standard "RUID" "Read Unique
+ * ID" instruction; use our flash chip's unique ID as the
+ * basis for our serial numbers. */
+ uint64_t flash_id64;
+ static_assert(sizeof(flash_id64) == FLASH_UNIQUE_ID_SIZE_BYTES);
+ flash_get_unique_id((uint8_t *)&flash_id64);
+ uint32_t flash_id32 = hash(&flash_id64, sizeof(flash_id64));
+ static_assert(sizeof(flash_id32) == sizeof(hash(NULL, 0)));
+ uint8_t flash_id24[3] = {
+ (uint8_t)((flash_id32 >> 16) & 0xFF),
+ (uint8_t)((flash_id32 >> 8) & 0xFF),
+ (uint8_t)((flash_id32 >> 0) & 0xFF),
+ };
+
struct rp2040_hwspi dev_spi;
struct w5500 dev_w5500;
rp2040_hwspi_init(&dev_spi, "W5500", RP2040_HWSPI_0,
@@ -47,18 +63,24 @@ int main() {
w5500_init(&dev_w5500, "W5500", &dev_spi,
21, /* PIN_INTR */
20, /* PIN_RESET */
- ((struct net_eth_addr){{0xDE,0xAD,0xBE,0xEF,0x01,0x02}}));
+ ((struct net_eth_addr){{
+ /* vendor ID: "Wiznet" */
+ 0x00, 0x08, 0xDC,
+ /* serial number */
+ flash_id24[0], flash_id24[1], flash_id24[2],
+ }}));
usb_common_earlyinit();
usb_keyboard_init();
usb_common_lateinit();
- /* set up coroutines */
+ /* set up coroutines **************************************************/
coroutine_add(usb_common_cr, NULL);
usb_keyboard_rpc_t keyboard_chan = {0};
coroutine_add(usb_keyboard_cr, &keyboard_chan);
//coroutine_add(hello_world_cr, &keyboard_chan);
+ //coroutine_add(dhcp_client_cr, NULL);
- /* Event loop. */
+ /* event loop *********************************************************/
coroutine_main();
}