summaryrefslogtreecommitdiff
path: root/libhw/w5500.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhw/w5500.c')
-rw-r--r--libhw/w5500.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/libhw/w5500.c b/libhw/w5500.c
index 5678ffd..79fc10e 100644
--- a/libhw/w5500.c
+++ b/libhw/w5500.c
@@ -67,6 +67,8 @@
* SPDX-License-Identifier: MIT
*/
+#include <stdio.h>
+
/* TODO: Write a <libhw/generic/gpio.h> to avoid w5500.c being
* pico-sdk-specific. */
#include <hardware/gpio.h> /* pico-sdk:hardware_gpio */
@@ -273,12 +275,6 @@ static inline void w5500_socket_close(struct _w5500_socket *socket) {
/* Wait for it to transition to STATE_CLOSED. */
while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_CLOSED)
cr_yield();
-
- /* Update our MCU-side bookkeeping. */
- socket->mode = W5500_MODE_NONE;
- socket->port = 0;
- socket->read_deadline_ns = 0;
- socket->read_open = socket->write_open = false;
}
#define ASSERT_SELF(_iface, _mode) \
@@ -339,6 +335,15 @@ void _w5500_init(struct w5500 *chip,
gpio_set_dir(chip->pin_reset, GPIO_OUT);
w5500_hard_reset(chip);
+ /* Validate that SPI works correctly. */
+ for (uint16_t a = 0; a < 0x100; a++) {
+ w5500ll_write_sock_reg(chip->spidev, 0, mode, a);
+ uint8_t b = w5500ll_read_sock_reg(chip->spidev, 0, mode);
+ if (b != a)
+ printf("SPI to W5500 does not appear to be functional: wrote:%d != read:%d\n", a, b);
+ }
+ w5500ll_write_sock_reg(chip->spidev, 0, mode, 0);
+
/* Finally, wire in the interrupt handler. */
bool saved = cr_save_and_disable_interrupts();
for (size_t i = 0; i < ARRAY_LEN(w5500_chips); i++) {
@@ -506,6 +511,7 @@ implements_net_packet_conn *w5500_if_udp_conn(implements_net_iface *_chip, uint1
struct _w5500_socket *socket = w5500_alloc_socket(chip);
if (!socket)
return NULL;
+ uint8_t socknum = socket->socknum;
if (!local_port)
local_port = w5500_alloc_local_port(chip);
@@ -515,6 +521,14 @@ implements_net_packet_conn *w5500_if_udp_conn(implements_net_iface *_chip, uint1
socket->port = local_port;
socket->read_deadline_ns = 0;
+ /* Mimics socket.c:socket(). */
+ w5500_socket_close(socket);
+ w5500ll_write_sock_reg(chip->spidev, socknum, mode, SOCKMODE_UDP);
+ w5500ll_write_sock_reg(chip->spidev, socknum, local_port, uint16be_marshal(socket->port));
+ w5500_socket_cmd(socket, CMD_OPEN);
+ while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_UDP)
+ cr_yield();
+
return &socket->implements_net_packet_conn;
}
@@ -627,7 +641,7 @@ static void w5500_tcp_set_read_deadline(implements_net_stream_conn *_socket, uin
static void w5500_tcp_alarm_handler(void *_arg) {
struct _w5500_socket *socket = _arg;
- cr_sema_signal(&socket->read_sema);
+ cr_sema_signal_from_intrhandler(&socket->read_sema);
}
static ssize_t w5500_tcp_read(implements_net_stream_conn *_socket, void *buf, size_t count) {
@@ -649,7 +663,7 @@ static ssize_t w5500_tcp_read(implements_net_stream_conn *_socket, void *buf, si
VCALL(bootclock, del_trigger, &trigger);
return -NET_ECLOSED;
}
- if (socket->read_deadline_ns && socket->read_deadline_ns >= VCALL(bootclock, get_time_ns)) {
+ if (socket->read_deadline_ns && socket->read_deadline_ns <= VCALL(bootclock, get_time_ns)) {
VCALL(bootclock, del_trigger, &trigger);
return -NET_ETIMEDOUT;
}
@@ -726,7 +740,7 @@ static ssize_t w5500_udp_sendto(implements_net_packet_conn *_socket, void *buf,
assert(count);
uint16_t bufsize = ((uint16_t)w5500ll_read_sock_reg(chip->spidev, socknum, tx_buf_size))*1024;
- if (count < bufsize)
+ if (count > bufsize)
return -NET_EMSGSIZE;
for (;;) {
@@ -763,7 +777,7 @@ static void w5500_udp_set_read_deadline(implements_net_packet_conn *_socket, uin
static void w5500_udp_alarm_handler(void *_arg) {
struct _w5500_socket *socket = _arg;
- cr_sema_signal(&socket->read_sema);
+ cr_sema_signal_from_intrhandler(&socket->read_sema);
}
static ssize_t w5500_udp_recvfrom(implements_net_packet_conn *_socket, void *buf, size_t count,
@@ -782,7 +796,7 @@ static ssize_t w5500_udp_recvfrom(implements_net_packet_conn *_socket, void *buf
/* Wait until there is data to read. */
uint16_t avail = 0;
for (;;) {
- if (socket->read_deadline_ns && socket->read_deadline_ns >= VCALL(bootclock, get_time_ns)) {
+ if (socket->read_deadline_ns && socket->read_deadline_ns <= VCALL(bootclock, get_time_ns)) {
VCALL(bootclock, del_trigger, &trigger);
return -NET_ETIMEDOUT;
}