mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-23 07:59:01 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3d0697dbc | |||
| 9b5840e3cd |
@@ -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,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
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[](https://pkg.go.dev/tinygo.org/x/drivers) [](https://github.com/tinygo-org/drivers/actions/workflows/build.yml)
|
[](https://pkg.go.dev/tinygo.org/x/drivers) [](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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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
@@ -218,8 +218,8 @@ func (d *Device) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) Accept(sockfd int) (int, netip.AddrPort, error) {
|
func (d *Device) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
||||||
return -1, netip.AddrPort{}, netdev.ErrNotSupported
|
return -1, netdev.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -30,18 +30,16 @@ var (
|
|||||||
var buf [1024]byte
|
var buf [1024]byte
|
||||||
|
|
||||||
func echo(conn net.Conn) {
|
func echo(conn net.Conn) {
|
||||||
println("Client", conn.RemoteAddr(), "connected")
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_, err := io.CopyBuffer(conn, conn, buf[:])
|
_, err := io.CopyBuffer(conn, conn, buf[:])
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
println("Client", conn.RemoteAddr(), "closed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
link, _ := probe.Probe()
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
@@ -53,7 +51,6 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Starting TCP server listening on", port)
|
|
||||||
l, err := net.Listen("tcp", port)
|
l, err := net.Listen("tcp", port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
-112
@@ -236,83 +236,16 @@ func (d *Device) getMode() (byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) configRate(speed, clock byte) error {
|
func (d *Device) configRate(speed, clock byte) error {
|
||||||
|
// TODO: add another baudrate
|
||||||
var cfg1, cfg2, cfg3 byte
|
var cfg1, cfg2, cfg3 byte
|
||||||
set := true
|
set := true
|
||||||
switch clock {
|
switch clock {
|
||||||
case Clock16MHz:
|
case Clock16MHz:
|
||||||
switch speed {
|
switch speed {
|
||||||
case CAN5kBps:
|
|
||||||
cfg1 = mcp16mHz5kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz5kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz5kBpsCfg3
|
|
||||||
case CAN10kBps:
|
|
||||||
cfg1 = mcp16mHz10kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz10kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz10kBpsCfg3
|
|
||||||
case CAN20kBps:
|
|
||||||
cfg1 = mcp16mHz20kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz20kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz20kBpsCfg3
|
|
||||||
case CAN25kBps:
|
|
||||||
cfg1 = mcp16mHz25kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz25kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz25kBpsCfg3
|
|
||||||
case CAN31k25Bps:
|
|
||||||
cfg1 = mcp16mHz31k25BpsCfg1
|
|
||||||
cfg2 = mcp16mHz31k25BpsCfg2
|
|
||||||
cfg3 = mcp16mHz31k25BpsCfg3
|
|
||||||
case CAN33kBps:
|
|
||||||
cfg1 = mcp16mHz33kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz33kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz33kBpsCfg3
|
|
||||||
case CAN40kBps:
|
|
||||||
cfg1 = mcp16mHz40kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz40kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz40kBpsCfg3
|
|
||||||
case CAN47kBps:
|
|
||||||
cfg1 = mcp16mHz47kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz47kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz47kBpsCfg3
|
|
||||||
case CAN50kBps:
|
|
||||||
cfg1 = mcp16mHz50kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz50kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz50kBpsCfg3
|
|
||||||
case CAN80kBps:
|
|
||||||
cfg1 = mcp16mHz80kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz80kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz80kBpsCfg3
|
|
||||||
case CAN83k3Bps:
|
|
||||||
cfg1 = mcp16mHz83k3BpsCfg1
|
|
||||||
cfg2 = mcp16mHz83k3BpsCfg2
|
|
||||||
cfg3 = mcp16mHz83k3BpsCfg3
|
|
||||||
case CAN95kBps:
|
|
||||||
cfg1 = mcp16mHz95kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz95kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz95kBpsCfg3
|
|
||||||
case CAN100kBps:
|
|
||||||
cfg1 = mcp16mHz100kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz100kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz100kBpsCfg3
|
|
||||||
case CAN125kBps:
|
|
||||||
cfg1 = mcp16mHz125kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz125kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz125kBpsCfg3
|
|
||||||
case CAN200kBps:
|
|
||||||
cfg1 = mcp16mHz200kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz200kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz200kBpsCfg3
|
|
||||||
case CAN250kBps:
|
|
||||||
cfg1 = mcp16mHz250kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz250kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz250kBpsCfg3
|
|
||||||
case CAN500kBps:
|
case CAN500kBps:
|
||||||
cfg1 = mcp16mHz500kBpsCfg1
|
cfg1 = mcp16mHz500kBpsCfg1
|
||||||
cfg2 = mcp16mHz500kBpsCfg2
|
cfg2 = mcp16mHz500kBpsCfg2
|
||||||
cfg3 = mcp16mHz500kBpsCfg3
|
cfg3 = mcp16mHz500kBpsCfg3
|
||||||
case CAN666kBps:
|
|
||||||
cfg1 = mcp16mHz666kBpsCfg1
|
|
||||||
cfg2 = mcp16mHz666kBpsCfg2
|
|
||||||
cfg3 = mcp16mHz666kBpsCfg3
|
|
||||||
case CAN1000kBps:
|
case CAN1000kBps:
|
||||||
cfg1 = mcp16mHz1000kBpsCfg1
|
cfg1 = mcp16mHz1000kBpsCfg1
|
||||||
cfg2 = mcp16mHz1000kBpsCfg2
|
cfg2 = mcp16mHz1000kBpsCfg2
|
||||||
@@ -322,50 +255,6 @@ func (d *Device) configRate(speed, clock byte) error {
|
|||||||
}
|
}
|
||||||
case Clock8MHz:
|
case Clock8MHz:
|
||||||
switch speed {
|
switch speed {
|
||||||
case CAN5kBps:
|
|
||||||
cfg1 = mcp8mHz5kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz5kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz5kBpsCfg3
|
|
||||||
case CAN10kBps:
|
|
||||||
cfg1 = mcp8mHz10kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz10kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz10kBpsCfg3
|
|
||||||
case CAN20kBps:
|
|
||||||
cfg1 = mcp8mHz20kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz20kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz20kBpsCfg3
|
|
||||||
case CAN31k25Bps:
|
|
||||||
cfg1 = mcp8mHz31k25BpsCfg1
|
|
||||||
cfg2 = mcp8mHz31k25BpsCfg2
|
|
||||||
cfg3 = mcp8mHz31k25BpsCfg3
|
|
||||||
case CAN40kBps:
|
|
||||||
cfg1 = mcp8mHz40kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz40kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz40kBpsCfg3
|
|
||||||
case CAN50kBps:
|
|
||||||
cfg1 = mcp8mHz50kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz50kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz50kBpsCfg3
|
|
||||||
case CAN80kBps:
|
|
||||||
cfg1 = mcp8mHz80kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz80kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz80kBpsCfg3
|
|
||||||
case CAN100kBps:
|
|
||||||
cfg1 = mcp8mHz100kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz100kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz100kBpsCfg3
|
|
||||||
case CAN125kBps:
|
|
||||||
cfg1 = mcp8mHz125kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz125kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz125kBpsCfg3
|
|
||||||
case CAN200kBps:
|
|
||||||
cfg1 = mcp8mHz200kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz200kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz200kBpsCfg3
|
|
||||||
case CAN250kBps:
|
|
||||||
cfg1 = mcp8mHz250kBpsCfg1
|
|
||||||
cfg2 = mcp8mHz250kBpsCfg2
|
|
||||||
cfg3 = mcp8mHz250kBpsCfg3
|
|
||||||
case CAN500kBps:
|
case CAN500kBps:
|
||||||
cfg1 = mcp8mHz500kBpsCfg1
|
cfg1 = mcp8mHz500kBpsCfg1
|
||||||
cfg2 = mcp8mHz500kBpsCfg2
|
cfg2 = mcp8mHz500kBpsCfg2
|
||||||
|
|||||||
+1
-2
@@ -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
|
||||||
@@ -83,7 +82,7 @@ type Netdever interface {
|
|||||||
Bind(sockfd int, ip netip.AddrPort) error
|
Bind(sockfd int, ip netip.AddrPort) error
|
||||||
Connect(sockfd int, host string, ip netip.AddrPort) error
|
Connect(sockfd int, host string, ip netip.AddrPort) error
|
||||||
Listen(sockfd int, backlog int) 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)
|
Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
|
||||||
Recv(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
|
Close(sockfd int) error
|
||||||
|
|||||||
@@ -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,4 +1,4 @@
|
|||||||
//go:build ninafw && !arduino_mkrwifi1010
|
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || matrixportal_m4
|
||||||
|
|
||||||
package probe
|
package probe
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,54 @@ func (img Image[T]) LimitHeight(height int) Image[T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split the buffer into two buffers that can be used independently.
|
||||||
|
// The top half is split just like LimitHeight. The bottom half is made out of
|
||||||
|
// the remaining buffer area and can be zero. The topHeight parameter must not
|
||||||
|
// be larger than the height of the buffer.
|
||||||
|
//
|
||||||
|
// Always check the height of the bottom half: it may be zero due to alignment
|
||||||
|
// issues.
|
||||||
|
func (img Image[T]) Split(topHeight int) (top, bottom Image[T]) {
|
||||||
|
if topHeight < 0 || topHeight > int(img.height) {
|
||||||
|
panic("Image.Split: out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The top half of the buffer, the same as LimitHeight.
|
||||||
|
top = Image[T]{
|
||||||
|
width: img.width,
|
||||||
|
height: int16(topHeight),
|
||||||
|
data: img.data,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the bottom half of the buffer.
|
||||||
|
// This is a bit more complicated since it's possible that the bottom half
|
||||||
|
// can't have all the other bytes: the top half pixels might cross a byte
|
||||||
|
// boundary (for example with RGB444). So instead we calculate the size of
|
||||||
|
// the buffer we have, the size of the buffer that the top half will use
|
||||||
|
// (which is rounded up to a byte boundary), and then calculate the
|
||||||
|
// remaining bytes at the bottom.
|
||||||
|
// In practice, I expect it's unlikely that the top half will cross a byte
|
||||||
|
// boundary since a typical split buffer will have a width that's a nice
|
||||||
|
// round number, but it's possible so we have to avoid this edge case.
|
||||||
|
var zeroColor T
|
||||||
|
dataBytes := (int(img.width)*int(img.height)*zeroColor.BitsPerPixel() + 7) / 8
|
||||||
|
topDataBytes := (int(img.width)*int(topHeight)*zeroColor.BitsPerPixel() + 7) / 8
|
||||||
|
bottomDataBytes := dataBytes - topDataBytes
|
||||||
|
if bottomDataBytes < 0 {
|
||||||
|
// No buffer remaining (not sure whether this is possible in practice
|
||||||
|
// but guarding just in case).
|
||||||
|
bottomDataBytes = 0
|
||||||
|
}
|
||||||
|
bottomHeight := (bottomDataBytes * 8 / zeroColor.BitsPerPixel()) / int(img.width)
|
||||||
|
bottom = Image[T]{
|
||||||
|
width: img.width,
|
||||||
|
height: int16(bottomHeight),
|
||||||
|
data: unsafe.Add(img.data, topDataBytes),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Len returns the number of pixels in this image buffer.
|
// Len returns the number of pixels in this image buffer.
|
||||||
func (img Image[T]) Len() int {
|
func (img Image[T]) Len() int {
|
||||||
return int(img.width) * int(img.height)
|
return int(img.width) * int(img.height)
|
||||||
|
|||||||
+10
-32
@@ -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
|
||||||
}
|
}
|
||||||
@@ -445,12 +437,6 @@ func ipToName(ip netip.AddrPort) []byte {
|
|||||||
return name
|
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 {
|
func (r *rtl8720dn) Bind(sockfd int, ip netip.AddrPort) error {
|
||||||
|
|
||||||
if debugging(debugNetdev) {
|
if debugging(debugNetdev) {
|
||||||
@@ -548,10 +534,10 @@ func (r *rtl8720dn) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
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) {
|
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()
|
r.mu.Lock()
|
||||||
@@ -560,12 +546,12 @@ func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
|
|||||||
var newSock int32
|
var newSock int32
|
||||||
var lsock = sock(sockfd)
|
var lsock = sock(sockfd)
|
||||||
var socket = r.sockets[lsock]
|
var socket = r.sockets[lsock]
|
||||||
var name = ipToName(netip.AddrPort{})
|
var name = ipToName(ip)
|
||||||
|
|
||||||
switch socket.protocol {
|
switch socket.protocol {
|
||||||
case netdev.IPPROTO_TCP:
|
case netdev.IPPROTO_TCP:
|
||||||
default:
|
default:
|
||||||
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
|
return -1, netdev.ErrProtocolNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -584,14 +570,6 @@ func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
|
|||||||
continue
|
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
|
// If we've already seen this socket, we can re-use
|
||||||
// the socket and return it. But, only if the socket
|
// the socket and return it. But, only if the socket
|
||||||
// is closed. If it's not closed, we'll just come back
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
// Reuse client socket
|
// Reuse client socket
|
||||||
return int(newSock), raddr, nil
|
return int(newSock), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new socket for client and return fd
|
// Create new socket for client and return fd
|
||||||
r.sockets[sock(newSock)] = newSocket(socket.protocol)
|
r.sockets[sock(newSock)] = newSocket(socket.protocol)
|
||||||
return int(newSock), raddr, nil
|
return int(newSock), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -11,3 +11,12 @@ type SPI interface {
|
|||||||
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
||||||
Transfer(b byte) (byte, error)
|
Transfer(b byte) (byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncSPI is a SPI bus that also implements async operations (using DMA,
|
||||||
|
// probably).
|
||||||
|
type AsyncSPI interface {
|
||||||
|
SPI
|
||||||
|
IsAsync() bool
|
||||||
|
StartTx(tx, rx []byte) error
|
||||||
|
Wait() error
|
||||||
|
}
|
||||||
|
|||||||
+4
-26
@@ -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)
|
||||||
|
|||||||
+48
-3
@@ -45,7 +45,7 @@ type Device = DeviceOf[pixel.RGB565BE]
|
|||||||
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
||||||
// formats.
|
// formats.
|
||||||
type DeviceOf[T Color] struct {
|
type DeviceOf[T Color] struct {
|
||||||
bus drivers.SPI
|
bus drivers.AsyncSPI
|
||||||
dcPin machine.Pin
|
dcPin machine.Pin
|
||||||
resetPin machine.Pin
|
resetPin machine.Pin
|
||||||
csPin machine.Pin
|
csPin machine.Pin
|
||||||
@@ -83,13 +83,13 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
func New(bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
||||||
// wire must already be configured.
|
// wire must already be configured.
|
||||||
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
func NewOf[T Color](bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
||||||
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
@@ -404,6 +404,51 @@ func (d *DeviceOf[T]) DrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
|||||||
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAsync returns whether the underlying SPI bus supports async operations.
|
||||||
|
func (d *DeviceOf[T]) IsAsync() bool {
|
||||||
|
return d.bus.IsAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartDrawBitmap starts sending the given bitmap to the screen.
|
||||||
|
// After calling StartDrawBitmap, you can only call Wait() or another
|
||||||
|
// StartDrawBitmap. Calling any other method may result in incorrect behavior.
|
||||||
|
// The bitmap passed to StartDrawBitmap may not be written to until Wait() has
|
||||||
|
// been called.
|
||||||
|
func (d *DeviceOf[T]) StartDrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
||||||
|
// Check that the provided buffer is drawn entirely inside the image.
|
||||||
|
width, height := bitmap.Size()
|
||||||
|
displayWidth, displayHeight := d.Size()
|
||||||
|
if uint(int(x)+width) > uint(int(displayWidth)) || uint(int(y)+height) > uint(int(displayHeight)) {
|
||||||
|
return errOutOfBounds
|
||||||
|
}
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
return nil // no bitmap to send
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the previous buffer has been fully sent.
|
||||||
|
err := d.bus.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the next buffer.
|
||||||
|
d.startWrite()
|
||||||
|
d.setWindow(x, y, int16(width), int16(height))
|
||||||
|
d.bus.StartTx(bitmap.RawBuffer(), nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all previous transfers have completed. After this call, the bitmap
|
||||||
|
// passed to StartDrawBitmap can be reused.
|
||||||
|
func (d *DeviceOf[T]) Wait() error {
|
||||||
|
err := d.bus.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.endWrite()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
||||||
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
||||||
i, j := d.Size()
|
i, j := d.Size()
|
||||||
|
|||||||
+1
-1
@@ -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"
|
||||||
|
|||||||
+99
-161
@@ -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
|
||||||
@@ -730,29 +676,27 @@ func (w *wifinina) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
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) {
|
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()
|
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:
|
||||||
default:
|
default:
|
||||||
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
|
return -1, 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)
|
||||||
@@ -760,46 +704,49 @@ skip:
|
|||||||
|
|
||||||
// Check if we've faulted
|
// Check if we've faulted
|
||||||
if w.fault != nil {
|
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
|
// 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
|
// If we've already seen this socket, we can reuse
|
||||||
for _, s := range w.sockets {
|
// the socket and return it. But, only if the socket
|
||||||
if s.sock == client {
|
// is closed. If it's not closed, we'll just come back
|
||||||
continue skip
|
// 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
|
// Create new socket for client and return fd
|
||||||
clientfd := w.newSockfd()
|
w.sockets[client] = newSocket(socket.protocol)
|
||||||
if clientfd == -1 {
|
return int(client), nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +774,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 +792,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 +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) {
|
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 +822,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 +869,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 +890,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 +934,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.inuse {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if socket.clientConnected {
|
w.stopClient(sock)
|
||||||
w.stopClient(socket.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 {
|
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
|
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
|
// insertDataBuf adds data to the buffer used for sending UDP data
|
||||||
func (w *wifinina) insertDataBuf(sock sock, buf []byte) bool {
|
func (w *wifinina) insertDataBuf(sock sock, buf []byte) bool {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user