Files
Nicholas Wiersma 4b831af52b w5500: initial version the driver (#788)
Thank you, @nrwiersma for working on this and @soypat for review. Now merging.
2025-11-12 09:00:21 +01:00

249 lines
5.3 KiB
Go

// Package w5500 implements a driver for the W5500 Ethernet controller.
//
// The driver supports basic network functionality including TCP and UDP sockets.
// It currently does not use the IRQ or RST pins.
//
// Datasheet: https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf
// Product Page: https://wiznet.io/products/ethernet-chips/w5500
package w5500
import (
"errors"
"net"
"net/netip"
"sync"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/netdev"
)
var _ netdev.Netdever = &Device{}
// Resolver is a function that resolves a hostname to an IP address.
type Resolver func(host string) (netip.Addr, error)
// Device is a driver for the W5500 Ethernet controller.
type Device struct {
maxSockets int
maxSockSize int
mu sync.Mutex
bus drivers.SPI
cs pin.OutputFunc
dns Resolver
sockets []*socket
laddr netip.Addr
cmdBuf [3]byte
}
// New returns a new w5500 driver.
func New(bus drivers.SPI, csPin pin.Output) *Device {
return &Device{
bus: bus,
cs: csPin.Set,
}
}
// Config is the configuration for the device.
//
// The SPI bus must be fully configured.
type Config struct {
DNS Resolver
MAC net.HardwareAddr
IP netip.Addr
SubnetMask netip.Addr
Gateway netip.Addr
// Optional, default is 8.
MaxSockets int
}
// Configure sets up the device.
//
// MAC address must be provided. The other fields are optional.
func (d *Device) Configure(cfg Config) error {
d.cs(true)
d.mu.Lock()
defer d.mu.Unlock()
d.dns = cfg.DNS
d.reset()
if err := d.setupSockets(cfg.MaxSockets); err != nil {
return errors.New("could not setup sockets: " + err.Error())
}
// Set the MAC address and IP configuration.
d.write(regMAC, 0, cfg.MAC)
d.write(regIPAddr, 0, cfg.IP.AsSlice())
d.write(regSubnetMask, 0, cfg.SubnetMask.AsSlice())
d.write(regGatewayAddr, 0, cfg.Gateway.AsSlice())
d.laddr = cfg.IP
return nil
}
func (d *Device) setupSockets(maxSockets int) error {
if maxSockets == 0 {
maxSockets = 8 // Default to 8 sockets if not specified.
}
switch maxSockets {
case 1, 2, 4, 8:
// Valid socket counts.
default:
return errors.New("invalid number of sockets, must be one of 1, 2, 4, or 8")
}
socks := make([]*socket, maxSockets)
for i := range socks {
socks[i] = &socket{
sockn: uint8(i),
}
}
d.maxSockets = maxSockets
d.maxSockSize = 16 * 1024 / maxSockets
d.sockets = socks
// Set the RX and TX buffer sizes for each socket.
for i := 0; i < 8; i++ {
size := byte(d.maxSockSize >> 10)
if i >= maxSockets {
size = 0
}
d.writeByte(sockRXBUFSize, sockAddr(uint8(i)), size)
d.writeByte(sockTXBUFSize, sockAddr(uint8(i)), size)
}
mask := byte(0b11111111)
switch maxSockets {
case 1:
mask = 0b00000001
case 2:
mask = 0b00000011
case 4:
mask = 0b00001111
}
d.writeByte(regSockIntMask, 0, mask)
d.writeByte(regIntMask, 0, 0)
return nil
}
// Reset performs a soft reset.
func (d *Device) Reset() {
d.mu.Lock()
defer d.mu.Unlock()
d.reset()
}
func (d *Device) reset() {
// RST is bit 7 of regMode.
d.writeByte(regMode, 0, 0x80)
}
// GetHardwareAddr returns the hardware address of the device.
func (d *Device) GetHardwareAddr() (net.HardwareAddr, error) {
d.mu.Lock()
defer d.mu.Unlock()
mac := make([]byte, 6)
d.read(regMAC, 0, mac)
return mac, nil
}
// Addr returns the IP address of the device.
func (d *Device) Addr() (netip.Addr, error) {
d.mu.Lock()
defer d.mu.Unlock()
var ip [4]byte
d.read(regIPAddr, 0, ip[:])
return netip.AddrFrom4(ip), nil
}
// SetAddr sets the IP address of the device.
//
// The IP address must be a valid IPv4 address.
func (d *Device) SetAddr(ip netip.Addr) error {
if err := d.setAddress(regIPAddr, ip); err != nil {
return errors.New("could not set IP address: " + err.Error())
}
d.mu.Lock()
defer d.mu.Unlock()
d.laddr = ip
return nil
}
// SetSubnetMask sets the subnet mask of the device.
//
// The subnet mask must be a valid IPv4 address.
// It is not checked if the subnet mask is valid for the device's IP address.
func (d *Device) SetSubnetMask(mask netip.Addr) error {
return d.setAddress(regSubnetMask, mask)
}
// SetGateway sets the gateway address of the device.
//
// The gateway must be a valid IPv4 address.
// It is not checked if the gateway is in the same subnet as the device.
func (d *Device) SetGateway(gateway netip.Addr) error {
return d.setAddress(regGatewayAddr, gateway)
}
func (d *Device) setAddress(addr uint16, ip netip.Addr) error {
if !ip.IsValid() || !ip.Is4() {
return errors.New("invalid IP address: " + ip.String())
}
d.mu.Lock()
defer d.mu.Unlock()
d.write(addr, 0, ip.AsSlice())
return nil
}
// LinkStatus is the link status of the device.
type LinkStatus = uint8
// LinkStatus values.
const (
LinkStatusDown LinkStatus = iota
LinkStatusUp
)
// LinkStatus returns the current link status of the device.
func (d *Device) LinkStatus() LinkStatus {
d.mu.Lock()
defer d.mu.Unlock()
return d.readByte(regPHYCfg, 0) & 0b00000001
}
// LinkInfo returns the current link information of the device.
func (d *Device) LinkInfo() string {
d.mu.Lock()
defer d.mu.Unlock()
linkInfo := d.readByte(regPHYCfg, 0) & 0b00000110
speed := "10Mbps"
if linkInfo&0b00000010 != 0 {
speed = "100Mbps"
}
duplex := "Half Duplex"
if linkInfo&0b00000100 != 0 {
duplex = "Full Duplex"
}
return speed + " " + duplex
}