Compare commits

..

14 Commits

Author SHA1 Message Date
soypat 85a28fb937 delay addition of extra error types until verifiably needed 2024-02-24 23:43:12 -03:00
Patricio Whittingslow 9b74ecbc36 Delete nets/example_test.go 2024-01-10 09:11:23 -03:00
Patricio Whittingslow 1690c2c2d8 Delete nets/nets.go
nets/nets.go was replaced by netif/netif.go
2024-01-10 09:11:09 -03:00
soypat cdc76f3ea7 modify netif.Resolver to use net.DefaultResolver method set 2024-01-07 15:42:43 -03:00
soypat 68ccd70c56 rename file 2024-01-07 15:28:48 -03:00
soypat f657269a66 rename package: nets -> netif 2024-01-07 15:26:55 -03:00
soypat 6913eaf2b9 add examples 2023-12-20 10:26:06 -03:00
soypat d4705e501d rethink netdev name again 2023-12-19 23:12:46 -03:00
soypat 728bdbba5b apply some of @scottfeldman's suggestions 2023-12-19 23:07:20 -03:00
soypat b4f43b4d21 remove old comment 2023-12-18 16:02:55 -08:00
soypat 570e3d2b71 change EthLinkPoller name 2023-12-18 16:01:59 -08:00
soypat 7e45551ff5 add more methods to Link interface 2023-12-18 16:01:17 -08:00
soypat 60cdb7fd50 add EthLinkPoller; 2023-12-18 15:56:35 -08:00
soypat 731362a0cf nets: new package with netdev redesign ideas 2023-12-18 15:32:49 -08:00
38 changed files with 452 additions and 704 deletions
-83
View File
@@ -1,86 +1,3 @@
0.27.0
---
- **core**
- prepare for CGo changes in TinyGo
- **new devices**
- **adafruit4650**
- support for Adafruit 4650 feather OLED
- **net**
- new networking support based on tinygo net package
- **pixel**
- add package for efficiently working with raw pixel buffers
- **rotary**
- Adding driver for rotary encoder support
- **seesaw**
- Adding support for Adafruit Seesaw platform
- **sgp30**
- add SGP30 air quality sensor
- **sk6812**
- added support for SK6812 to WS2812 device (#610)
- **enhancements**
- **epd2in13**
- add Sleep method like other displays
- unify rotation configuration with other displays
- use better black/white approximation
- **ili9341**
- add DrawBitmap method
- **lora/lorawan**
- LoRa WAN US915 Support
- LoRa WAN add setter functions
- refactor shared functionality for channels/regions
- **mcp2515**
- Add more line speeds to mcp2515.go (#626)
- **rtl8720dn**
- use drivers package version as the driver version
- **ssd1306**
- improvements needed for Thumby SPI display
- **st7735**
- make the display generic over RGB565 and RGB444
- **st7789**
- add DrawBitmap method
- make the display generic over RGB565 and RGB444
- **wifinina**
- add ResetIsHigh cfg switch for MKR 1010 (copied from #561)
- maintenence. Also see PR #4085 in the main TinyGo repo
- use drivers package version as the driver version
- **bugfixes**
- **adxl345**
- Use int16 for ADXL345 readings (#656)
- **at24cx**
- fixed the description of the device struct
- **rtl8720dn**
- allow connecting to open wifi access points
- fix check for bad Wifi connect
- **sh1106**
- fix I2C interface and add smoketest
- fixed the description of the device struct
- **wifinina**
- add 'unknown failure' reason code for AP connect
- fix concurrency issues with multiple sockets
- fix wifinina UDP send
- **examples**
- **ds3231**
- fix the description in the example
- **lorawan**
- add missing functions for simulated interface
- modify atcmd and basic demo to support choosing any one of the supported regions at compile time by using ldflags
- **net**
- all networking examples now using netdev and netlink.
- **build**
- **all**
- fix broken testrunner
- migrated legacy I2C
- add natiu package for tests
- **smoketest**
- add stack-size param for net tests.
- allow stack-size flag as it is needed for net examples
0.26.0
---
- **core**
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2024 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
+1 -1
View File
@@ -3,7 +3,7 @@
[![PkgGoDev](https://pkg.go.dev/badge/tinygo.org/x/drivers)](https://pkg.go.dev/tinygo.org/x/drivers) [![Build](https://github.com/tinygo-org/drivers/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/drivers/actions/workflows/build.yml)
This package provides a collection of 102 different hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
This package provides a collection of 101 different hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
For the complete list, please see:
https://tinygo.org/docs/reference/devices/
+7 -7
View File
@@ -95,16 +95,16 @@ func (d *Device) Restart() {
func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
rx, ry, rz := d.ReadRawAcceleration()
x = int32(d.dataFormat.convertToIS(rx))
y = int32(d.dataFormat.convertToIS(ry))
z = int32(d.dataFormat.convertToIS(rz))
x = d.dataFormat.convertToIS(rx)
y = d.dataFormat.convertToIS(ry)
z = d.dataFormat.convertToIS(rz)
return
}
// ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis
// from the adxl345.
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
data := []byte{0, 0, 0, 0, 0, 0}
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data)
@@ -140,7 +140,7 @@ func (d *Device) SetRange(sensorRange Range) bool {
}
// convertToIS adjusts the raw values from the adxl345 with the range configuration
func (d *dataFormat) convertToIS(rawValue int16) int16 {
func (d *dataFormat) convertToIS(rawValue int32) int32 {
switch d.sensorRange {
case RANGE_2G:
return rawValue * 4 // rawValue * 2 * 1000 / 512
@@ -190,6 +190,6 @@ func (b *bwRate) toByte() (bits uint8) {
}
// readInt converts two bytes to int16
func readIntLE(msb byte, lsb byte) int16 {
return int16(uint16(msb) | uint16(lsb)<<8)
func readIntLE(msb byte, lsb byte) int32 {
return int32(uint16(msb) | uint16(lsb)<<8)
}
-34
View File
@@ -1,34 +0,0 @@
package encoders
type QuadratureDevice struct {
cfg QuadratureConfig
impl quadratureImpl
}
type QuadratureConfig struct {
Precision int
}
type quadratureImpl interface {
configure(cfg QuadratureConfig) error
readValue() int
writeValue(int)
}
func (enc *QuadratureDevice) Configure(cfg QuadratureConfig) error {
if cfg.Precision < 1 {
cfg.Precision = 4
}
enc.cfg = cfg
return enc.impl.configure(cfg)
}
// Position returns the stored int value for the encoder
func (enc *QuadratureDevice) Position() int {
return enc.impl.readValue() / enc.cfg.Precision
}
// SetPosition overwrites the currently stored value with the specified int value
func (enc *QuadratureDevice) SetPosition(v int) {
enc.impl.writeValue(v * enc.cfg.Precision)
}
-69
View File
@@ -1,69 +0,0 @@
//go:build tinygo && (rp2040 || stm32 || k210 || esp32c3 || nrf || (avr && (atmega328p || atmega328pb)))
// Implementation based on:
// https://gist.github.com/aykevl/3fc1683ed77bb0a9c07559dfe857304a
// Note: build constraints in this file list targets that define machine.PinToggle.
// If this is supported for additional targets in the future, they can be added above.
package encoders
import (
"machine"
"runtime/volatile"
)
var (
states = []int8{0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}
)
// NewQuadratureViaInterrupt returns a rotary encoder device that uses GPIO
// interrupts and a lookup table to keep track of quadrature state changes.
//
// This constructur is only available for TinyGo targets for which machine.PinToggle
// is defined as a valid interrupt type.
func NewQuadratureViaInterrupt(pinA, pinB machine.Pin) *QuadratureDevice {
return &QuadratureDevice{impl: &quadInterruptImpl{pinA: pinA, pinB: pinB, oldAB: 0b00000011}}
}
type quadInterruptImpl struct {
pinA machine.Pin
pinB machine.Pin
// precision int
oldAB int
value volatile.Register32
}
func (enc *quadInterruptImpl) configure(cfg QuadratureConfig) error {
enc.pinA.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
enc.pinA.SetInterrupt(machine.PinToggle, enc.interrupt)
enc.pinB.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
enc.pinB.SetInterrupt(machine.PinToggle, enc.interrupt)
return nil
}
func (enc *quadInterruptImpl) interrupt(pin machine.Pin) {
aHigh, bHigh := enc.pinA.Get(), enc.pinB.Get()
enc.oldAB <<= 2
if aHigh {
enc.oldAB |= 1 << 1
}
if bHigh {
enc.oldAB |= 1
}
enc.writeValue(enc.readValue() + int(states[enc.oldAB&0x0f]))
}
// readValue gets the value using volatile operations and returns it as an int
func (enc *quadInterruptImpl) readValue() int {
return int(enc.value.Get())
}
// writeValue set the value to the specified int using volatile operations
func (enc *quadInterruptImpl) writeValue(v int) {
enc.value.Set(uint32(v))
}
+2 -2
View File
@@ -218,8 +218,8 @@ func (d *Device) Listen(sockfd int, backlog int) error {
return nil
}
func (d *Device) Accept(sockfd int) (int, netip.AddrPort, error) {
return -1, netip.AddrPort{}, netdev.ErrNotSupported
func (d *Device) Accept(sockfd int, ip netip.AddrPort) (int, error) {
return -1, netdev.ErrNotSupported
}
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
@@ -1,28 +0,0 @@
//go:build macropad_rp2040
package main
import (
"machine"
"tinygo.org/x/drivers/encoders"
)
var (
enc = encoders.NewQuadratureViaInterrupt(machine.ROT_A, machine.ROT_B)
)
func main() {
enc.Configure(encoders.QuadratureConfig{
Precision: 4,
})
for oldValue := 0; ; {
if newValue := enc.Position(); newValue != oldValue {
println("value: ", newValue)
oldValue = newValue
}
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal || challenger_rp2040
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal || challenger_rp2040
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -3,7 +3,7 @@
// It creates a UDP connection to request the current time and parse the
// response from a NTP server. The system time is set to NTP time.
//go:build ninafw || wioterminal || challenger_rp2040
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
-30
View File
@@ -1,30 +0,0 @@
//go:build ninafw || wioterminal
package main
import (
"log"
"time"
"tinygo.org/x/drivers/netlink"
"tinygo.org/x/drivers/netlink/probe"
)
var (
ssid string
pass string
)
func init() {
time.Sleep(2 * time.Second)
link, _ := probe.Probe()
err := link.NetConnect(&netlink.ConnectParams{
Ssid: ssid,
Passphrase: pass,
})
if err != nil {
log.Fatal(err)
}
}
-120
View File
@@ -1,120 +0,0 @@
// This example is the classic snake network test. The snake is feed a steady
// diet of pkts and the pkts work themselves thru the snake segments and exit
// the tail. Each snake segment is a TCP socket connection to a server. The
// server echos pkts received back to the snake, and serves each segment on a
// different port. (See server/main.go for server).
//
// snake | server
// |
// head ----->---|-->--+
// seg a | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg b | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg c | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// ... | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg n | |
// tail -------<-|--<--+
// |
// The snake segments are linked by channels and each segment is run as a go
// func. This forces segments to connect and run concurrently, which is a good
// test of the underlying driver's ability to handle concurrent connections.
//go:build ninafw || wioterminal
package main
import (
_ "embed"
"fmt"
"log"
"net"
"strings"
"time"
)
//go:embed main.go
var code string
var (
server string = "10.0.0.100:8080"
)
func segment(in chan []byte, out chan []byte) {
var buf [512]byte
for {
c, err := net.Dial("tcp", server)
for ; err != nil; c, err = net.Dial("tcp", server) {
println(err.Error())
time.Sleep(5 * time.Second)
}
for {
select {
case msg := <-in:
_, err := c.Write(msg)
if err != nil {
log.Fatal(err.Error())
}
time.Sleep(100 * time.Millisecond)
n, err := c.Read(buf[:])
if err != nil {
log.Fatal(err.Error())
}
out <- buf[:n]
}
}
}
}
func feedit(head chan []byte) {
for i := 0; i < 100; i++ {
head <- []byte(fmt.Sprintf("\n---%d---\n", i))
for _, line := range strings.Split(code, "\n") {
if len(line) == 0 {
line = " "
}
head <- []byte(line)
}
}
}
var head = make(chan []byte)
var a = make(chan []byte)
var b = make(chan []byte)
var c = make(chan []byte)
var d = make(chan []byte)
var e = make(chan []byte)
var f = make(chan []byte)
var tail = make(chan []byte)
func main() {
// The snake
go segment(head, a)
go segment(a, b)
go segment(b, c)
go segment(c, d)
go segment(d, e)
go segment(e, f)
go segment(f, tail)
go feedit(head)
for {
select {
case msg := <-tail:
println(string(msg))
}
}
}
-34
View File
@@ -1,34 +0,0 @@
package main
import (
"io"
"log"
"net"
)
func main() {
// Listen for connections
l, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err.Error())
}
defer l.Close()
println("Listening on port", ":8080")
for {
// Wait for a connection
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
println("Accepted connection from", conn.RemoteAddr().String())
// Service the new connection in a goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently
go func(c net.Conn) {
// Echo all incoming data
io.Copy(c, c)
// Shut down the connection
c.Close()
}(conn)
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
//
// nc -lk 8080
//go:build ninafw || wioterminal || challenger_rp2040
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -5,7 +5,7 @@
//
// nc -lk 8080
//go:build ninafw || wioterminal || challenger_rp2040 || pico
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040 || pico
package main
+2 -5
View File
@@ -7,7 +7,7 @@
//
// $ nc 10.0.0.2 8080 <file >copy ; cmp file copy
//go:build ninafw || wioterminal
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
@@ -30,18 +30,16 @@ var (
var buf [1024]byte
func echo(conn net.Conn) {
println("Client", conn.RemoteAddr(), "connected")
defer conn.Close()
_, err := io.CopyBuffer(conn, conn, buf[:])
if err != nil && err != io.EOF {
log.Fatal(err.Error())
}
println("Client", conn.RemoteAddr(), "closed")
}
func main() {
time.Sleep(2 * time.Second)
time.Sleep(time.Second)
link, _ := probe.Probe()
@@ -53,7 +51,6 @@ func main() {
log.Fatal(err)
}
println("Starting TCP server listening on", port)
l, err := net.Listen("tcp", port)
if err != nil {
log.Fatal(err.Error())
+1 -1
View File
@@ -5,7 +5,7 @@
//
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -17,7 +17,7 @@
// }
// ---------------------------------------------------------------------------
//go:build ninafw || wioterminal
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -3,7 +3,7 @@
// Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
-50
View File
@@ -1,50 +0,0 @@
// This example using the SSD1306 OLED display over SPI on the Thumby board
// A very tiny 72x40 display.
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.SPI0.Configure(machine.SPIConfig{})
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
display.Configure(ssd1306.Config{
Width: 72,
Height: 40,
ResetCol: ssd1306.ResetValue{28, 99},
ResetPage: ssd1306.ResetValue{0, 5},
})
display.ClearDisplay()
x := int16(36)
y := int16(20)
deltaX := int16(1)
deltaY := int16(1)
for {
pixel := display.GetPixel(x, y)
c := color.RGBA{255, 255, 255, 255}
if pixel {
c = color.RGBA{0, 0, 0, 255}
}
display.SetPixel(x, y, c)
display.Display()
x += deltaX
y += deltaY
if x == 0 || x == 71 {
deltaX = -deltaX
}
if y == 0 || y == 39 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
+1 -2
View File
@@ -39,7 +39,6 @@ var (
ErrNoMoreSockets = errors.New("No more sockets")
ErrClosingSocket = errors.New("Error closing socket")
ErrNotSupported = errors.New("Not supported")
ErrInvalidSocketFd = errors.New("Invalid socket fd")
)
// Duplicate of non-exported net.errTimeout
@@ -83,7 +82,7 @@ type Netdever interface {
Bind(sockfd int, ip netip.AddrPort) error
Connect(sockfd int, host string, ip netip.AddrPort) error
Listen(sockfd int, backlog int) error
Accept(sockfd int) (int, netip.AddrPort, error)
Accept(sockfd int, ip netip.AddrPort) (int, error)
Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Close(sockfd int) error
+97
View File
@@ -0,0 +1,97 @@
package netif
import (
"net"
"time"
)
func AutoProbe(timeout time.Duration) (Stack, error) {
// This function automatically gets the first available network device
// and returns a stack for it.
// It is intended to be used by the user as a convenience function.
// Will be guarded by build tags and specific for whether the device
// is a StackWifi, InterfaceEthPollWifi or InterfaceEthPoller.
return nil, nil
}
func ProbeStackWifi() StackWifi {
return nil
}
func ProbeEthPollWifi() InterfaceEthPollWifi {
return nil
}
func ProbeEthPoller() InterfaceEthPoller {
return nil
}
func StackForEthPoll(dev InterfaceEthPoller) Stack {
// Use seqs to generate a stack.
return nil
}
// OSI layer 4 enabled WIFI chip. i.e.: ESP32
func ExampleProbeStackWifi() {
dev := ProbeStackWifi()
wifiparams := WifiParams{
SSID: "myssid",
ConnectMode: ConnectModeSTA,
Passphrase: "mypassphrase",
Auth: AuthTypeWPA2,
CountryCode: "US",
}
err := StartWifiAutoconnect(dev, WifiAutoconnectParams{
WifiParams: wifiparams,
})
if err != nil {
panic(err)
}
for dev.NetFlags()&net.FlagRunning == 0 {
time.Sleep(100 * time.Millisecond)
}
UseStack(dev)
net.Dial("tcp", "192.168.1.1:33")
}
// Simplest case, OSI layer 2 enabled WIFI chip, i.e: CYW43439
func ExampleProbeEthPollWifi() {
dev := ProbeEthPollWifi()
wifiparams := WifiParams{
SSID: "myssid",
ConnectMode: ConnectModeSTA,
Passphrase: "mypassphrase",
Auth: AuthTypeWPA2,
CountryCode: "US",
}
err := StartWifiAutoconnect(dev, WifiAutoconnectParams{
WifiParams: wifiparams,
})
if err != nil {
panic(err)
}
for dev.NetFlags()&net.FlagRunning == 0 {
time.Sleep(100 * time.Millisecond)
}
stack := StackForEthPoll(dev)
UseStack(stack)
net.Dial("tcp", "192.168.1.1:33")
}
// OSI level 2 chip with wired connection, i.e. ENC28J60.
func ExampleProbeEthPoller() {
dev := ProbeEthPoller()
if dev.NetFlags()&net.FlagRunning == 0 {
panic("ethernet not connected")
}
stack := StackForEthPoll(dev)
UseStack(stack)
net.Dial("tcp", "192.168.1.1:33")
}
func ExampleAutoProbe() {
stack, err := AutoProbe(10 * time.Second)
if err != nil {
panic(err)
}
UseStack(stack)
net.Dial("tcp", "192.168.1.1:33")
}
+211
View File
@@ -0,0 +1,211 @@
package netif
import (
"context"
"errors"
"net"
"net/netip"
"time"
_ "unsafe"
)
//go:linkname UseStack net.useNetdev
func UseStack(stack Stack)
// Socket errors.
var (
ErrProtocolNotSupported = errors.New("socket protocol/type not supported")
)
// Wifi errors.
var (
ErrAuthFailure = errors.New("wifi authentication failure")
ErrAuthUnsupported = errors.New("wifi authorization type not supported")
)
const (
_AF_INET = 0x2
_SOCK_STREAM = 0x1
_SOCK_DGRAM = 0x2
_SOL_SOCKET = 0x1
_SO_KEEPALIVE = 0x9
_SOL_TCP = 0x6
_TCP_KEEPINTVL = 0x5
_IPPROTO_TCP = 0x6
_IPPROTO_UDP = 0x11
// Made up, not a real IP protocol number. This is used to create a
// TLS socket on the device, assuming the device supports mbed TLS.
_IPPROTO_TLS = 0xFE
_F_SETFL = 0x4
)
// Interface is the minimum interface that need be implemented by any network
// device driver and is based on [net.Interface].
type Interface interface {
// HardwareAddr6 returns the device's 6-byte [MAC address].
//
// [MAC address]: https://en.wikipedia.org/wiki/MAC_address
HardwareAddr6() ([6]byte, error)
// NetFlags returns the net.Flag values for the interface. It includes state of connection.
NetFlags() net.Flags
// MTU returns the maximum transmission unit size.
MTU() int
// Notify to register callback for network events. May not be supported for certain devices.
NetNotify(cb func(Event)) error
}
// InterfaceEthPoller is implemented by devices that send/receive ethernet packets.
type InterfaceEthPoller interface {
Interface
// SendEth sends an Ethernet packet
SendEth(pkt []byte) error
// RecvEthHandle sets recieve Ethernet packet callback function
RecvEthHandle(func(pkt []byte) error)
// PollOne tries to receive one Ethernet packet and returns true if one was
PollOne() (bool, error)
}
// InterfaceWifi is implemented by a interface device that has the capacity
// to connect to wifi networks.
type InterfaceWifi interface {
Interface
// Connect device to network
NetConnect(params WifiParams) error
// Disconnect device from network
NetDisconnect()
}
// InterfaceEthPollWifi is implemented by devices that connect to wifi networks
// and send/receive ethernet packets (OSI level 2).
type InterfaceEthPollWifi interface {
InterfaceWifi
InterfaceEthPoller
}
type Stack interface {
// GetHostByName returns the IP address of either a hostname or IPv4
// address in standard dot notation
// GetHostByName(name string) (netip.Addr, error)
// Addr returns IP address assigned to the interface, either by
// DHCP or statically
Addr() (netip.Addr, error)
// Berkely Sockets-like interface, Go-ified. See man page for socket(2), etc.
Socket(domain int, stype int, protocol int) (int, error)
Bind(sockfd int, ip netip.AddrPort) error
Connect(sockfd int, host string, ip netip.AddrPort) error
Listen(sockfd int, backlog int) error
Accept(sockfd int) (int, netip.AddrPort, error)
Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Close(sockfd int) error
SetSockOpt(sockfd int, level int, opt int, value interface{}) error
}
// Resolver is implemented by DNS resolvers, notably Go's [net.DefaultResolver].
type Resolver interface {
// LookupNetIP looks up host using the local resolver.
// It returns a slice of that host's IP addresses of the type specified by
// network.
// The network must be one of "ip", "ip4" or "ip6".
LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error)
}
// StackWifi is returned by `Probe` function for devices that communicate
// on the OSI level 4 (transport) layer.
type StackWifi interface {
InterfaceWifi
Stack
}
type WifiParams struct {
// Connect mode
ConnectMode ConnectMode
// SSID of Wifi AP
SSID string
// Passphrase of Wifi AP
Passphrase string
// Wifi authorization type
Auth AuthType
// Wifi country code as two-char string. E.g. "XX" for world-wide,
// "US" for USA, etc.
CountryCode string
}
type Event uint8
// Network events
const (
// The device's network connection is now UP
EventNetUp Event = iota
// The device's network connection is now DOWN
EventNetDown
)
type ConnectMode uint8
// Connect modes
const (
ConnectModeSTA = iota // Connect as Wifi station (default)
ConnectModeAP // Connect as Wifi Access Point
)
type AuthType uint8
// Wifi authorization types. Used when setting up an access point, or
// connecting to an access point
const (
AuthTypeWPA2 = iota // WPA2 authorization (default)
AuthTypeOpen // No authorization required (open)
AuthTypeWPA // WPA authorization
AuthTypeWPA2Mixed // WPA2/WPA mixed authorization
)
type WifiAutoconnectParams struct {
WifiParams
// Retries is how many attempts to connect before returning with a
// "Connect failed" error. Zero means infinite retries.
// Retries int // Probably should be implemented as a function
// Timeout duration for each connection attempt. The default zero
// value means 10sec.
ConnectTimeout time.Duration
// Watchdog ticker duration. On tick, the watchdog will check for
// downed connection or hardware fault and try to recover the
// connection. Set to zero to disable watchodog.
WatchdogTimeout time.Duration
}
func StartWifiAutoconnect(dev InterfaceWifi, cfg WifiAutoconnectParams) error {
if dev == nil {
return errors.New("nil device")
}
go func() {
// Wifi autoconnect algorithm in one place,
// no need to implement for every single netdever.
RECONNECT:
for i := 0; i < 4; i++ {
err := dev.NetConnect(cfg.WifiParams)
if err != nil {
time.Sleep(cfg.ConnectTimeout)
goto RECONNECT
}
// Once connected reset the retry counter.
i = 0
for cfg.WatchdogTimeout != 0 {
time.Sleep(cfg.WatchdogTimeout)
if dev.NetFlags()&net.FlagRunning == 0 {
goto RECONNECT
}
}
}
}()
return nil
}
-1
View File
@@ -13,7 +13,6 @@ var (
ErrConnectFailed = errors.New("Connect failed")
ErrConnectTimeout = errors.New("Connect timed out")
ErrMissingSSID = errors.New("Missing WiFi SSID")
ErrShortPassphrase = errors.New("Invalid Wifi Passphrase < 8 chars")
ErrAuthFailure = errors.New("Wifi authentication failure")
ErrAuthTypeNoGood = errors.New("Wifi authorization type not supported")
ErrConnectModeNoGood = errors.New("Connect mode not supported")
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build ninafw && !arduino_mkrwifi1010
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || matrixportal_m4
package probe
+10 -32
View File
@@ -17,7 +17,6 @@ import (
"sync"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/netdev"
"tinygo.org/x/drivers/netlink"
)
@@ -28,6 +27,7 @@ var _debug debug = debugBasic
//var _debug debug = debugBasic | debugNetdev | debugRpc
var (
version = "0.0.1"
driverName = "Realtek rtl8720dn Wifi network device driver (rtl8720dn)"
)
@@ -102,22 +102,14 @@ func (r *rtl8720dn) connectToAP() error {
return netlink.ErrMissingSSID
}
if len(r.params.Passphrase) != 0 && len(r.params.Passphrase) < 8 {
return netlink.ErrShortPassphrase
}
if debugging(debugBasic) {
fmt.Printf("Connecting to Wifi SSID '%s'...", r.params.Ssid)
}
// Start the connection process
securityType := uint32(0) // RTW_SECURITY_OPEN
if len(r.params.Passphrase) != 0 {
securityType = 0x00400004 // RTW_SECURITY_WPA2_AES_PSK
}
securityType := uint32(0x00400004)
result := r.rpc_wifi_connect(r.params.Ssid, r.params.Passphrase, securityType, -1, 0)
if result != 0 {
if result == -1 {
if debugging(debugBasic) {
fmt.Printf("FAILED\r\n")
}
@@ -142,7 +134,7 @@ func (r *rtl8720dn) showDriver() {
if debugging(debugBasic) {
fmt.Printf("\r\n")
fmt.Printf("%s\r\n\r\n", driverName)
fmt.Printf("Driver version : %s\r\n", drivers.Version)
fmt.Printf("Driver version : %s\r\n", version)
}
r.driverShown = true
}
@@ -445,12 +437,6 @@ func ipToName(ip netip.AddrPort) []byte {
return name
}
func nameToIp(name []byte) netip.AddrPort {
port := uint16(name[2])<<8 | uint16(name[3])
addr, _ := netip.AddrFromSlice(name[4:8])
return netip.AddrPortFrom(addr, port)
}
func (r *rtl8720dn) Bind(sockfd int, ip netip.AddrPort) error {
if debugging(debugNetdev) {
@@ -548,10 +534,10 @@ func (r *rtl8720dn) Listen(sockfd int, backlog int) error {
return nil
}
func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
func (r *rtl8720dn) Accept(sockfd int, ip netip.AddrPort) (int, error) {
if debugging(debugNetdev) {
fmt.Printf("[Accept] sockfd: %d\r\n", sockfd)
fmt.Printf("[Accept] sockfd: %d, peer: %s\r\n", sockfd, ip)
}
r.mu.Lock()
@@ -560,12 +546,12 @@ func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
var newSock int32
var lsock = sock(sockfd)
var socket = r.sockets[lsock]
var name = ipToName(netip.AddrPort{})
var name = ipToName(ip)
switch socket.protocol {
case netdev.IPPROTO_TCP:
default:
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
return -1, netdev.ErrProtocolNotSupported
}
for {
@@ -584,14 +570,6 @@ func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
continue
}
// Get remote peer ip:port
namelen = uint32(len(name))
result := r.rpc_lwip_getpeername(int32(newSock), name, &namelen)
if result == -1 {
return -1, netip.AddrPort{}, fmt.Errorf("Getpeername failed")
}
raddr := nameToIp(name)
// If we've already seen this socket, we can re-use
// the socket and return it. But, only if the socket
// is closed. If it's not closed, we'll just come back
@@ -604,12 +582,12 @@ func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
continue
}
// Reuse client socket
return int(newSock), raddr, nil
return int(newSock), nil
}
// Create new socket for client and return fd
r.sockets[sock(newSock)] = newSocket(socket.protocol)
return int(newSock), raddr, nil
return int(newSock), nil
}
}
-1
View File
@@ -129,7 +129,6 @@ tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ndir/ma
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/sh1106/macropad_spi
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/encoders/quadrature-interrupt
# network examples (espat)
tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
# network examples (wifinina)
+4 -26
View File
@@ -13,8 +13,6 @@ import (
"tinygo.org/x/drivers/internal/legacy"
)
type ResetValue [2]byte
// Device wraps I2C or SPI connection.
type Device struct {
bus Buser
@@ -24,8 +22,6 @@ type Device struct {
bufferSize int16
vccState VccMode
canReset bool
resetCol ResetValue
resetPage ResetValue
}
// Config is the configuration for the display
@@ -34,13 +30,6 @@ type Config struct {
Height int16
VccState VccMode
Address uint16
// ResetCol and ResetPage are used to reset the screen to 0x0
// This is useful for some screens that have a different size than 128x64
// For example, the Thumby's screen is 72x40
// The default values are normally set automatically based on the size.
// If you're using a different size, you might need to set these values manually.
ResetCol ResetValue
ResetPage ResetValue
}
type I2CBus struct {
@@ -90,7 +79,6 @@ func NewSPI(bus drivers.SPI, dcPin, resetPin, csPin machine.Pin) Device {
// Configure initializes the display with default configuration
func (d *Device) Configure(cfg Config) {
var zeroReset ResetValue
if cfg.Width != 0 {
d.width = cfg.Width
} else {
@@ -109,16 +97,6 @@ func (d *Device) Configure(cfg Config) {
} else {
d.vccState = SWITCHCAPVCC
}
if cfg.ResetCol != zeroReset {
d.resetCol = cfg.ResetCol
} else {
d.resetCol = ResetValue{0, uint8(d.width - 1)}
}
if cfg.ResetPage != zeroReset {
d.resetPage = cfg.ResetPage
} else {
d.resetPage = ResetValue{0, uint8(d.height/8) - 1}
}
d.bufferSize = d.width * d.height / 8
d.buffer = make([]byte, d.bufferSize)
d.canReset = cfg.Address != 0 || d.width != 128 || d.height != 64 // I2C or not 128x64
@@ -208,11 +186,11 @@ func (d *Device) Display() error {
// Since we're printing the whole buffer, avoid resetting it in this case
if d.canReset {
d.Command(COLUMNADDR)
d.Command(d.resetCol[0])
d.Command(d.resetCol[1])
d.Command(0)
d.Command(uint8(d.width - 1))
d.Command(PAGEADDR)
d.Command(d.resetPage[0])
d.Command(d.resetPage[1])
d.Command(0)
d.Command(uint8(d.height/8) - 1)
}
return d.Tx(d.buffer, false)
+1 -1
View File
@@ -2,4 +2,4 @@ package drivers
// Version returns a user-readable string showing the version of the drivers package for support purposes.
// Update this value before release of new version of software.
const Version = "0.27.0"
const Version = "0.26.0"
+99 -161
View File
@@ -33,6 +33,7 @@ var _debug debug = debugBasic
//var _debug debug = debugBasic | debugNetdev | debugCmd | debugDetail
var (
version = "0.0.1"
driverName = "Tinygo ESP32 Wifi network device driver (WiFiNINA)"
)
@@ -162,12 +163,10 @@ type encryptionType uint8
type sock uint8
type hwerr uint8
type Socket struct {
protocol int
clientConnected bool
laddr netip.AddrPort // Set in Bind()
raddr netip.AddrPort // Set in Connect()
sock // Device socket, as returned from w.getSocket()
type socket struct {
protocol int
ip netip.AddrPort
inuse bool
}
type Config struct {
@@ -214,13 +213,17 @@ type wifinina struct {
killWatchdog chan bool
fault error
sockets map[int]*Socket // keyed by sockfd
sockets map[sock]*socket // keyed by sock as returned by getSocket()
}
func newSocket(protocol int) *socket {
return &socket{protocol: protocol, inuse: true}
}
func New(cfg *Config) *wifinina {
w := wifinina{
cfg: cfg,
sockets: make(map[int]*Socket),
sockets: make(map[sock]*socket),
killWatchdog: make(chan bool),
cs: cfg.Cs,
ack: cfg.Ack,
@@ -310,7 +313,7 @@ func (w *wifinina) showDriver() {
if debugging(debugBasic) {
fmt.Printf("\r\n")
fmt.Printf("%s\r\n\r\n", driverName)
fmt.Printf("Driver version : %s\r\n", drivers.Version)
fmt.Printf("Driver version : %s\r\n", version)
}
w.driverShown = true
}
@@ -501,12 +504,6 @@ func (w *wifinina) GetHostByName(name string) (netip.Addr, error) {
fmt.Printf("[GetHostByName] name: %s\r\n", name)
}
// If it's already in dotted-decimal notation, return a copy
// per gethostbyname(3).
if ip, err := netip.ParseAddr(name); err == nil {
return ip, nil
}
w.mu.Lock()
defer w.mu.Unlock()
@@ -549,20 +546,6 @@ func (w *wifinina) Addr() (netip.Addr, error) {
return ip, nil
}
// newSockfd returns the next available sockfd, or -1 if none available
func (w *wifinina) newSockfd() int {
if len(w.sockets) >= maxNetworks {
return -1
}
// Search for the next available sockfd starting at 0
for sockfd := 0; ; sockfd++ {
if _, ok := w.sockets[sockfd]; !ok {
return sockfd
}
}
return -1
}
// See man socket(2) for standard Berkely sockets for Socket, Bind, etc.
// The driver strives to meet the function and semantics of socket(2).
@@ -590,49 +573,37 @@ func (w *wifinina) Socket(domain int, stype int, protocol int) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
sockfd := w.newSockfd()
if sockfd == -1 {
sock := w.getSocket()
if sock == noSocketAvail {
return -1, netdev.ErrNoMoreSockets
}
w.sockets[sockfd] = &Socket{
protocol: protocol,
sock: noSocketAvail,
}
socket := newSocket(protocol)
w.sockets[sock] = socket
if debugging(debugNetdev) {
fmt.Printf("[Socket] <-- sockfd %d\r\n", sockfd)
}
return sockfd, nil
return int(sock), nil
}
func (w *wifinina) Bind(sockfd int, ip netip.AddrPort) error {
if debugging(debugNetdev) {
fmt.Printf("[Bind] sockfd: %d, addr: %s:%d\r\n", sockfd, ip.Addr(), ip.Port())
fmt.Printf("[Bind] sockfd: %d, addr: %s\r\n", sockfd, ip)
}
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return netdev.ErrInvalidSocketFd
}
var sock = sock(sockfd)
var socket = w.sockets[sock]
switch socket.protocol {
case netdev.IPPROTO_TCP:
case netdev.IPPROTO_TLS:
case netdev.IPPROTO_UDP:
socket.sock = w.getSocket()
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startServer(socket.sock, ip.Port(), protoModeUDP)
w.startServer(sock, ip.Port(), protoModeUDP)
}
socket.laddr = ip
socket.ip = ip
return nil
}
@@ -657,40 +628,21 @@ func (w *wifinina) Connect(sockfd int, host string, ip netip.AddrPort) error {
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return netdev.ErrInvalidSocketFd
}
var sock = sock(sockfd)
var socket = w.sockets[sock]
// Start the connection
switch socket.protocol {
case netdev.IPPROTO_TCP:
socket.sock = w.getSocket()
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startClient(socket.sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeTCP)
w.startClient(sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeTCP)
case netdev.IPPROTO_TLS:
socket.sock = w.getSocket()
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startClient(socket.sock, host, 0, ip.Port(), protoModeTLS)
w.startClient(sock, host, 0, ip.Port(), protoModeTLS)
case netdev.IPPROTO_UDP:
if socket.sock == noSocketAvail {
return fmt.Errorf("Must Bind before Connecting")
}
// See start in sendUDP()
socket.raddr = ip
socket.clientConnected = true
w.startClient(sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeUDP)
return nil
}
if w.getClientState(socket.sock) == tcpStateEstablished {
socket.clientConnected = true
if w.getClientState(sock) == tcpStateEstablished {
return nil
}
@@ -710,18 +662,12 @@ func (w *wifinina) Listen(sockfd int, backlog int) error {
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return netdev.ErrInvalidSocketFd
}
var sock = sock(sockfd)
var socket = w.sockets[sock]
switch socket.protocol {
case netdev.IPPROTO_TCP:
socket.sock = w.getSocket()
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startServer(socket.sock, socket.laddr.Port(), protoModeTCP)
w.startServer(sock, socket.ip.Port(), protoModeTCP)
case netdev.IPPROTO_UDP:
default:
return netdev.ErrProtocolNotSupported
@@ -730,29 +676,27 @@ func (w *wifinina) Listen(sockfd int, backlog int) error {
return nil
}
func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
if debugging(debugNetdev) {
fmt.Printf("[Accept] sockfd: %d\r\n", sockfd)
fmt.Printf("[Accept] sockfd: %d, peer: %s\r\n", sockfd, ip)
}
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return -1, netip.AddrPort{}, netdev.ErrInvalidSocketFd
}
var client sock
var sock = sock(sockfd)
var socket = w.sockets[sock]
switch socket.protocol {
case netdev.IPPROTO_TCP:
default:
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
return -1, netdev.ErrProtocolNotSupported
}
skip:
for {
// Accept() will be sleeping most of the time, checking for
// Accept() will be sleeping most of the time, checking for a
// new clients every 1/10 sec.
w.mu.Unlock()
time.Sleep(100 * time.Millisecond)
@@ -760,46 +704,49 @@ skip:
// Check if we've faulted
if w.fault != nil {
return -1, netip.AddrPort{}, w.fault
return -1, w.fault
}
// TODO: BUG: Currently, a sock that is 100% busy will always be
// TODO: returned by w.accept(sock), starving other socks
// TODO: from begin serviced. Need to figure out how to
// TODO: service socks fairly (round-robin?) so no one sock
// TODO: can dominate.
// Check if a client has data
var client sock = w.accept(socket.sock)
client = w.accept(sock)
if client == noSocketAvail {
// None ready
continue
}
// If we already have a socket for the client, skip
for _, s := range w.sockets {
if s.sock == client {
continue skip
// If we've already seen this socket, we can reuse
// the socket and return it. But, only if the socket
// is closed. If it's not closed, we'll just come back
// later to reuse it.
clientSocket, ok := w.sockets[client]
if ok {
// Wait for client to Close
if clientSocket.inuse {
continue
}
// Reuse client socket
return int(client), nil
}
// Otherwise, create a new socket
clientfd := w.newSockfd()
if clientfd == -1 {
return -1, netip.AddrPort{}, netdev.ErrNoMoreSockets
}
w.sockets[clientfd] = &Socket{
protocol: netdev.IPPROTO_TCP,
sock: client,
clientConnected: true,
}
raddr := w.getRemoteData(client)
return clientfd, raddr, nil
// Create new socket for client and return fd
w.sockets[client] = newSocket(socket.protocol)
return int(client), nil
}
}
func (w *wifinina) sockDown(socket *Socket) bool {
func (w *wifinina) sockDown(sock sock) bool {
var socket = w.sockets[sock]
if socket.protocol == netdev.IPPROTO_UDP {
return false
}
return w.getClientState(socket.sock) != tcpStateEstablished
return w.getClientState(sock) != tcpStateEstablished
}
func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, error) {
@@ -827,7 +774,7 @@ func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, erro
}
// Check if socket went down
if w.getClientState(sock) != tcpStateEstablished {
if w.sockDown(sock) {
return -1, io.EOF
}
@@ -845,10 +792,7 @@ func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, erro
return -1, netdev.ErrTimeout
}
func (w *wifinina) sendUDP(sock sock, raddr netip.AddrPort, buf []byte, deadline time.Time) (int, error) {
// Start a client for each send
w.startClient(sock, "", toUint32(raddr.Addr().As4()), raddr.Port(), protoModeUDP)
func (w *wifinina) sendUDP(sock sock, buf []byte, deadline time.Time) (int, error) {
// Queue it
ok := w.insertDataBuf(sock, buf)
@@ -866,10 +810,8 @@ func (w *wifinina) sendUDP(sock sock, raddr netip.AddrPort, buf []byte, deadline
}
func (w *wifinina) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
socket, ok := w.sockets[sockfd]
if !ok {
return -1, netdev.ErrInvalidSocketFd
}
var sock = sock(sockfd)
var socket = w.sockets[sock]
// Check if we've timed out
if !deadline.IsZero() {
@@ -880,9 +822,9 @@ func (w *wifinina) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, e
switch socket.protocol {
case netdev.IPPROTO_TCP, netdev.IPPROTO_TLS:
return w.sendTCP(socket.sock, buf, deadline)
return w.sendTCP(sock, buf, deadline)
case netdev.IPPROTO_UDP:
return w.sendUDP(socket.sock, socket.raddr, buf, deadline)
return w.sendUDP(sock, buf, deadline)
}
return -1, netdev.ErrProtocolNotSupported
@@ -927,10 +869,7 @@ func (w *wifinina) Recv(sockfd int, buf []byte, flags int,
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return -1, netdev.ErrInvalidSocketFd
}
var sock = sock(sockfd)
// Limit max read size to chunk large read requests
var max = len(buf)
@@ -951,22 +890,22 @@ func (w *wifinina) Recv(sockfd int, buf []byte, flags int,
// doesn't return unless there is data, even a single byte, or
// on error such as timeout or EOF.
n := int(w.getDataBuf(socket.sock, buf[:max]))
n := int(w.getDataBuf(sock, buf[:max]))
if n > 0 {
if debugging(debugNetdev) {
fmt.Printf("[<--Recv] sockfd: %d, n: %d\r\n",
sockfd, n)
sock, n)
}
return n, nil
}
// Check if socket went down
if w.sockDown(socket) {
if w.sockDown(sock) {
// Get any last bytes
n = int(w.getDataBuf(socket.sock, buf[:max]))
n = int(w.getDataBuf(sock, buf[:max]))
if debugging(debugNetdev) {
fmt.Printf("[<--Recv] sockfd: %d, n: %d, EOF\r\n",
sockfd, n)
sock, n)
}
if n > 0 {
return n, io.EOF
@@ -995,18 +934,34 @@ func (w *wifinina) Close(sockfd int) error {
w.mu.Lock()
defer w.mu.Unlock()
socket, ok := w.sockets[sockfd]
if !ok {
return netdev.ErrInvalidSocketFd
var sock = sock(sockfd)
var socket = w.sockets[sock]
if !socket.inuse {
return nil
}
if socket.clientConnected {
w.stopClient(socket.sock)
w.stopClient(sock)
if socket.protocol == netdev.IPPROTO_UDP {
socket.inuse = false
return nil
}
delete(w.sockets, sockfd)
start := time.Now()
for time.Since(start) < 5*time.Second {
return nil
if w.getClientState(sock) == tcpStateClosed {
socket.inuse = false
return nil
}
w.mu.Unlock()
time.Sleep(100 * time.Millisecond)
w.mu.Lock()
}
return netdev.ErrClosingSocket
}
func (w *wifinina) SetSockOpt(sockfd int, level int, opt int, value interface{}) error {
@@ -1168,23 +1123,6 @@ func (w *wifinina) accept(s sock) sock {
return newsock
}
func (w *wifinina) getRemoteData(s sock) netip.AddrPort {
if debugging(debugCmd) {
fmt.Printf(" [cmdGetRemoteData] sock: %d\r\n", s)
}
sl := make([]string, 2)
l := w.reqRspStr1(cmdGetRemoteData, uint8(s), sl)
if l != 2 {
w.faultf("getRemoteData wanted l=2, got l=%d", l)
return netip.AddrPort{}
}
ip, _ := netip.AddrFromSlice([]byte(sl[0])[:4])
port := binary.BigEndian.Uint16([]byte(sl[1]))
return netip.AddrPortFrom(ip, port)
}
// insertDataBuf adds data to the buffer used for sending UDP data
func (w *wifinina) insertDataBuf(sock sock, buf []byte) bool {