mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-20 06:28:59 +00:00
Client driver for WiFiNINA firmware (#98)
* wifinina: implementation of WiFiNINA driver, including: - TCP client example is working - reading sockets and mqtt working - switched over to common net package also used by espat package - smoke tests and updated README for wifinina
This commit is contained in:
@@ -85,6 +85,10 @@ smoke-test:
|
|||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/tcpclient/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/webclient/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812/main.go
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bme280/main.go
|
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bme280/main.go
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ The following 34 devices are supported.
|
|||||||
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
|
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
|
||||||
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
||||||
| ["Easystepper" stepper motor controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
|
| ["Easystepper" stepper motor controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
|
||||||
|
| [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI |
|
||||||
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
|
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
|
||||||
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
|
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
|
||||||
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
|
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
|
||||||
|
// It creates an MQTT connection that publishes a message every second
|
||||||
|
// to an MQTT broker.
|
||||||
|
//
|
||||||
|
// In other words:
|
||||||
|
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> Internet <--> MQTT broker.
|
||||||
|
//
|
||||||
|
// You must install the Paho MQTT package to build this program:
|
||||||
|
//
|
||||||
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/net/mqtt"
|
||||||
|
"tinygo.org/x/drivers/wifinina"
|
||||||
|
)
|
||||||
|
|
||||||
|
// access point info
|
||||||
|
const ssid = ""
|
||||||
|
const pass = ""
|
||||||
|
|
||||||
|
// IP address of the MQTT broker to use. Replace with your own info.
|
||||||
|
const server = "tcp://test.mosquitto.org:1883"
|
||||||
|
|
||||||
|
//const server = "ssl://test.mosquitto.org:8883"
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
var (
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
uart = machine.UART2
|
||||||
|
tx = machine.NINA_TX
|
||||||
|
rx = machine.NINA_RX
|
||||||
|
spi = machine.NINA_SPI
|
||||||
|
|
||||||
|
// this is the ESP chip that has the WIFININA firmware flashed on it
|
||||||
|
adaptor = &wifinina.Device{
|
||||||
|
SPI: spi,
|
||||||
|
CS: machine.NINA_CS,
|
||||||
|
ACK: machine.NINA_ACK,
|
||||||
|
GPIO0: machine.NINA_GPIO0,
|
||||||
|
RESET: machine.NINA_RESETN,
|
||||||
|
}
|
||||||
|
|
||||||
|
console = machine.UART0
|
||||||
|
topic = "tinygo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
time.Sleep(3000 * time.Millisecond)
|
||||||
|
|
||||||
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||||
|
spi.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 8 * 1e6,
|
||||||
|
MOSI: machine.NINA_MOSI,
|
||||||
|
MISO: machine.NINA_MISO,
|
||||||
|
SCK: machine.NINA_SCK,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Init esp8266/esp32
|
||||||
|
adaptor.Configure()
|
||||||
|
|
||||||
|
connectToAP()
|
||||||
|
|
||||||
|
opts := mqtt.NewClientOptions()
|
||||||
|
opts.AddBroker(server).SetClientID("tinygo-client-" + randomString(10))
|
||||||
|
|
||||||
|
println("Connectng to MQTT...")
|
||||||
|
cl := mqtt.NewClient(opts)
|
||||||
|
if token := cl.Connect(); token.Wait() && token.Error() != nil {
|
||||||
|
failMessage(token.Error().Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
println("Publishing MQTT message...")
|
||||||
|
data := []byte(fmt.Sprintf(`{"e":[{"n":"hello %d","v":101}]}`, i))
|
||||||
|
token := cl.Publish(topic, 0, false, data)
|
||||||
|
token.Wait()
|
||||||
|
if err := token.Error(); err != nil {
|
||||||
|
switch t := err.(type) {
|
||||||
|
case wifinina.Error:
|
||||||
|
println(t.Error(), "attempting to reconnect")
|
||||||
|
if token := cl.Connect(); token.Wait() && token.Error() != nil {
|
||||||
|
failMessage(token.Error().Error())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right now this code is never reached. Need a way to trigger it...
|
||||||
|
println("Disconnecting MQTT...")
|
||||||
|
cl.Disconnect(100)
|
||||||
|
|
||||||
|
println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to access point
|
||||||
|
func connectToAP() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
println("Connecting to " + ssid)
|
||||||
|
adaptor.SetPassphrase(ssid, pass)
|
||||||
|
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||||
|
println("Connection status: " + st.String())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
st, _ = adaptor.GetConnectionStatus()
|
||||||
|
}
|
||||||
|
println("Connected.")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
ip, _, _, err := adaptor.GetIP()
|
||||||
|
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||||
|
println(err.Error())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
println(ip.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an int >= min, < max
|
||||||
|
func randomInt(min, max int) int {
|
||||||
|
return min + rand.Intn(max-min)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random string of A-Z chars with len = l
|
||||||
|
func randomString(len int) string {
|
||||||
|
bytes := make([]byte, len)
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
bytes[i] = byte(randomInt(65, 90))
|
||||||
|
}
|
||||||
|
return string(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func failMessage(msg string) {
|
||||||
|
for {
|
||||||
|
println(msg)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
|
||||||
|
// It creates an MQTT connection that publishes a message every second
|
||||||
|
// to an MQTT broker.
|
||||||
|
//
|
||||||
|
// In other words:
|
||||||
|
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> Internet <--> MQTT broker.
|
||||||
|
//
|
||||||
|
// You must also install the Paho MQTT package to build this program:
|
||||||
|
//
|
||||||
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/net/mqtt"
|
||||||
|
"tinygo.org/x/drivers/wifinina"
|
||||||
|
)
|
||||||
|
|
||||||
|
// access point info
|
||||||
|
const ssid = ""
|
||||||
|
const pass = ""
|
||||||
|
|
||||||
|
// IP address of the MQTT broker to use. Replace with your own info.
|
||||||
|
const server = "tcp://test.mosquitto.org:1883"
|
||||||
|
|
||||||
|
//const server = "ssl://test.mosquitto.org:8883"
|
||||||
|
|
||||||
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
var (
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
uart = machine.UART2
|
||||||
|
tx = machine.NINA_TX
|
||||||
|
rx = machine.NINA_RX
|
||||||
|
spi = machine.NINA_SPI
|
||||||
|
|
||||||
|
// this is the ESP chip that has the WIFININA firmware flashed on it
|
||||||
|
adaptor = &wifinina.Device{
|
||||||
|
SPI: spi,
|
||||||
|
CS: machine.NINA_CS,
|
||||||
|
ACK: machine.NINA_ACK,
|
||||||
|
GPIO0: machine.NINA_GPIO0,
|
||||||
|
RESET: machine.NINA_RESETN,
|
||||||
|
}
|
||||||
|
|
||||||
|
console = machine.UART0
|
||||||
|
|
||||||
|
cl mqtt.Client
|
||||||
|
topicTx = "tinygo/tx"
|
||||||
|
topicRx = "tinygo/rx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func subHandler(client mqtt.Client, msg mqtt.Message) {
|
||||||
|
fmt.Printf("[%s] ", msg.Topic())
|
||||||
|
fmt.Printf("%s\r\n", msg.Payload())
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
time.Sleep(3000 * time.Millisecond)
|
||||||
|
|
||||||
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||||
|
spi.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 8 * 1e6,
|
||||||
|
MOSI: machine.NINA_MOSI,
|
||||||
|
MISO: machine.NINA_MISO,
|
||||||
|
SCK: machine.NINA_SCK,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Init esp8266/esp32
|
||||||
|
adaptor.Configure()
|
||||||
|
|
||||||
|
connectToAP()
|
||||||
|
|
||||||
|
opts := mqtt.NewClientOptions()
|
||||||
|
opts.AddBroker(server).SetClientID("tinygo-client-" + randomString(10))
|
||||||
|
|
||||||
|
println("Connecting to MQTT broker at", server)
|
||||||
|
cl = mqtt.NewClient(opts)
|
||||||
|
if token := cl.Connect(); token.Wait() && token.Error() != nil {
|
||||||
|
failMessage(token.Error().Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe
|
||||||
|
token := cl.Subscribe(topicRx, 0, subHandler)
|
||||||
|
token.Wait()
|
||||||
|
if token.Error() != nil {
|
||||||
|
failMessage(token.Error().Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
go publishing()
|
||||||
|
|
||||||
|
select {}
|
||||||
|
|
||||||
|
// Right now this code is never reached. Need a way to trigger it...
|
||||||
|
println("Disconnecting MQTT...")
|
||||||
|
cl.Disconnect(100)
|
||||||
|
|
||||||
|
println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func publishing() {
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
println("Publishing MQTT message...")
|
||||||
|
data := []byte(fmt.Sprintf(`{"e":[{"n":"hello %d","v":101}]}`, i))
|
||||||
|
token := cl.Publish(topicRx, 0, false, data)
|
||||||
|
token.Wait()
|
||||||
|
if token.Error() != nil {
|
||||||
|
println(token.Error().Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to access point
|
||||||
|
func connectToAP() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
println("Connecting to " + ssid)
|
||||||
|
adaptor.SetPassphrase(ssid, pass)
|
||||||
|
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||||
|
println("Connection status: " + st.String())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
st, _ = adaptor.GetConnectionStatus()
|
||||||
|
}
|
||||||
|
println("Connected.")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
ip, _, _, err := adaptor.GetIP()
|
||||||
|
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||||
|
println(err.Error())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
println(ip.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an int >= min, < max
|
||||||
|
func randomInt(min, max int) int {
|
||||||
|
return min + rand.Intn(max-min)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random string of A-Z chars with len = l
|
||||||
|
func randomString(len int) string {
|
||||||
|
bytes := make([]byte, len)
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
bytes[i] = byte(randomInt(65, 90))
|
||||||
|
}
|
||||||
|
return string(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func failMessage(msg string) {
|
||||||
|
for {
|
||||||
|
println(msg)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// This example opens a TCP connection using a device with WiFiNINA firmware
|
||||||
|
// and sends some data, for the purpose of testing speed and connectivity.
|
||||||
|
//
|
||||||
|
// You can open a server to accept connections from this program using:
|
||||||
|
//
|
||||||
|
// nc -w 5 -lk 8080
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/net"
|
||||||
|
"tinygo.org/x/drivers/wifinina"
|
||||||
|
)
|
||||||
|
|
||||||
|
// access point info
|
||||||
|
const ssid = ""
|
||||||
|
const pass = ""
|
||||||
|
|
||||||
|
// IP address of the server aka "hub". Replace with your own info.
|
||||||
|
const serverIP = ""
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
var (
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
uart = machine.UART2
|
||||||
|
tx = machine.NINA_TX
|
||||||
|
rx = machine.NINA_RX
|
||||||
|
spi = machine.NINA_SPI
|
||||||
|
|
||||||
|
// this is the ESP chip that has the WIFININA firmware flashed on it
|
||||||
|
adaptor = &wifinina.Device{
|
||||||
|
SPI: spi,
|
||||||
|
CS: machine.NINA_CS,
|
||||||
|
ACK: machine.NINA_ACK,
|
||||||
|
GPIO0: machine.NINA_GPIO0,
|
||||||
|
RESET: machine.NINA_RESETN,
|
||||||
|
}
|
||||||
|
|
||||||
|
console = machine.UART0
|
||||||
|
)
|
||||||
|
|
||||||
|
var buf = &bytes.Buffer{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
|
||||||
|
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||||
|
spi.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 8 * 1e6,
|
||||||
|
MOSI: machine.NINA_MOSI,
|
||||||
|
MISO: machine.NINA_MISO,
|
||||||
|
SCK: machine.NINA_SCK,
|
||||||
|
})
|
||||||
|
|
||||||
|
adaptor.Configure()
|
||||||
|
|
||||||
|
connectToAP()
|
||||||
|
|
||||||
|
for {
|
||||||
|
sendBatch()
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendBatch() {
|
||||||
|
|
||||||
|
// make TCP connection
|
||||||
|
ip := net.ParseIP(serverIP)
|
||||||
|
raddr := &net.TCPAddr{IP: ip, Port: 8080}
|
||||||
|
laddr := &net.TCPAddr{Port: 8080}
|
||||||
|
|
||||||
|
message("---------------\r\nDialing TCP connection")
|
||||||
|
conn, err := net.DialTCP("tcp", laddr, raddr)
|
||||||
|
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
||||||
|
message(err.Error())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
w := 0
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// send data
|
||||||
|
message("Sending data")
|
||||||
|
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
buf.Reset()
|
||||||
|
fmt.Fprint(buf,
|
||||||
|
"\r---------------------------- i == ", i, " ----------------------------"+
|
||||||
|
"\r---------------------------- i == ", i, " ----------------------------")
|
||||||
|
if w, err = conn.Write(buf.Bytes()); err != nil {
|
||||||
|
println("error:", err.Error(), "\r")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n += w
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
ms := time.Now().Sub(start).Milliseconds()
|
||||||
|
fmt.Fprint(buf, "\nWrote ", n, " bytes in ", ms, " ms\r\n")
|
||||||
|
message(buf.String())
|
||||||
|
|
||||||
|
if _, err := conn.Write(buf.Bytes()); err != nil {
|
||||||
|
println("error:", err.Error(), "\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right now this code is never reached. Need a way to trigger it...
|
||||||
|
println("Disconnecting TCP...")
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to access point
|
||||||
|
func connectToAP() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
message("Connecting to " + ssid)
|
||||||
|
adaptor.SetPassphrase(ssid, pass)
|
||||||
|
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||||
|
message("Connection status: " + st.String())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
st, _ = adaptor.GetConnectionStatus()
|
||||||
|
}
|
||||||
|
message("Connected.")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
ip, _, _, err := adaptor.GetIP()
|
||||||
|
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||||
|
message(err.Error())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
message(ip.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func message(msg string) {
|
||||||
|
println(msg, "\r")
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// This example opens a TCP connection using a device with WiFiNINA firmware
|
||||||
|
// and sends a HTTP request to retrieve a webpage, based on the following
|
||||||
|
// Arduino example:
|
||||||
|
//
|
||||||
|
// https://github.com/arduino-libraries/WiFiNINA/blob/master/examples/WiFiWebClientRepeating/
|
||||||
|
//
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/net"
|
||||||
|
"tinygo.org/x/drivers/wifinina"
|
||||||
|
)
|
||||||
|
|
||||||
|
// access point info
|
||||||
|
const ssid = ""
|
||||||
|
const pass = ""
|
||||||
|
|
||||||
|
// IP address of the server aka "hub". Replace with your own info.
|
||||||
|
const server = "tinygo.org"
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
var (
|
||||||
|
|
||||||
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
|
uart = machine.UART2
|
||||||
|
tx = machine.NINA_TX
|
||||||
|
rx = machine.NINA_RX
|
||||||
|
spi = machine.NINA_SPI
|
||||||
|
|
||||||
|
// this is the ESP chip that has the WIFININA firmware flashed on it
|
||||||
|
adaptor = &wifinina.Device{
|
||||||
|
SPI: spi,
|
||||||
|
CS: machine.NINA_CS,
|
||||||
|
ACK: machine.NINA_ACK,
|
||||||
|
GPIO0: machine.NINA_GPIO0,
|
||||||
|
RESET: machine.NINA_RESETN,
|
||||||
|
}
|
||||||
|
|
||||||
|
console = machine.UART0
|
||||||
|
)
|
||||||
|
|
||||||
|
var buf [256]byte
|
||||||
|
|
||||||
|
var lastRequestTime time.Time
|
||||||
|
var conn net.Conn
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
|
||||||
|
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||||
|
spi.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 8 * 1e6,
|
||||||
|
MOSI: machine.NINA_MOSI,
|
||||||
|
MISO: machine.NINA_MISO,
|
||||||
|
SCK: machine.NINA_SCK,
|
||||||
|
})
|
||||||
|
|
||||||
|
adaptor.Configure()
|
||||||
|
|
||||||
|
connectToAP()
|
||||||
|
|
||||||
|
for {
|
||||||
|
loop()
|
||||||
|
}
|
||||||
|
println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loop() {
|
||||||
|
if conn != nil {
|
||||||
|
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
|
||||||
|
if err != nil {
|
||||||
|
println("Read error: " + err.Error())
|
||||||
|
} else {
|
||||||
|
print(string(buf[0:n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
|
||||||
|
makeHTTPRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeHTTPRequest() {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if conn != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// make TCP connection
|
||||||
|
ip := net.ParseIP(server)
|
||||||
|
raddr := &net.TCPAddr{IP: ip, Port: 80}
|
||||||
|
laddr := &net.TCPAddr{Port: 8080}
|
||||||
|
|
||||||
|
message("\r\n---------------\r\nDialing TCP connection")
|
||||||
|
conn, err = net.DialTCP("tcp", laddr, raddr)
|
||||||
|
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
||||||
|
message("connection failed: " + err.Error())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
println("Connected!\r")
|
||||||
|
|
||||||
|
print("Sending HTTP request...")
|
||||||
|
fmt.Fprintln(conn, "GET / HTTP/1.1")
|
||||||
|
fmt.Fprintln(conn, "Host:", server)
|
||||||
|
fmt.Fprintln(conn, "User-Agent: TinyGo/0.10.0")
|
||||||
|
fmt.Fprintln(conn, "Connection: close")
|
||||||
|
fmt.Fprintln(conn)
|
||||||
|
println("Sent!\r\n\r")
|
||||||
|
|
||||||
|
lastRequestTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
func readLine(conn *net.TCPSerialConn) string {
|
||||||
|
println("Attempting to read...\r")
|
||||||
|
b := buf[:]
|
||||||
|
for expiry := time.Now().Unix() + 10; time.Now().Unix() > expiry; {
|
||||||
|
if n, err := conn.Read(b); n > 0 && err == nil {
|
||||||
|
return string(b[0:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to access point
|
||||||
|
func connectToAP() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
message("Connecting to " + ssid)
|
||||||
|
adaptor.SetPassphrase(ssid, pass)
|
||||||
|
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||||
|
message("Connection status: " + st.String())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
st, _ = adaptor.GetConnectionStatus()
|
||||||
|
}
|
||||||
|
message("Connected.")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
ip, _, _, err := adaptor.GetIP()
|
||||||
|
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||||
|
message(err.Error())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
message(ip.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func message(msg string) {
|
||||||
|
println(msg, "\r")
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
WiFiNINA protocol
|
||||||
|
=================
|
||||||
|
|
||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
package wifinina
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ReadBufferSize = 128
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *Device) NewDriver() net.DeviceDriver {
|
||||||
|
return &Driver{dev: d, sock: NoSocketAvail}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Driver struct {
|
||||||
|
dev *Device
|
||||||
|
sock uint8
|
||||||
|
readBuf readBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
type readBuffer struct {
|
||||||
|
data [ReadBufferSize]byte
|
||||||
|
head int
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) GetDNS(domain string) (string, error) {
|
||||||
|
ipAddr, err := drv.dev.GetHostByName(domain)
|
||||||
|
return ipAddr.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) ConnectTCPSocket(addr, portStr string) error {
|
||||||
|
return drv.connectSocket(addr, portStr, ProtoModeTCP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) ConnectSSLSocket(addr, portStr string) error {
|
||||||
|
return drv.connectSocket(addr, portStr, ProtoModeTLS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error {
|
||||||
|
|
||||||
|
// convert port to uint16
|
||||||
|
p64, err := strconv.ParseUint(portStr, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not convert port to uint16: %s", err.Error())
|
||||||
|
}
|
||||||
|
port := uint16(p64)
|
||||||
|
|
||||||
|
// look up the hostname if necessary; if an IP address was specified, the
|
||||||
|
// same will be returned. Otherwise, an IPv4 for the hostname is returned.
|
||||||
|
ipAddr, err := drv.dev.GetHostByName(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ip := ipAddr.AsUint32()
|
||||||
|
|
||||||
|
// check to see if socket is already set; if so, stop it
|
||||||
|
if drv.sock != NoSocketAvail {
|
||||||
|
if err := drv.stop(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a socket from the device
|
||||||
|
if drv.sock, err = drv.dev.GetSocket(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to start the client
|
||||||
|
if err := drv.dev.StartClient(ip, port, drv.sock, mode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: this 4 second timeout is simply mimicking the Arduino driver
|
||||||
|
for t := newTimer(4 * time.Second); !t.Expired(); {
|
||||||
|
connected, err := drv.IsConnected()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if connected {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
wait(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrConnectionTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) ConnectUDPSocket(addr, sport, lport string) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) DisconnectSocket() error {
|
||||||
|
return drv.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) StartSocketSend(size int) error {
|
||||||
|
// not needed for WiFiNINA???
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) Response(timeout int) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) Write(b []byte) (n int, err error) {
|
||||||
|
if drv.sock == NoSocketAvail {
|
||||||
|
return 0, ErrNoSocketAvail
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
return 0, ErrNoData
|
||||||
|
}
|
||||||
|
written, err := drv.dev.SendData(b, drv.sock)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if written == 0 {
|
||||||
|
return 0, ErrDataNotWritten
|
||||||
|
}
|
||||||
|
if sent, _ := drv.dev.CheckDataSent(drv.sock); !sent {
|
||||||
|
return 0, ErrCheckDataError
|
||||||
|
}
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) ReadSocket(b []byte) (n int, err error) {
|
||||||
|
avail, err := drv.available()
|
||||||
|
if err != nil {
|
||||||
|
println("ReadSocket error: " + err.Error())
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if avail == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
length := len(b)
|
||||||
|
if avail < length {
|
||||||
|
length = avail
|
||||||
|
}
|
||||||
|
copy(b, drv.readBuf.data[drv.readBuf.head:drv.readBuf.head+length])
|
||||||
|
drv.readBuf.head += length
|
||||||
|
drv.readBuf.size -= length
|
||||||
|
return length, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSocketDataAvailable returns of there is socket data available
|
||||||
|
func (drv *Driver) IsSocketDataAvailable() bool {
|
||||||
|
n, err := drv.available()
|
||||||
|
return err == nil && n > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) available() (int, error) {
|
||||||
|
if drv.readBuf.size == 0 {
|
||||||
|
n, err := drv.dev.GetDataBuf(drv.sock, drv.readBuf.data[:])
|
||||||
|
if n > 0 {
|
||||||
|
drv.readBuf.head = 0
|
||||||
|
drv.readBuf.size = n
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drv.readBuf.size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) IsConnected() (bool, error) {
|
||||||
|
if drv.sock == NoSocketAvail {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
s, err := drv.status()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
isConnected := !(s == TCPStateListen || s == TCPStateClosed ||
|
||||||
|
s == TCPStateFinWait1 || s == TCPStateFinWait2 || s == TCPStateTimeWait ||
|
||||||
|
s == TCPStateSynSent || s == TCPStateSynRcvd || s == TCPStateCloseWait)
|
||||||
|
// TODO: investigate if the below is necessary (as per Arduino driver)
|
||||||
|
//if !isConnected {
|
||||||
|
// //close socket buffer?
|
||||||
|
// WiFiSocketBuffer.close(_sock);
|
||||||
|
// _sock = 255;
|
||||||
|
//}
|
||||||
|
return isConnected, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) status() (uint8, error) {
|
||||||
|
if drv.sock == NoSocketAvail {
|
||||||
|
return TCPStateClosed, nil
|
||||||
|
}
|
||||||
|
return drv.dev.GetClientState(drv.sock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drv *Driver) stop() error {
|
||||||
|
if drv.sock == NoSocketAvail {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
drv.dev.StopClient(drv.sock)
|
||||||
|
for t := newTimer(5 * time.Second); !t.Expired(); {
|
||||||
|
st, _ := drv.status()
|
||||||
|
if st == TCPStateClosed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// FIXME: without the time.Sleep below this blocks until TCPStateClosed,
|
||||||
|
// however with it got goroutine stack overflows; not sure if this is still
|
||||||
|
// an issue so should investigate further
|
||||||
|
//time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
drv.sock = NoSocketAvail
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package wifinina
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func wait(duration time.Duration) {
|
||||||
|
newTimer(duration).WaitUntilExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
type timer struct {
|
||||||
|
start int64
|
||||||
|
interval int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTimer(interval time.Duration) timer {
|
||||||
|
return timer{
|
||||||
|
start: time.Now().UnixNano(),
|
||||||
|
interval: int64(interval),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t timer) Expired() bool {
|
||||||
|
return time.Now().UnixNano() > (t.start + t.interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t timer) WaitUntilExpired() {
|
||||||
|
for !t.Expired() {
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user