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
---
- **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)
}
+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/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
+1 -1
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
+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
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
-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
+4 -12
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
}
-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"
+98 -141
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
@@ -739,10 +685,9 @@ func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
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:
@@ -750,9 +695,8 @@ func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
return -1, netip.AddrPort{}, 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)
@@ -763,43 +707,48 @@ skip:
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
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
}
}
// 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
// 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 {
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 +776,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 +794,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 +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) {
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 +824,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 +871,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 +892,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 +936,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 {