Compare commits

..

3 Commits

Author SHA1 Message Date
soypat 5405842815 rewrite enum implementations 2023-12-26 22:44:25 -03:00
soypat 09b7b249fe working more or less 2023-12-26 22:35:48 -03:00
soypat 4bd873a82d add draft apds9930 2023-12-26 15:00:56 -08:00
38 changed files with 430 additions and 657 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 0.26.0
--- ---
- **core** - **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 Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are 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) [![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: For the complete list, please see:
https://tinygo.org/docs/reference/devices/ 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) { func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
rx, ry, rz := d.ReadRawAcceleration() rx, ry, rz := d.ReadRawAcceleration()
x = int32(d.dataFormat.convertToIS(rx)) x = d.dataFormat.convertToIS(rx)
y = int32(d.dataFormat.convertToIS(ry)) y = d.dataFormat.convertToIS(ry)
z = int32(d.dataFormat.convertToIS(rz)) z = d.dataFormat.convertToIS(rz)
return return
} }
// ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis // ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis
// from the adxl345. // 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} data := []byte{0, 0, 0, 0, 0, 0}
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data) 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 // 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 { switch d.sensorRange {
case RANGE_2G: case RANGE_2G:
return rawValue * 4 // rawValue * 2 * 1000 / 512 return rawValue * 4 // rawValue * 2 * 1000 / 512
@@ -190,6 +190,6 @@ func (b *bwRate) toByte() (bits uint8) {
} }
// readInt converts two bytes to int16 // readInt converts two bytes to int16
func readIntLE(msb byte, lsb byte) int16 { func readIntLE(msb byte, lsb byte) int32 {
return int16(uint16(msb) | uint16(lsb)<<8) return int32(uint16(msb) | uint16(lsb)<<8)
} }
+231
View File
@@ -0,0 +1,231 @@
package apds9930
import (
"errors"
"tinygo.org/x/drivers"
)
var errInvalidParam = errors.New("apds9930: invalid param")
type Dev struct {
bus drivers.I2C
_txerr error
addr uint16
buf [3]byte
}
func New(bus drivers.I2C, addr uint8) Dev {
return Dev{bus: bus, addr: uint16(addr)}
}
// Status contains info on:
//
// AVALID: Indicates that the ALS Ch0/Ch1 channels have completed an integration cycle.
// PSValid. Indicates that the PS has completed an integration cycle.
// AINTL ALS Interrupt. Indicates that the device is asserting an ALS interrupt
// PINT: Proximity Interrupt. Indicates that the device is asserting a proximity interrupt.
// PSAT: Proximity Saturation. Indicates that the proximity measurement is saturated
type Status uint8
func (s Status) ALSAvailable() bool { return s&(1<<0) != 0 } // AVALID
func (s Status) ProximityAvailable() bool { return s&(1<<1) != 0 } // PVALID
func (s Status) HasALSInterrupt() bool { return s&(1<<4) != 0 } // AINT
func (s Status) HasProxInterrupt() bool { return s&(1<<5) != 0 } // PINT
func (s Status) IsProximitySaturated() bool { return s&(1<<6) != 0 } // PSAT
type Enable uint8
const (
EnPower Enable = 1 << iota
EnALS
EnProx
EnWait
EnALSInt
EnProxInt
EnSleepAfterInt
)
// Luminic control gain.
type ALSGain uint8
const (
AGain1 ALSGain = iota
AGain8
AGain16
AGain120
)
type ProxGain uint8
const (
PGain1 ProxGain = iota
PGain2
PGain4
PGain8
)
type Drive uint8
const (
Drive100mA Drive = iota
Drive50mA
Drive25mA
Drive12_5mA
)
type Config struct {
ProxGain ProxGain
ALSGain ALSGain
LEDDrive Drive
}
func (d *Dev) Init(cfg Config) error {
if cfg.LEDDrive > Drive100mA {
return errInvalidParam
}
d.txNew()
d.txWrite8(regENABLE, 0x00) // disable all features.
d.txWrite8(regATIME, 0xee) // set default integration time.
d.txWrite8(regPPULSE, 0x04)
d.txWrite8(regWTIME, 0xee) // set default wait time.
d.txWrite8(regPTIME, 0xff) // set default pulse count.
var ctlval uint8 = 0b10 << 4 // Use Channel 1 diode.
ctlval |= uint8(cfg.LEDDrive&0b11) << 6
ctlval |= uint8(cfg.ProxGain&0b11) << 2
ctlval |= uint8(cfg.ALSGain & 0b11)
d.txWrite8(regCONTROL, ctlval)
return d.txErr()
}
func (d *Dev) Status() (Status, error) {
d.txNew()
v := d.txRead8(regSTATUS)
return Status(v), d.txErr()
}
// Enable sets the ENABLE register used primarily to
// power the APDS-9930 device on/off, enable functions, and interrupts.
// Arguments must be ORed, i.e: d.Enable(EnPower|EnProx); to enable proximity.
func (d *Dev) Enable(en Enable) error {
en &= 0b01111111 // Seventh bit reserved.
d.txNew()
d.txWrite8(regENABLE, uint8(en))
return d.txErr()
}
func (d *Dev) enableLightSensor(withInterrupts bool) error {
return nil
}
func (d *Dev) setAmbientLightGain() {
}
func (d *Dev) EnableProximity() error {
return d.Enable(EnPower | EnALS | EnProx | EnWait)
}
func (d *Dev) proxIntLowThresh() (uint16, error) {
d.txNew()
return d.txRead16(regPILTL), d.txErr()
}
func (d *Dev) setProxIntLowThresh(loThresh uint16) error {
d.txNew()
d.txWrite16(regPILTL, loThresh)
return d.txErr()
}
func (d *Dev) proxIntHighThresh() (uint16, error) {
d.txNew()
val := d.txRead16(regPIHTL)
return val, d.txErr()
}
func (d *Dev) setProxIntHighThresh(hiThresh uint16) error {
d.txNew()
d.txWrite16(regPIHTL, hiThresh)
return d.txErr()
}
func (d *Dev) LEDDrive() (Drive, error) {
d.txNew()
val := (d.txRead8(regCONTROL) >> 6) & 0b11
return Drive(val), d.txErr()
}
// SetLEDDrive drive strength for proximity and ALS
//
// Value LED Current
// 3 100 mA
// 2 50 mA
// 1 25 mA
// 0 12.5 mA
func (d *Dev) SetLEDDrive(drive Drive) error {
if drive > 3 {
return errInvalidParam
}
current, err := d.LEDDrive()
if err != nil {
return err
}
// Replace LED bits in Control register.
current &= 0b00111111
current |= drive << 6
d.txNew()
d.txWrite8(regCONTROL, uint8(current))
return d.txErr()
}
func (d *Dev) proxGain() (uint8, error) {
val := d.txRead8(regCONTROL)
return (val >> 2) & 0b11, d.txErr()
}
// ReadProximity returns a 10-bit value (0..1023), the higher the value the closer the object
func (d *Dev) ReadProximity() uint16 {
d.txNew()
v := d.txRead16(regPDATAL)
if d.txErr() != nil {
return 0
}
return v
}
func (d *Dev) txRead16(addr uint8) uint16 {
if d.txErr() != nil {
return 0
}
d.buf[0] = addr | protoAutoInc
d._txerr = d.bus.Tx(d.addr, d.buf[:1], d.buf[1:3])
return uint16(d.buf[1]) | uint16(d.buf[2])<<8
}
func (d *Dev) txRead8(addr uint8) uint8 {
if d.txErr() != nil {
return 0
}
d.buf[0] = addr | protoAutoInc
d._txerr = d.bus.Tx(d.addr, d.buf[:1], d.buf[1:2])
return d.buf[1]
}
func (d *Dev) txWrite16(addr uint8, val uint16) {
d.txWrite8(addr, uint8(val))
d.txWrite8(addr+1, uint8(val>>8))
}
func (d *Dev) txWrite8(reg uint8, val uint8) {
if d.txErr() != nil {
return
}
d.buf[0] = reg | 0x80
d.buf[1] = val
d._txerr = d.bus.Tx(d.addr, d.buf[:2], nil)
}
func (d *Dev) txNew() { d._txerr = nil }
func (d *Dev) txErr() error { return d._txerr }
+23
View File
@@ -0,0 +1,23 @@
package apds9930
const (
protoAutoInc = 0xA0
)
const (
regENABLE = 0x00
regATIME = 0x01
regPTIME = 0x02
regWTIME = 0x03
regPILTL = 0x08
regPILTH = 0x09
regPIHTL = 0x0A
regPIHTH = 0x0B
regCONFIG = 0x0D
regPPULSE = 0x0E
regCONTROL = 0x0F
regSTATUS = 0x13
regPDATAL = 0x18
regPDATAH = 0x19
regPOFFSET = 0x1E
)
-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))
}
+43
View File
@@ -0,0 +1,43 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/apds9930"
)
func main() {
// Sleep to catch any errors through the serial monitor.
time.Sleep(1000 * time.Millisecond)
bus := machine.I2C0
// use Nano 33 BLE Sense's internal I2C bus
err := bus.Configure(machine.I2CConfig{
SCL: machine.GP1,
SDA: machine.GP0,
Frequency: 100 * machine.KHz,
})
if err != nil {
panic(err.Error())
}
sensor := apds9930.New(bus, 0x39)
err = sensor.Init(apds9930.Config{})
if err != nil {
panic(err)
}
err = sensor.EnableProximity()
if err != nil {
panic(err)
}
println("proximity enabled!")
for {
stat, _ := sensor.Status()
if !stat.ProximityAvailable() {
time.Sleep(5 * time.Millisecond)
continue
}
prox := sensor.ReadProximity()
println("proximity:", prox)
}
}
@@ -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/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS) // examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal //go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP) // examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS) // examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal //go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP) // examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS) // examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal //go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP) // examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS) // examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal //go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using // Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option. // 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 package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using // Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option. // 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 package main
+1 -1
View File
@@ -3,7 +3,7 @@
// It creates a UDP connection to request the current time and parse the // 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. // 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 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 // 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 package main
+1 -1
View File
@@ -5,7 +5,7 @@
// //
// nc -lk 8080 // 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 package main
+1 -1
View File
@@ -7,7 +7,7 @@
// //
// $ nc 10.0.0.2 8080 <file >copy ; cmp file copy // $ 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 package main
+1 -1
View File
@@ -5,7 +5,7 @@
// //
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security // 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 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 package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using "net/http". // Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option. // 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 package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using // 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. // "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 package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using // 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. // "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 package main
+1 -1
View File
@@ -3,7 +3,7 @@
// Note: It may be necessary to increase the stack size when using "net/http". // Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option. // 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 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
View File
@@ -39,7 +39,6 @@ var (
ErrNoMoreSockets = errors.New("No more sockets") ErrNoMoreSockets = errors.New("No more sockets")
ErrClosingSocket = errors.New("Error closing socket") ErrClosingSocket = errors.New("Error closing socket")
ErrNotSupported = errors.New("Not supported") ErrNotSupported = errors.New("Not supported")
ErrInvalidSocketFd = errors.New("Invalid socket fd")
) )
// Duplicate of non-exported net.errTimeout // Duplicate of non-exported net.errTimeout
-1
View File
@@ -13,7 +13,6 @@ var (
ErrConnectFailed = errors.New("Connect failed") ErrConnectFailed = errors.New("Connect failed")
ErrConnectTimeout = errors.New("Connect timed out") ErrConnectTimeout = errors.New("Connect timed out")
ErrMissingSSID = errors.New("Missing WiFi SSID") ErrMissingSSID = errors.New("Missing WiFi SSID")
ErrShortPassphrase = errors.New("Invalid Wifi Passphrase < 8 chars")
ErrAuthFailure = errors.New("Wifi authentication failure") ErrAuthFailure = errors.New("Wifi authentication failure")
ErrAuthTypeNoGood = errors.New("Wifi authorization type not supported") ErrAuthTypeNoGood = errors.New("Wifi authorization type not supported")
ErrConnectModeNoGood = errors.New("Connect mode 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 package probe
+4 -12
View File
@@ -17,7 +17,6 @@ import (
"sync" "sync"
"time" "time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/netdev" "tinygo.org/x/drivers/netdev"
"tinygo.org/x/drivers/netlink" "tinygo.org/x/drivers/netlink"
) )
@@ -28,6 +27,7 @@ var _debug debug = debugBasic
//var _debug debug = debugBasic | debugNetdev | debugRpc //var _debug debug = debugBasic | debugNetdev | debugRpc
var ( var (
version = "0.0.1"
driverName = "Realtek rtl8720dn Wifi network device driver (rtl8720dn)" driverName = "Realtek rtl8720dn Wifi network device driver (rtl8720dn)"
) )
@@ -102,22 +102,14 @@ func (r *rtl8720dn) connectToAP() error {
return netlink.ErrMissingSSID return netlink.ErrMissingSSID
} }
if len(r.params.Passphrase) != 0 && len(r.params.Passphrase) < 8 {
return netlink.ErrShortPassphrase
}
if debugging(debugBasic) { if debugging(debugBasic) {
fmt.Printf("Connecting to Wifi SSID '%s'...", r.params.Ssid) fmt.Printf("Connecting to Wifi SSID '%s'...", r.params.Ssid)
} }
// Start the connection process // Start the connection process
securityType := uint32(0) // RTW_SECURITY_OPEN securityType := uint32(0x00400004)
if len(r.params.Passphrase) != 0 {
securityType = 0x00400004 // RTW_SECURITY_WPA2_AES_PSK
}
result := r.rpc_wifi_connect(r.params.Ssid, r.params.Passphrase, securityType, -1, 0) result := r.rpc_wifi_connect(r.params.Ssid, r.params.Passphrase, securityType, -1, 0)
if result != 0 { if result == -1 {
if debugging(debugBasic) { if debugging(debugBasic) {
fmt.Printf("FAILED\r\n") fmt.Printf("FAILED\r\n")
} }
@@ -142,7 +134,7 @@ func (r *rtl8720dn) showDriver() {
if debugging(debugBasic) { if debugging(debugBasic) {
fmt.Printf("\r\n") fmt.Printf("\r\n")
fmt.Printf("%s\r\n\r\n", driverName) 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 r.driverShown = true
} }
-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.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.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/sh1106/macropad_spi
tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/encoders/quadrature-interrupt
# network examples (espat) # network examples (espat)
tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/ tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
# network examples (wifinina) # network examples (wifinina)
+4 -26
View File
@@ -13,8 +13,6 @@ import (
"tinygo.org/x/drivers/internal/legacy" "tinygo.org/x/drivers/internal/legacy"
) )
type ResetValue [2]byte
// Device wraps I2C or SPI connection. // Device wraps I2C or SPI connection.
type Device struct { type Device struct {
bus Buser bus Buser
@@ -24,8 +22,6 @@ type Device struct {
bufferSize int16 bufferSize int16
vccState VccMode vccState VccMode
canReset bool canReset bool
resetCol ResetValue
resetPage ResetValue
} }
// Config is the configuration for the display // Config is the configuration for the display
@@ -34,13 +30,6 @@ type Config struct {
Height int16 Height int16
VccState VccMode VccState VccMode
Address uint16 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 { 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 // Configure initializes the display with default configuration
func (d *Device) Configure(cfg Config) { func (d *Device) Configure(cfg Config) {
var zeroReset ResetValue
if cfg.Width != 0 { if cfg.Width != 0 {
d.width = cfg.Width d.width = cfg.Width
} else { } else {
@@ -109,16 +97,6 @@ func (d *Device) Configure(cfg Config) {
} else { } else {
d.vccState = SWITCHCAPVCC 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.bufferSize = d.width * d.height / 8
d.buffer = make([]byte, d.bufferSize) d.buffer = make([]byte, d.bufferSize)
d.canReset = cfg.Address != 0 || d.width != 128 || d.height != 64 // I2C or not 128x64 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 // Since we're printing the whole buffer, avoid resetting it in this case
if d.canReset { if d.canReset {
d.Command(COLUMNADDR) d.Command(COLUMNADDR)
d.Command(d.resetCol[0]) d.Command(0)
d.Command(d.resetCol[1]) d.Command(uint8(d.width - 1))
d.Command(PAGEADDR) d.Command(PAGEADDR)
d.Command(d.resetPage[0]) d.Command(0)
d.Command(d.resetPage[1]) d.Command(uint8(d.height/8) - 1)
} }
return d.Tx(d.buffer, false) 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. // 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. // Update this value before release of new version of software.
const Version = "0.27.0" const Version = "0.26.0"
+100 -143
View File
@@ -33,6 +33,7 @@ var _debug debug = debugBasic
//var _debug debug = debugBasic | debugNetdev | debugCmd | debugDetail //var _debug debug = debugBasic | debugNetdev | debugCmd | debugDetail
var ( var (
version = "0.0.1"
driverName = "Tinygo ESP32 Wifi network device driver (WiFiNINA)" driverName = "Tinygo ESP32 Wifi network device driver (WiFiNINA)"
) )
@@ -162,12 +163,10 @@ type encryptionType uint8
type sock uint8 type sock uint8
type hwerr uint8 type hwerr uint8
type Socket struct { type socket struct {
protocol int protocol int
clientConnected bool ip netip.AddrPort
laddr netip.AddrPort // Set in Bind() inuse bool
raddr netip.AddrPort // Set in Connect()
sock // Device socket, as returned from w.getSocket()
} }
type Config struct { type Config struct {
@@ -214,13 +213,17 @@ type wifinina struct {
killWatchdog chan bool killWatchdog chan bool
fault error 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 { func New(cfg *Config) *wifinina {
w := wifinina{ w := wifinina{
cfg: cfg, cfg: cfg,
sockets: make(map[int]*Socket), sockets: make(map[sock]*socket),
killWatchdog: make(chan bool), killWatchdog: make(chan bool),
cs: cfg.Cs, cs: cfg.Cs,
ack: cfg.Ack, ack: cfg.Ack,
@@ -310,7 +313,7 @@ func (w *wifinina) showDriver() {
if debugging(debugBasic) { if debugging(debugBasic) {
fmt.Printf("\r\n") fmt.Printf("\r\n")
fmt.Printf("%s\r\n\r\n", driverName) 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 w.driverShown = true
} }
@@ -501,12 +504,6 @@ func (w *wifinina) GetHostByName(name string) (netip.Addr, error) {
fmt.Printf("[GetHostByName] name: %s\r\n", name) 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() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
@@ -549,20 +546,6 @@ func (w *wifinina) Addr() (netip.Addr, error) {
return ip, nil 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. // See man socket(2) for standard Berkely sockets for Socket, Bind, etc.
// The driver strives to meet the function and semantics of socket(2). // 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() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
sockfd := w.newSockfd() sock := w.getSocket()
if sockfd == -1 { if sock == noSocketAvail {
return -1, netdev.ErrNoMoreSockets return -1, netdev.ErrNoMoreSockets
} }
w.sockets[sockfd] = &Socket{ socket := newSocket(protocol)
protocol: protocol, w.sockets[sock] = socket
sock: noSocketAvail,
}
if debugging(debugNetdev) { return int(sock), nil
fmt.Printf("[Socket] <-- sockfd %d\r\n", sockfd)
}
return sockfd, nil
} }
func (w *wifinina) Bind(sockfd int, ip netip.AddrPort) error { func (w *wifinina) Bind(sockfd int, ip netip.AddrPort) error {
if debugging(debugNetdev) { 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() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok { var socket = w.sockets[sock]
return netdev.ErrInvalidSocketFd
}
switch socket.protocol { switch socket.protocol {
case netdev.IPPROTO_TCP: case netdev.IPPROTO_TCP:
case netdev.IPPROTO_TLS: case netdev.IPPROTO_TLS:
case netdev.IPPROTO_UDP: case netdev.IPPROTO_UDP:
socket.sock = w.getSocket() w.startServer(sock, ip.Port(), protoModeUDP)
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startServer(socket.sock, ip.Port(), protoModeUDP)
} }
socket.laddr = ip socket.ip = ip
return nil return nil
} }
@@ -657,40 +628,21 @@ func (w *wifinina) Connect(sockfd int, host string, ip netip.AddrPort) error {
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok { var socket = w.sockets[sock]
return netdev.ErrInvalidSocketFd
}
// Start the connection // Start the connection
switch socket.protocol { switch socket.protocol {
case netdev.IPPROTO_TCP: case netdev.IPPROTO_TCP:
socket.sock = w.getSocket() w.startClient(sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeTCP)
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startClient(socket.sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeTCP)
case netdev.IPPROTO_TLS: case netdev.IPPROTO_TLS:
socket.sock = w.getSocket() w.startClient(sock, host, 0, ip.Port(), protoModeTLS)
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startClient(socket.sock, host, 0, ip.Port(), protoModeTLS)
case netdev.IPPROTO_UDP: case netdev.IPPROTO_UDP:
if socket.sock == noSocketAvail { w.startClient(sock, "", toUint32(ip.Addr().As4()), ip.Port(), protoModeUDP)
return fmt.Errorf("Must Bind before Connecting")
}
// See start in sendUDP()
socket.raddr = ip
socket.clientConnected = true
return nil return nil
} }
if w.getClientState(socket.sock) == tcpStateEstablished { if w.getClientState(sock) == tcpStateEstablished {
socket.clientConnected = true
return nil return nil
} }
@@ -710,18 +662,12 @@ func (w *wifinina) Listen(sockfd int, backlog int) error {
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok { var socket = w.sockets[sock]
return netdev.ErrInvalidSocketFd
}
switch socket.protocol { switch socket.protocol {
case netdev.IPPROTO_TCP: case netdev.IPPROTO_TCP:
socket.sock = w.getSocket() w.startServer(sock, socket.ip.Port(), protoModeTCP)
if socket.sock == noSocketAvail {
return netdev.ErrNoMoreSockets
}
w.startServer(socket.sock, socket.laddr.Port(), protoModeTCP)
case netdev.IPPROTO_UDP: case netdev.IPPROTO_UDP:
default: default:
return netdev.ErrProtocolNotSupported return netdev.ErrProtocolNotSupported
@@ -739,10 +685,9 @@ func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var client sock
if !ok { var sock = sock(sockfd)
return -1, netip.AddrPort{}, netdev.ErrInvalidSocketFd var socket = w.sockets[sock]
}
switch socket.protocol { switch socket.protocol {
case netdev.IPPROTO_TCP: case netdev.IPPROTO_TCP:
@@ -750,9 +695,8 @@ func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
} }
skip:
for { 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. // new clients every 1/10 sec.
w.mu.Unlock() w.mu.Unlock()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@@ -763,43 +707,48 @@ skip:
return -1, netip.AddrPort{}, w.fault return -1, netip.AddrPort{}, 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 // Check if a client has data
var client sock = w.accept(socket.sock) client = w.accept(sock)
if client == noSocketAvail { if client == noSocketAvail {
// None ready // None ready
continue continue
} }
// If we already have a socket for the client, skip
for _, s := range w.sockets {
if s.sock == client {
continue skip
}
}
// 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) raddr := w.getRemoteData(client)
return clientfd, raddr, nil // 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), raddr, nil
}
// Create new socket for client and return fd
w.sockets[client] = newSocket(socket.protocol)
return int(client), raddr, 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 { if socket.protocol == netdev.IPPROTO_UDP {
return false 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) { func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, error) {
@@ -827,7 +776,7 @@ func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, erro
} }
// Check if socket went down // Check if socket went down
if w.getClientState(sock) != tcpStateEstablished { if w.sockDown(sock) {
return -1, io.EOF return -1, io.EOF
} }
@@ -845,10 +794,7 @@ func (w *wifinina) sendTCP(sock sock, buf []byte, deadline time.Time) (int, erro
return -1, netdev.ErrTimeout return -1, netdev.ErrTimeout
} }
func (w *wifinina) sendUDP(sock sock, raddr netip.AddrPort, buf []byte, deadline time.Time) (int, error) { func (w *wifinina) sendUDP(sock sock, buf []byte, deadline time.Time) (int, error) {
// Start a client for each send
w.startClient(sock, "", toUint32(raddr.Addr().As4()), raddr.Port(), protoModeUDP)
// Queue it // Queue it
ok := w.insertDataBuf(sock, buf) ok := w.insertDataBuf(sock, buf)
@@ -866,10 +812,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) { func (w *wifinina) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok { var socket = w.sockets[sock]
return -1, netdev.ErrInvalidSocketFd
}
// Check if we've timed out // Check if we've timed out
if !deadline.IsZero() { if !deadline.IsZero() {
@@ -880,9 +824,9 @@ func (w *wifinina) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, e
switch socket.protocol { switch socket.protocol {
case netdev.IPPROTO_TCP, netdev.IPPROTO_TLS: case netdev.IPPROTO_TCP, netdev.IPPROTO_TLS:
return w.sendTCP(socket.sock, buf, deadline) return w.sendTCP(sock, buf, deadline)
case netdev.IPPROTO_UDP: case netdev.IPPROTO_UDP:
return w.sendUDP(socket.sock, socket.raddr, buf, deadline) return w.sendUDP(sock, buf, deadline)
} }
return -1, netdev.ErrProtocolNotSupported return -1, netdev.ErrProtocolNotSupported
@@ -927,10 +871,7 @@ func (w *wifinina) Recv(sockfd int, buf []byte, flags int,
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok {
return -1, netdev.ErrInvalidSocketFd
}
// Limit max read size to chunk large read requests // Limit max read size to chunk large read requests
var max = len(buf) var max = len(buf)
@@ -951,22 +892,22 @@ func (w *wifinina) Recv(sockfd int, buf []byte, flags int,
// doesn't return unless there is data, even a single byte, or // doesn't return unless there is data, even a single byte, or
// on error such as timeout or EOF. // 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 n > 0 {
if debugging(debugNetdev) { if debugging(debugNetdev) {
fmt.Printf("[<--Recv] sockfd: %d, n: %d\r\n", fmt.Printf("[<--Recv] sockfd: %d, n: %d\r\n",
sockfd, n) sock, n)
} }
return n, nil return n, nil
} }
// Check if socket went down // Check if socket went down
if w.sockDown(socket) { if w.sockDown(sock) {
// Get any last bytes // Get any last bytes
n = int(w.getDataBuf(socket.sock, buf[:max])) n = int(w.getDataBuf(sock, buf[:max]))
if debugging(debugNetdev) { if debugging(debugNetdev) {
fmt.Printf("[<--Recv] sockfd: %d, n: %d, EOF\r\n", fmt.Printf("[<--Recv] sockfd: %d, n: %d, EOF\r\n",
sockfd, n) sock, n)
} }
if n > 0 { if n > 0 {
return n, io.EOF return n, io.EOF
@@ -995,18 +936,34 @@ func (w *wifinina) Close(sockfd int) error {
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
socket, ok := w.sockets[sockfd] var sock = sock(sockfd)
if !ok { var socket = w.sockets[sock]
return netdev.ErrInvalidSocketFd
}
if socket.clientConnected {
w.stopClient(socket.sock)
}
delete(w.sockets, sockfd)
if !socket.inuse {
return nil return nil
}
w.stopClient(sock)
if socket.protocol == netdev.IPPROTO_UDP {
socket.inuse = false
return nil
}
start := time.Now()
for time.Since(start) < 5*time.Second {
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 { func (w *wifinina) SetSockOpt(sockfd int, level int, opt int, value interface{}) error {