diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-17 22:33:58 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-17 22:33:58 -0600 |
commit | fcc4852960d3f92b3aa55cc98e627ae8e648d625 (patch) | |
tree | 7b66efc17f3febd9be60adeee1a2e8443919b5c4 /cmd/sbc_harness/hw | |
parent | f132dab76a07473d41e14f5f4fb1857a3229ec6a (diff) |
wip w5500
Diffstat (limited to 'cmd/sbc_harness/hw')
-rw-r--r-- | cmd/sbc_harness/hw/w5500.c | 196 | ||||
-rw-r--r-- | cmd/sbc_harness/hw/w5500.h | 20 |
2 files changed, 134 insertions, 82 deletions
diff --git a/cmd/sbc_harness/hw/w5500.c b/cmd/sbc_harness/hw/w5500.c index 8e3dab0..b6d2b33 100644 --- a/cmd/sbc_harness/hw/w5500.c +++ b/cmd/sbc_harness/hw/w5500.c @@ -57,6 +57,8 @@ # define CONFIG_W5500_LOCAL_PORT_MAX 60999 #endif +#define UNUSED(name) + /* Low-level protocol built on SPI frames. ***********************************/ /* A u8 control byte has 3 parts: block-ID, R/W, and @@ -325,16 +327,16 @@ static_assert(sizeof(struct w5500_block_sock_reg) == 0x30); sizeof(lval)); \ } while (0) -#define REGREAD_COMMON(spidev, field, typ) ({ \ - typ val; \ - assert(sizeof(val) == sizeof(((struct w5500_block_sock_reg){}).field)); \ - w5500_spiframe_read(spidev, \ - offsetof(struct w5500_block_sock_reg, field), \ - CTL_BLOCK_COMMON, \ - &(val), \ - sizeof(val)); \ - val; \ - }) +#define REGREAD_COMMON(spidev, field, typ) ({ \ + typ val; \ + assert(sizeof(val) == sizeof(((struct w5500_block_sock_reg){}).field)); \ + w5500_spiframe_read(spidev, \ + offsetof(struct w5500_block_sock_reg, field), \ + CTL_BLOCK_COMMON, \ + &(val), \ + sizeof(val)); \ + val; \ + }) #define REGWRITE_SOCK(spidev, socknum, field, val) do { \ assert(sizeof(val) == sizeof(((struct w5500_block_sock_reg){}).field)); \ @@ -346,16 +348,16 @@ static_assert(sizeof(struct w5500_block_sock_reg) == 0x30); sizeof(lval)); \ } while (0) -#define REGREAD_SOCK(spidev, socknum, field, typ) ({ \ - typ val; \ - assert(sizeof(val) == sizeof(((struct w5500_block_sock_reg){}).field)); \ - w5500_spiframe_read(spidev, \ - offsetof(struct w5500_block_sock_reg, field), \ - CTL_BLOCK_SOCK(socknum, REG), \ - &(val), \ - sizeof(val)); \ - val; \ - }) +#define REGREAD_SOCK(spidev, socknum, field, typ) ({ \ + typ val; \ + assert(sizeof(val) == sizeof(((struct w5500_block_sock_reg){}).field)); \ + w5500_spiframe_read(spidev, \ + offsetof(struct w5500_block_sock_reg, field), \ + CTL_BLOCK_SOCK(socknum, REG), \ + &(val), \ + sizeof(val)); \ + val; \ + }) /* init() *********************************************************************/ @@ -374,42 +376,78 @@ static struct net_conn_vtable w5500_conn_vtable = { .close = w5500_close, }; -uint16_t w5500_get_local_port(struct w5500 *self) { - uint16_t ret = self->_next_local_port++; - if (self->_next_local_port > CONFIG_W5500_LOCAL_PORT_MAX) - self->_next_local_port = CONFIG_W5500_LOCAL_PORT_MIN; +static uint16_t w5500_get_local_port(struct w5500 *self) { + uint16_t ret = self->next_local_port++; + if (self->next_local_port > CONFIG_W5500_LOCAL_PORT_MAX) + self->next_local_port = CONFIG_W5500_LOCAL_PORT_MIN; return ret; } +static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) { + assert(listener); + assert(listener->socknum < 8); + + struct _w5500_listener *sock0 = &listener[-listener->socknum]; + assert(sock0); + struct w5500 *chip = + ((void *)sock0) - offsetof(struct w5500, listeners); + assert(chip); + return chip; +} + +static struct _w5500_listener *w5500_conn_listener(struct _w5500_conn *conn) { + assert(conn); + + struct _w5500_listener *list = + ((void *)conn) - offsetof(struct _w5500_listener, active_conn); + return list; +} + +static void w5500_intrhandler(uint UNUSED(gpio), uint32_t UNUSED(event_mask)) { + /* TODO */ +} + void _w5500_init(struct w5500 *chip, struct spi* spi, uint pin_intr, uint pin_reset, struct net_eth_addr addr) { - chip->spidev = spi; - chip->pin_reset = pin_reset; + assert(chip); + assert(spi); + + /* Initialize the data structures. */ + *chip = (struct w5500){ + /* const-after-init */ + .spidev = spi, + .pin_reset = pin_reset, + /* mutable */ + .next_local_port = CONFIG_W5500_LOCAL_PORT_MIN, + }; for (uint8_t i = 0; i < 8; i++) { - chip->_listeners[i].vtable = &w5500_listener_vtable; - chip->_listeners[i].chip = chip; - chip->_listeners[i].socknum = i; - chip->_listeners[i].active_conn.vtable = &w5500_conn_vtable; - chip->_listeners[i].active_conn.parent_listener = &chip->_listeners[i]; + chip->listeners[i] = (struct _w5500_listener){ + /* const-after-init */ + .vtable = &w5500_listener_vtable, + .socknum = i, + .active_conn = { + .vtable = &w5500_conn_vtable, + }, + /* mutable */ + .port = 0, + }; } - chip->_next_local_port = CONFIG_W5500_LOCAL_PORT_MIN; - gpio_set_irq_enabled_with_callback(pin_intr, GPIO_IRQ_EDGE_FALL, true, TODO_cbfn); + /* Initialize the hardware. */ + gpio_set_irq_enabled_with_callback(pin_intr, GPIO_IRQ_EDGE_FALL, true, w5500_intrhandler); gpio_set_dir(chip->pin_reset, GPIO_OUT); - - w5500_reset(chip); - - REGWRITE_COMMON(spi, eth_addr, addr); + w5500_reset(chip, addr); } - -void w5500_reset(struct w5500 *chip) { +void w5500_reset(struct w5500 *chip, struct net_eth_addr addr) { /* TODO: Replace blocking sleep_ms() with something libcr-friendly. */ gpio_put(chip->pin_reset, 0); sleep_ms(1); /* minimum of 500us */ gpio_put(chip->pin_reset, 1); sleep_ms(2); /* minimum of 1ms */ + + REGWRITE_COMMON(chip->spidev, eth_addr, addr); } void w5500_netcfg(struct w5500 *chip, struct w5500_netcfg cfg) { @@ -420,37 +458,54 @@ void w5500_netcfg(struct w5500 *chip, struct w5500_netcfg cfg) { /* listen() *******************************************************************/ -implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum, uint16_t port) { +implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum, + uint16_t port) { assert(chip); assert(socknum < 8); assert(port); - w5500_close(&chip->_listeners[socknum].active_conn, true, true); - REGWRITE_SOCK(chip->spidev, socknum, mode, MODE_TCP); - REGWRITE_SOCK(chip->spidev, socknum, local_port, ((uint8_t[2]){port>>8, port})); - REGWRITE_SOCK(chip->spidev, socknum, command, CMD_OPEN); - while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) - cr_yield(); - while (REGREAD_SOCK(chip->spidev, socknum, state, uint8_t) != STATE_TCP_INIT) - cr_yield(); + assert(chip->listeners[socknum].port == 0); + chip->listeners[socknum].port = port; - return &chip->_listeners[socknum]; + return &chip->listeners[socknum]; } /* accept() *******************************************************************/ -#define ASSERT_LISTENER() \ - struct _w5500_listener *self = VCALL_SELF(struct _w5500_listener, implements_net_listener, _self); \ - assert(self); \ - \ - struct w5500 *chip = self->chip; \ - uint8_t socknum = self->socknum; \ - assert(chip); \ - assert(socknum < 8) +#define ASSERT_LISTENER() \ + struct _w5500_listener *self = \ + VCALL_SELF(struct _w5500_listener, \ + implements_net_listener, _self); \ + struct w5500 *chip = w5500_listener_chip(self); \ + uint8_t socknum = self->socknum; + +static void w5500_cmd_close(struct _w5500_listener *listener) { + struct w5500 *chip = w5500_listener_chip(listener); + uint8_t socknum = listener->socknum; + + REGWRITE_SOCK(chip->spidev, socknum, command, CMD_CLOSE); + while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) + cr_yield(); + REGWRITE_SOCK(chip->spidev, socknum, interrupt, (uint8_t)0xff); + while (REGREAD_SOCK(chip->spidev, socknum, state, uint8_t) != STATE_CLOSED) + cr_yield(); +} static implements_net_conn *w5500_accept(implements_net_listener *_self) { ASSERT_LISTENER(); + /* Mimics socket.c:socket(). */ + w5500_cmd_close(self); + REGWRITE_SOCK(chip->spidev, socknum, mode, MODE_TCP); + struct { uint8_t octets[2]; } port_be = {{self->port>>8, self->port}}; + REGWRITE_SOCK(chip->spidev, socknum, local_port, port_be); + REGWRITE_SOCK(chip->spidev, socknum, command, CMD_OPEN); + while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) + cr_yield(); + while (REGREAD_SOCK(chip->spidev, socknum, state, uint8_t) != STATE_TCP_INIT) + cr_yield(); + + /* Mimics socket.c:listen(). */ REGWRITE_SOCK(chip->spidev, socknum, command, CMD_LISTEN); while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) cr_yield(); @@ -469,14 +524,12 @@ static implements_net_conn *w5500_accept(implements_net_listener *_self) { /* write() ********************************************************************/ -#define ASSERT_CONN() \ - struct _w5500_conn *self = VCALL_SELF(struct _w5500_conn, implements_net_conn, _self); \ - assert(self); \ - \ - struct w5500 *chip = self->parent_listener->chip; \ - uint8_t socknum = self->parent_listener->socknum; \ - assert(chip); \ - assert(socknum < 8) +#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); \ + uint8_t socknum = listener->socknum; static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) { ASSERT_CONN(); @@ -486,15 +539,10 @@ static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) // TODO } -static int w5500_close(implements_net_conn *_self, bool rd, bool wr) { +static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) { ASSERT_CONN(); + assert(buf); + assert(count); - REGWRITE_SOCK(chip->spidev, socknum, command, CMD_CLOSE); - while (REGREAD_SOCK(chip->spidev, socknum, command, uint8_t) != 0x00) - cr_yield(); - REGWRITE_SOCK(chip->spidev, socknum, interrupt, (uint8_t)0xff); - while (REGREAD_SOCK(chip->spidev, socknum, state, uint8_t) != STATE_CLOSED) - cr_yield(); - - return 0; + // TODO } diff --git a/cmd/sbc_harness/hw/w5500.h b/cmd/sbc_harness/hw/w5500.h index 4ec6edd..f8a7034 100644 --- a/cmd/sbc_harness/hw/w5500.h +++ b/cmd/sbc_harness/hw/w5500.h @@ -14,25 +14,28 @@ struct _w5500_listener; struct _w5500_conn { + /* const-after-init */ implements_net_conn; - - struct _w5500_listener *parent_listener; }; struct _w5500_listener { + /* const-after-init */ implements_net_listener; - - struct w5500 *chip; uint8_t socknum; struct _w5500_conn active_conn; + + /* mutable */ + uint16_t port; }; struct w5500 { + /* const-after-init */ struct spi *spidev; uint pin_reset; - struct _w5500_listener _listeners[8]; - uint16_t _next_local_port; + /* mutable */ + uint16_t next_local_port; + struct _w5500_listener listeners[8]; }; /** @@ -61,7 +64,7 @@ void _w5500_init(struct w5500 *self, /** * TODO. */ -void w5500_reset(struct w5500 *self); +void w5500_reset(struct w5500 *self, struct net_eth_addr addr); struct w5500_netcfg { struct net_ip4_addr gateway_addr; @@ -74,6 +77,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_listener *w5500_listen(struct w5500 *self, uint8_t socknum, + uint16_t port); #endif /* _HW_W5500_H_ */ |