mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-18 21:53:56 +00:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31f09d93b8 | |||
| 0ea969f25a | |||
| 8665d44e0f | |||
| c344e5d879 | |||
| 308763f500 | |||
| c41f2e472d | |||
| aa7bd47c68 | |||
| e7931c6a22 | |||
| 3c5e17423a | |||
| 0262122ccd | |||
| 7d24c3c285 | |||
| 5c0f0480bc | |||
| 8642886f73 | |||
| 1a96fc4547 | |||
| 3fabdc5c96 | |||
| a8928d137e | |||
| 709fc77960 | |||
| d6ae0b0d8b | |||
| 7a7235f83b | |||
| 3089bf8b1b | |||
| 196d1dd58d | |||
| 1fd8a768ae | |||
| 8238f96319 | |||
| e7d51d3c73 | |||
| 4bf631a7e3 | |||
| 3c4df6e811 | |||
| 255c639ad4 | |||
| 276feecc20 | |||
| 00b1b4fbfb | |||
| 3b183ad6ed | |||
| 68da68c8c8 | |||
| f7b80ef95a | |||
| 933c9e127d | |||
| 92050d90da | |||
| 93cbba5d8b | |||
| 6cf07aff4c | |||
| af33129f41 | |||
| 100aadf585 | |||
| 4a9667ffef | |||
| f96a70915e | |||
| 3e64e754a2 | |||
| 2c2da5c7bb | |||
| 14994a3f31 | |||
| 47dfeb9e94 | |||
| f20d1759d3 | |||
| 6b79a1b386 | |||
| 7dd1067cc1 | |||
| 4edb771c5b | |||
| e95cfe66c1 | |||
| 4edb58c0c5 | |||
| f384e2db48 | |||
| 7c96387845 | |||
| 182d4c6ebb | |||
| dc2de4f9ed | |||
| 36a12dd7a2 | |||
| 00992756eb | |||
| 715c33d4b0 | |||
| fd21e6ac9b | |||
| 485ed702c8 | |||
| cfa50fd3c2 | |||
| 5888bb2ded |
+120
@@ -1,3 +1,123 @@
|
|||||||
|
0.27.0
|
||||||
|
---
|
||||||
|
- **core**
|
||||||
|
- prepare for CGo changes in TinyGo
|
||||||
|
|
||||||
|
- **new devices**
|
||||||
|
- **adafruit4650**
|
||||||
|
- support for Adafruit 4650 feather OLED
|
||||||
|
- **net**
|
||||||
|
- new networking support based on tinygo net package
|
||||||
|
- **pixel**
|
||||||
|
- add package for efficiently working with raw pixel buffers
|
||||||
|
- **rotary**
|
||||||
|
- Adding driver for rotary encoder support
|
||||||
|
- **seesaw**
|
||||||
|
- Adding support for Adafruit Seesaw platform
|
||||||
|
- **sgp30**
|
||||||
|
- add SGP30 air quality sensor
|
||||||
|
- **sk6812**
|
||||||
|
- added support for SK6812 to WS2812 device (#610)
|
||||||
|
|
||||||
|
- **enhancements**
|
||||||
|
- **epd2in13**
|
||||||
|
- add Sleep method like other displays
|
||||||
|
- unify rotation configuration with other displays
|
||||||
|
- use better black/white approximation
|
||||||
|
- **ili9341**
|
||||||
|
- add DrawBitmap method
|
||||||
|
- **lora/lorawan**
|
||||||
|
- LoRa WAN US915 Support
|
||||||
|
- LoRa WAN add setter functions
|
||||||
|
- refactor shared functionality for channels/regions
|
||||||
|
- **mcp2515**
|
||||||
|
- Add more line speeds to mcp2515.go (#626)
|
||||||
|
- **rtl8720dn**
|
||||||
|
- use drivers package version as the driver version
|
||||||
|
- **ssd1306**
|
||||||
|
- improvements needed for Thumby SPI display
|
||||||
|
- **st7735**
|
||||||
|
- make the display generic over RGB565 and RGB444
|
||||||
|
- **st7789**
|
||||||
|
- add DrawBitmap method
|
||||||
|
- make the display generic over RGB565 and RGB444
|
||||||
|
- **wifinina**
|
||||||
|
- add ResetIsHigh cfg switch for MKR 1010 (copied from #561)
|
||||||
|
- maintenence. Also see PR #4085 in the main TinyGo repo
|
||||||
|
- use drivers package version as the driver version
|
||||||
|
|
||||||
|
- **bugfixes**
|
||||||
|
- **adxl345**
|
||||||
|
- Use int16 for ADXL345 readings (#656)
|
||||||
|
- **at24cx**
|
||||||
|
- fixed the description of the device struct
|
||||||
|
- **rtl8720dn**
|
||||||
|
- allow connecting to open wifi access points
|
||||||
|
- fix check for bad Wifi connect
|
||||||
|
- **sh1106**
|
||||||
|
- fix I2C interface and add smoketest
|
||||||
|
- fixed the description of the device struct
|
||||||
|
- **wifinina**
|
||||||
|
- add 'unknown failure' reason code for AP connect
|
||||||
|
- fix concurrency issues with multiple sockets
|
||||||
|
- fix wifinina UDP send
|
||||||
|
|
||||||
|
- **examples**
|
||||||
|
- **ds3231**
|
||||||
|
- fix the description in the example
|
||||||
|
- **lorawan**
|
||||||
|
- add missing functions for simulated interface
|
||||||
|
- modify atcmd and basic demo to support choosing any one of the supported regions at compile time by using ldflags
|
||||||
|
- **net**
|
||||||
|
- all networking examples now using netdev and netlink.
|
||||||
|
|
||||||
|
- **build**
|
||||||
|
- **all**
|
||||||
|
- fix broken testrunner
|
||||||
|
- migrated legacy I2C
|
||||||
|
- add natiu package for tests
|
||||||
|
- **smoketest**
|
||||||
|
- add stack-size param for net tests.
|
||||||
|
- allow stack-size flag as it is needed for net examples
|
||||||
|
|
||||||
|
|
||||||
|
0.26.0
|
||||||
|
---
|
||||||
|
- **core**
|
||||||
|
- i2c iface refactor: Resolve #559
|
||||||
|
- fix uses of legacy i2c WriteRegister calls
|
||||||
|
- add correct Tx implementation for mock I2C interfaces
|
||||||
|
- bump golang.org/x/net version
|
||||||
|
|
||||||
|
- **new devices**
|
||||||
|
- **bma42x**
|
||||||
|
- add new BMA421/BMA425 driver
|
||||||
|
- **ndir**
|
||||||
|
- add Sandbox Electronics NDIR CO2 sensor driver (#580)
|
||||||
|
- **mpu9150**
|
||||||
|
- implement driver for Mpu9150 (#596)
|
||||||
|
- **sht4x**
|
||||||
|
- implement driver for sht4x (#597)
|
||||||
|
- **pcf8523**
|
||||||
|
- implement driver for pcf8523 (#599)
|
||||||
|
|
||||||
|
- **enhancements**
|
||||||
|
- **ssd1306**
|
||||||
|
- improve bus error handling
|
||||||
|
|
||||||
|
- **bugfixes**
|
||||||
|
- **st7789**
|
||||||
|
- fix scrolling when rotated by 180°
|
||||||
|
- **st7789**
|
||||||
|
- fix incorrect Rotation configuration
|
||||||
|
- fix SetScrollArea
|
||||||
|
- **ili9341**
|
||||||
|
- fix SetScrollArea
|
||||||
|
|
||||||
|
- **build**
|
||||||
|
- use latest tag of tinygo-dev container for running tests
|
||||||
|
|
||||||
|
|
||||||
0.25.0
|
0.25.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
Copyright (c) 2018-2024 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
|
||||||
|
|||||||
+233
@@ -0,0 +1,233 @@
|
|||||||
|
### Table of Contents
|
||||||
|
|
||||||
|
- ["net" Package](#net-package)
|
||||||
|
- [Using "net" Package](#using-net-package)
|
||||||
|
- [Using "net/http" Package](#using-nethttp-package)
|
||||||
|
- [Using "crypto/tls" Package](#using-cryptotls-package)
|
||||||
|
- [Using Sockets](#using-sockets)
|
||||||
|
|
||||||
|
## "net" Package
|
||||||
|
|
||||||
|
TinyGo's "net" package is ported from Go. The port offers a subset of Go's
|
||||||
|
"net" package. The subset maintains Go 1 compatiblity guarantee. A Go
|
||||||
|
application that uses "net" will most-likey just work on TinyGo if the usage is
|
||||||
|
within the subset offered. (There may be external constraints such as limited
|
||||||
|
SRAM on some targets that may limit full "net" functionality).
|
||||||
|
|
||||||
|
Continue below for details on using "net" and "net/http" packages.
|
||||||
|
|
||||||
|
See src/net/READMD.md in the TinyGo repo for more details on maintaining
|
||||||
|
TinyGo's "net" package.
|
||||||
|
|
||||||
|
## Using "net" Package
|
||||||
|
|
||||||
|
Ideally, TinyGo's "net" package would be Go's "net" package and applications
|
||||||
|
using "net" would just work, as-is. TinyGo's net package is a partial port of
|
||||||
|
Go's net package, so some things may not work because they have not been
|
||||||
|
ported.
|
||||||
|
|
||||||
|
There are a few features excluded during the porting process, in particular:
|
||||||
|
|
||||||
|
- No IPv6 support
|
||||||
|
- No DualStack support
|
||||||
|
|
||||||
|
Run ```go doc -all ./src/net``` in TinyGo repo to see full listing of what has
|
||||||
|
been ported. Here is a list of things known to work. You can find examples
|
||||||
|
of these at [examples/net](examples/net/).
|
||||||
|
|
||||||
|
### What is Known to Work
|
||||||
|
|
||||||
|
(These are all IPv4 only).
|
||||||
|
|
||||||
|
- TCP client and server
|
||||||
|
- UDP client
|
||||||
|
- TLS client
|
||||||
|
- HTTP client and server
|
||||||
|
- HTTPS client
|
||||||
|
- NTP client (UDP)
|
||||||
|
- MQTT client (paho & natiu)
|
||||||
|
- WebSocket client and server
|
||||||
|
|
||||||
|
Multiple sockets can be opened in a single app. For example, the app could run
|
||||||
|
as an http server listen on port :80 and also use NTP to get the current time
|
||||||
|
or send something over MQTT. There is a practical limit to the number of
|
||||||
|
active sockets per app, around 8 or 10, so don't go crazy.
|
||||||
|
|
||||||
|
Applications using Go's net package will need a few setup steps to work with
|
||||||
|
TinyGo's net package. The steps are required before using "net".
|
||||||
|
|
||||||
|
### Step 1: Probe to Load Network Driver
|
||||||
|
|
||||||
|
Call Probe() to load the correct network driver for your target. Probe()
|
||||||
|
allows the app to work on multiple targets.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// load network driver for target
|
||||||
|
link, dev := probe.Probe()
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Probe() will load the driver with default configuration for the target. For
|
||||||
|
custom configuration, the app can open code Probe() for the target
|
||||||
|
requirements.
|
||||||
|
|
||||||
|
Probe() returns a [Netlinker](netlink/README.md) and a
|
||||||
|
[Netdever](netdev/README.md), interfaces implemented by the network driver.
|
||||||
|
Next, we'll use the Netlinker interface to connect the target to an IP network.
|
||||||
|
|
||||||
|
### Step 2: Connect to an IP Network
|
||||||
|
|
||||||
|
Before the net package is fully functional, we need to connect the target to an
|
||||||
|
IP network.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// load network driver for target
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
// Connect target to IP network
|
||||||
|
link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: "my SSID",
|
||||||
|
Passphrase: "my passphrase",
|
||||||
|
})
|
||||||
|
|
||||||
|
// OK to use "net" from here on
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, get notified of IP network connects and disconnects:
|
||||||
|
|
||||||
|
```go
|
||||||
|
link.Notify(func(e netlink.Event) {
|
||||||
|
switch e {
|
||||||
|
case netlink.EventNetUp: println("Network UP")
|
||||||
|
case netlink.EventNetDown: println("Network DOWN")
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example of an http server listening on port :8080:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// load network driver for target
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
// Connect target to IP network
|
||||||
|
link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: "my SSID",
|
||||||
|
Passphrase: "my passphrase",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Serve it up
|
||||||
|
http.HandleFunc("/", HelloServer)
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using "net/http" Package
|
||||||
|
|
||||||
|
TinyGo's net/http package is a partial port of Go's net/http package, providing
|
||||||
|
a subset of the full net/http package. There are a few features excluded
|
||||||
|
during the porting process, in particular:
|
||||||
|
|
||||||
|
- No HTTP/2 support
|
||||||
|
- No TLS support for HTTP servers (no https servers)
|
||||||
|
- HTTP client request can't be reused
|
||||||
|
|
||||||
|
HTTP client methods (http.Get, http.Head, http.Post, and http.PostForm) are
|
||||||
|
functional. Dial clients support both HTTP and HTTPS URLs.
|
||||||
|
|
||||||
|
HTTP server methods and objects are mostly ported, but for HTTP only; HTTPS
|
||||||
|
servers are not supported.
|
||||||
|
|
||||||
|
HTTP request and response handling code is mostly ported, so most the intricacy
|
||||||
|
of parsing and writing headers is handled as in the full net/http package.
|
||||||
|
|
||||||
|
Run ```go doc -all ./src/net/http``` in TinyGo repo to see full listing.
|
||||||
|
|
||||||
|
## Using "crypto/tls" Package
|
||||||
|
|
||||||
|
TinyGo's TLS support (crypto/tls) relies on hardware offload of the TLS
|
||||||
|
protocol. This is different from Go's crypto/tls package which handles the TLS
|
||||||
|
protocol in software.
|
||||||
|
|
||||||
|
TinyGo's TLS support is only available for client applications. You can
|
||||||
|
http.Get() to an https:// address, but you cannot http.ListenAndServeTLS() an
|
||||||
|
https server.
|
||||||
|
|
||||||
|
The offloading hardware has pre-defined TLS certificates built-in.
|
||||||
|
|
||||||
|
## Using Sockets
|
||||||
|
|
||||||
|
The Netdever interface is a BSD socket-like interface so an application can make direct
|
||||||
|
socket calls, bypassing the "net" package for the lowest overhead.
|
||||||
|
|
||||||
|
Here is a simple TCP client application using direct sockets:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net" // only need to parse IP address
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netdev"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// load network driver for target
|
||||||
|
link, dev := probe.Probe()
|
||||||
|
|
||||||
|
// Connect target to IP network
|
||||||
|
link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: "my SSID",
|
||||||
|
Passphrase: "my passphrase",
|
||||||
|
})
|
||||||
|
|
||||||
|
// omit error handling
|
||||||
|
|
||||||
|
sock, _ := dev.Socket(netdev.AF_INET, netdev.SOCK_STREAM, netdev.IPPROTO_TCP)
|
||||||
|
|
||||||
|
dev.Connect(sock, "", net.ParseIP("10.0.0.100"), 8080)
|
||||||
|
dev.Send(sock, []bytes("hello"), 0, 0)
|
||||||
|
|
||||||
|
dev.Close(sock)
|
||||||
|
link.NetDisconnect()
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
[](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 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 102 different hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
|
||||||
|
|
||||||
|
For the complete list, please see:
|
||||||
|
https://tinygo.org/docs/reference/devices/
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@@ -50,11 +53,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Supported devices
|
|
||||||
|
|
||||||
There are currently 96 devices supported. For the complete list, please see:
|
|
||||||
https://tinygo.org/docs/reference/devices/
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Your contributions are welcome!
|
Your contributions are welcome!
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
// Package adafruit4650 implements a driver for the Adafruit FeatherWing OLED - 128x64 OLED display.
|
||||||
|
// The display is backed itself by a SH1107 driver chip.
|
||||||
|
//
|
||||||
|
// Store: https://www.adafruit.com/product/4650
|
||||||
|
//
|
||||||
|
// Documentation: https://learn.adafruit.com/adafruit-128x64-oled-featherwing
|
||||||
|
package adafruit4650
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DefaultAddress = 0x3c
|
||||||
|
|
||||||
|
const (
|
||||||
|
commandSetLowColumn = 0x00
|
||||||
|
commandSetHighColumn = 0x10
|
||||||
|
commandSetPage = 0xb0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
width = 128
|
||||||
|
height = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device represents an Adafruit 4650 device
|
||||||
|
type Device struct {
|
||||||
|
bus drivers.I2C
|
||||||
|
Address uint8
|
||||||
|
buffer []byte
|
||||||
|
width int16
|
||||||
|
height int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new device, not configuring anything yet.
|
||||||
|
func New(bus drivers.I2C) Device {
|
||||||
|
return Device{
|
||||||
|
bus: bus,
|
||||||
|
Address: DefaultAddress,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure initializes the display with default configuration
|
||||||
|
func (d *Device) Configure() error {
|
||||||
|
|
||||||
|
bufferSize := d.width * d.height / 8
|
||||||
|
d.buffer = make([]byte, bufferSize)
|
||||||
|
|
||||||
|
// This sequence is an amalgamation of the datasheet, official Arduino driver, CircuitPython driver and other drivers
|
||||||
|
initSequence := []byte{
|
||||||
|
0xae, // display off, sleep mode
|
||||||
|
//0xd5, 0x41, // set display clock divider (from original datasheet)
|
||||||
|
0xd5, 0x51, // set display clock divider (from Adafruit driver)
|
||||||
|
0xd9, 0x22, // pre-charge/dis-charge period mode: 2 DCLKs/2 DCLKs (POR)
|
||||||
|
0x20, // memory mode
|
||||||
|
0x81, 0x4f, // contrast setting = 0x4f
|
||||||
|
0xad, 0x8a, // set dc/dc pump
|
||||||
|
0xa0, // segment remap, flip-x
|
||||||
|
0xc0, // common output scan direction
|
||||||
|
0xdc, 0x00, // set display start line 0 (POR=0)
|
||||||
|
0xa8, 0x3f, // multiplex ratio, height - 1 = 0x3f
|
||||||
|
0xd3, 0x60, // set display offset mode = 0x60
|
||||||
|
0xdb, 0x35, // VCOM deselect level = 0.770 (POR)
|
||||||
|
0xa4, // entire display off, retain RAM, normal status (POR)
|
||||||
|
0xa6, // normal (not reversed) display
|
||||||
|
0xaf, // display on
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.writeCommands(initSequence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// recommended in the datasheet, same in other drivers
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearDisplay clears the image buffer as well as the actual display
|
||||||
|
func (d *Device) ClearDisplay() error {
|
||||||
|
d.ClearBuffer()
|
||||||
|
return d.Display()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearBuffer clears the buffer
|
||||||
|
func (d *Device) ClearBuffer() {
|
||||||
|
bzero(d.buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPixel modifies the internal buffer. Since this display has a bit-depth of 1 bit any non-zero
|
||||||
|
// color component will be treated as 'on', otherwise 'off'.
|
||||||
|
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
||||||
|
if x < 0 || x >= d.width || y < 0 || y >= d.height {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAM layout
|
||||||
|
// *-----> y
|
||||||
|
// |
|
||||||
|
// x| col0 col1 ... col63
|
||||||
|
// v p0 a0 b0 ..
|
||||||
|
// a1 b1 ..
|
||||||
|
// .. .. ..
|
||||||
|
// a7 b7 ..
|
||||||
|
// p1 a0 b0
|
||||||
|
// a1 b1
|
||||||
|
//
|
||||||
|
|
||||||
|
//flip y - so the display orientation matches the silk screen labeling etc.
|
||||||
|
y = d.height - y - 1
|
||||||
|
|
||||||
|
page := x / 8
|
||||||
|
bytesPerPage := d.height
|
||||||
|
byteIndex := y + bytesPerPage*page
|
||||||
|
bit := x % 8
|
||||||
|
if (c.R | c.G | c.B) != 0 {
|
||||||
|
d.buffer[byteIndex] |= 1 << uint8(bit)
|
||||||
|
} else {
|
||||||
|
d.buffer[byteIndex] &^= 1 << uint8(bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display sends the whole buffer to the screen
|
||||||
|
func (d *Device) Display() error {
|
||||||
|
|
||||||
|
bytesPerPage := d.height
|
||||||
|
|
||||||
|
pages := (d.width + 7) / 8
|
||||||
|
for page := int16(0); page < pages; page++ {
|
||||||
|
|
||||||
|
err := d.setRAMPosition(uint8(page), 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := page * bytesPerPage
|
||||||
|
err = d.writeRAM(d.buffer[offset : offset+bytesPerPage])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setRAMPosition updates the device's current page and column position
|
||||||
|
func (d *Device) setRAMPosition(page uint8, column uint8) error {
|
||||||
|
if page > 15 {
|
||||||
|
panic("page out of bounds")
|
||||||
|
}
|
||||||
|
if column > 127 {
|
||||||
|
panic("column out of bounds")
|
||||||
|
}
|
||||||
|
setPage := commandSetPage | (page & 0xF)
|
||||||
|
|
||||||
|
lo := column & 0xF
|
||||||
|
setLowColumn := commandSetLowColumn | lo
|
||||||
|
|
||||||
|
hi := (column >> 4) & 0x7
|
||||||
|
setHighColumn := commandSetHighColumn | hi
|
||||||
|
|
||||||
|
cmds := []byte{
|
||||||
|
setPage,
|
||||||
|
setLowColumn,
|
||||||
|
setHighColumn,
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.writeCommands(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the current size of the display.
|
||||||
|
func (d *Device) Size() (w, h int16) {
|
||||||
|
return d.width, d.height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) writeCommands(commands []byte) error {
|
||||||
|
onlyCommandsFollowing := byte(0x00)
|
||||||
|
return d.bus.Tx(uint16(d.Address), append([]byte{onlyCommandsFollowing}, commands...), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) writeRAM(data []byte) error {
|
||||||
|
onlyRAMFollowing := byte(0x40)
|
||||||
|
return d.bus.Tx(uint16(d.Address), append([]byte{onlyRAMFollowing}, data...), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bzero(buf []byte) {
|
||||||
|
for i := range buf {
|
||||||
|
buf[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package adafruit4650
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
"image/png"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
"tinygo.org/x/tinyfont"
|
||||||
|
"tinygo.org/x/tinyfont/freemono"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed expected_hello_world.png
|
||||||
|
var expectedHelloWorld []byte
|
||||||
|
|
||||||
|
// mockBus mocks a fake i2c device adafruit4650 display.
|
||||||
|
// The memory layout assumes that clients set up the device in a particular way and always send complete
|
||||||
|
// pages to the device buffer.
|
||||||
|
type mockBus struct {
|
||||||
|
img draw.Image
|
||||||
|
line int
|
||||||
|
addr uint8
|
||||||
|
currentPage int
|
||||||
|
currentColumn int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockBus) Tx(addr uint16, w, r []byte) error {
|
||||||
|
if addr != uint16(m.addr) {
|
||||||
|
panic("unexpected address")
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
panic("mock does not support reads")
|
||||||
|
}
|
||||||
|
|
||||||
|
if w[0] == 0x00 {
|
||||||
|
if w[1]&0xf0 == 0xb0 {
|
||||||
|
m.currentPage = int(w[1] & 0x0f)
|
||||||
|
|
||||||
|
lo := w[2] & 0x0f
|
||||||
|
hi := w[2] & 0x07
|
||||||
|
m.currentColumn = int(hi<<4 | lo)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if w[0] != 0x40 {
|
||||||
|
panic("unexpected first byte: " + hex.EncodeToString(w[0:1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.writeRAM(w[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMock() *mockBus {
|
||||||
|
|
||||||
|
m := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||||
|
return &mockBus{img: m, addr: DefaultAddress, currentPage: -1, currentColumn: -1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockBus) writeRAM(data []byte) error {
|
||||||
|
|
||||||
|
// RAM layout
|
||||||
|
// *-----> y
|
||||||
|
// |
|
||||||
|
// x| col0 col1 ... col63
|
||||||
|
// v p0 a0 b0 ..
|
||||||
|
// a1 b1 ..
|
||||||
|
// .. .. ..
|
||||||
|
// a7 b7 ..
|
||||||
|
// p1 a0 b0
|
||||||
|
// a1 b1
|
||||||
|
//
|
||||||
|
|
||||||
|
fmt.Printf("writing page %d\n", m.currentPage)
|
||||||
|
// assuming entire pages will be written
|
||||||
|
for x := 0; x < 8; x++ {
|
||||||
|
for y := 0; y < height; y++ {
|
||||||
|
|
||||||
|
col := data[y]
|
||||||
|
|
||||||
|
c := color.Black
|
||||||
|
if col&(1<<x) != 0 {
|
||||||
|
c = color.White
|
||||||
|
}
|
||||||
|
|
||||||
|
m.img.Set(x+m.currentPage*8, height-y-1, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockBus) toImage() *image.RGBA {
|
||||||
|
|
||||||
|
container := image.NewRGBA(m.img.Bounds().Inset(-1))
|
||||||
|
draw.Draw(container, container.Bounds(), image.NewUniform(color.RGBA{G: 255, A: 255}), image.Point{}, draw.Over)
|
||||||
|
draw.Draw(container, m.img.Bounds(), m.img, image.Point{}, draw.Over)
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDevice_Display(t *testing.T) {
|
||||||
|
|
||||||
|
bus := newMock()
|
||||||
|
dev := New(bus)
|
||||||
|
|
||||||
|
dev.Configure()
|
||||||
|
|
||||||
|
drawPlus(&dev)
|
||||||
|
drawHellowWorld(&dev)
|
||||||
|
|
||||||
|
//when
|
||||||
|
dev.Display()
|
||||||
|
|
||||||
|
//then
|
||||||
|
actual := bus.toImage()
|
||||||
|
|
||||||
|
expected, err := png.Decode(bytes.NewReader(expectedHelloWorld))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqualImages(t, actual, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawPlus(d drivers.Displayer) {
|
||||||
|
for i := int16(0); i < 128; i++ {
|
||||||
|
d.SetPixel(i, 32, color.RGBA{R: 1})
|
||||||
|
}
|
||||||
|
for i := int16(0); i < 64; i++ {
|
||||||
|
d.SetPixel(64, i, color.RGBA{R: 1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawHellowWorld(d drivers.Displayer) {
|
||||||
|
tinyfont.WriteLine(d, &freemono.Regular9pt7b, 0, 32, "Hello World!", color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEqualImages(t testing.TB, actual, expected image.Image) {
|
||||||
|
|
||||||
|
if actual.Bounds().Dx() != expected.Bounds().Dx() || actual.Bounds().Dy() != expected.Bounds().Dy() {
|
||||||
|
f := writeImage(actual)
|
||||||
|
t.Fatalf("differing size: was %v, expected %v, saved actual to %s", actual.Bounds(), expected.Bounds(), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
bb := expected.Bounds()
|
||||||
|
for x := bb.Min.X; x < bb.Max.X; x++ {
|
||||||
|
for y := bb.Min.Y; y < bb.Max.Y; y++ {
|
||||||
|
actualBB := actual.Bounds()
|
||||||
|
if actual.At(x+actualBB.Min.X, y+actualBB.Min.Y) != expected.At(x, y) {
|
||||||
|
f := writeImage(actual)
|
||||||
|
t.Fatalf("different pixel at %d/%d: %v != %v, saved actual at %s", x, y, actual.At(x, y), expected.At(x, y), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeImage(img image.Image) string {
|
||||||
|
|
||||||
|
fn := fmt.Sprintf("%d.png", time.Now().Unix())
|
||||||
|
f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = png.Encode(f, img)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return fn
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 449 B |
+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 = d.dataFormat.convertToIS(rx)
|
x = int32(d.dataFormat.convertToIS(rx))
|
||||||
y = d.dataFormat.convertToIS(ry)
|
y = int32(d.dataFormat.convertToIS(ry))
|
||||||
z = d.dataFormat.convertToIS(rz)
|
z = int32(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 int32, y int32, z int32) {
|
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
|
||||||
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 int32) int32 {
|
func (d *dataFormat) convertToIS(rawValue int16) int16 {
|
||||||
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) int32 {
|
func readIntLE(msb byte, lsb byte) int16 {
|
||||||
return int32(uint16(msb) | uint16(lsb)<<8)
|
return int16(uint16(msb) | uint16(lsb)<<8)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
|||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps an I2C connection to a DS3231 device.
|
// Device wraps an I2C connection to an AT24CX device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.I2C
|
bus drivers.I2C
|
||||||
Address uint16
|
Address uint16
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ func Sleep(duration time.Duration) {
|
|||||||
// * The CPU frequency is lower than 256MHz. If it is higher, long sleep
|
// * The CPU frequency is lower than 256MHz. If it is higher, long sleep
|
||||||
// times (1-16ms) may not work correctly.
|
// times (1-16ms) may not work correctly.
|
||||||
cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000
|
cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000
|
||||||
slept := C.tinygo_drivers_sleep(cycles)
|
slept := C.tinygo_drivers_sleep(C.uint32_t(cycles))
|
||||||
if !slept {
|
if !slept {
|
||||||
// Fallback for platforms without inline assembly support.
|
// Fallback for platforms without inline assembly support.
|
||||||
time.Sleep(duration)
|
time.Sleep(duration)
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
//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))
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package espat
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (d *Device) ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error {
|
|
||||||
if len(ssid) == 0 {
|
|
||||||
return net.ErrWiFiMissingSSID
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetWifiMode(WifiModeClient)
|
|
||||||
return d.ConnectToAP(ssid, pass, int(timeout.Seconds()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) Disconnect() error {
|
|
||||||
return d.DisconnectFromAP()
|
|
||||||
}
|
|
||||||
+297
-34
@@ -15,41 +15,302 @@
|
|||||||
//
|
//
|
||||||
// AT command set:
|
// AT command set:
|
||||||
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
||||||
|
//
|
||||||
|
// 02/2023 sfeldma@gmail.com Heavily modified to use netdev interface
|
||||||
|
|
||||||
package espat // import "tinygo.org/x/drivers/espat"
|
package espat // import "tinygo.org/x/drivers/espat"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers/netdev"
|
||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps UART connection to the ESP8266/ESP32.
|
type Config struct {
|
||||||
type Device struct {
|
// UART config
|
||||||
bus drivers.UART
|
Uart *machine.UART
|
||||||
|
Tx machine.Pin
|
||||||
|
Rx machine.Pin
|
||||||
|
}
|
||||||
|
|
||||||
|
type socket struct {
|
||||||
|
inUse bool
|
||||||
|
protocol int
|
||||||
|
laddr netip.AddrPort
|
||||||
|
}
|
||||||
|
|
||||||
|
type Device struct {
|
||||||
|
cfg *Config
|
||||||
|
uart *machine.UART
|
||||||
// command responses that come back from the ESP8266/ESP32
|
// command responses that come back from the ESP8266/ESP32
|
||||||
response []byte
|
response []byte
|
||||||
|
|
||||||
// data received from a TCP/UDP connection forwarded by the ESP8266/ESP32
|
// data received from a TCP/UDP connection forwarded by the ESP8266/ESP32
|
||||||
socketdata []byte
|
data []byte
|
||||||
|
socket socket
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActiveDevice is the currently configured Device in use. There can only be one.
|
func NewDevice(cfg *Config) *Device {
|
||||||
var ActiveDevice *Device
|
return &Device{
|
||||||
|
cfg: cfg,
|
||||||
// New returns a new espat driver. Pass in a fully configured UART bus.
|
response: make([]byte, 1500),
|
||||||
func New(b drivers.UART) *Device {
|
data: make([]byte, 0, 1500),
|
||||||
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure sets up the device for communication.
|
func (d *Device) NetConnect(params *netlink.ConnectParams) error {
|
||||||
func (d Device) Configure() {
|
|
||||||
ActiveDevice = &d
|
if len(params.Ssid) == 0 {
|
||||||
net.ActiveDevice = ActiveDevice
|
return netlink.ErrMissingSSID
|
||||||
|
}
|
||||||
|
|
||||||
|
d.uart = d.cfg.Uart
|
||||||
|
d.uart.Configure(machine.UARTConfig{TX: d.cfg.Tx, RX: d.cfg.Rx})
|
||||||
|
|
||||||
|
// Connect to ESP8266/ESP32
|
||||||
|
fmt.Printf("Connecting to device...")
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
if d.Connected() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !d.Connected() {
|
||||||
|
fmt.Printf("FAILED\r\n")
|
||||||
|
return netlink.ErrConnectFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("CONNECTED\r\n")
|
||||||
|
|
||||||
|
// Connect to Wifi AP
|
||||||
|
fmt.Printf("Connecting to Wifi SSID '%s'...", params.Ssid)
|
||||||
|
|
||||||
|
d.SetWifiMode(WifiModeClient)
|
||||||
|
|
||||||
|
err := d.ConnectToAP(params.Ssid, params.Passphrase, 10 /* secs */)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("FAILED\r\n")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("CONNECTED\r\n")
|
||||||
|
|
||||||
|
ip, err := d.Addr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("DHCP-assigned IP: %s\r\n", ip)
|
||||||
|
fmt.Printf("\r\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) NetDisconnect() {
|
||||||
|
d.DisconnectFromAP()
|
||||||
|
fmt.Printf("\r\nDisconnected from Wifi\r\n\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) NetNotify(cb func(netlink.Event)) {
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) GetHostByName(name string) (netip.Addr, error) {
|
||||||
|
ip, err := d.GetDNS(name)
|
||||||
|
if err != nil {
|
||||||
|
return netip.Addr{}, err
|
||||||
|
}
|
||||||
|
return netip.ParseAddr(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) GetHardwareAddr() (net.HardwareAddr, error) {
|
||||||
|
return net.HardwareAddr{}, netlink.ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Addr() (netip.Addr, error) {
|
||||||
|
resp, err := d.GetClientIP()
|
||||||
|
if err != nil {
|
||||||
|
return netip.Addr{}, err
|
||||||
|
}
|
||||||
|
prefix := "+CIPSTA:ip:"
|
||||||
|
for _, line := range strings.Split(resp, "\n") {
|
||||||
|
if ok := strings.HasPrefix(line, prefix); ok {
|
||||||
|
ip := line[len(prefix)+1 : len(line)-2]
|
||||||
|
return netip.ParseAddr(ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netip.Addr{}, fmt.Errorf("Error getting IP address")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Socket(domain int, stype int, protocol int) (int, error) {
|
||||||
|
|
||||||
|
switch domain {
|
||||||
|
case netdev.AF_INET:
|
||||||
|
default:
|
||||||
|
return -1, netdev.ErrFamilyNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case protocol == netdev.IPPROTO_TCP && stype == netdev.SOCK_STREAM:
|
||||||
|
case protocol == netdev.IPPROTO_TLS && stype == netdev.SOCK_STREAM:
|
||||||
|
case protocol == netdev.IPPROTO_UDP && stype == netdev.SOCK_DGRAM:
|
||||||
|
default:
|
||||||
|
return -1, netdev.ErrProtocolNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only supporting single connection mode, so only one socket at a time
|
||||||
|
if d.socket.inUse {
|
||||||
|
return -1, netdev.ErrNoMoreSockets
|
||||||
|
}
|
||||||
|
d.socket.inUse = true
|
||||||
|
d.socket.protocol = protocol
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Bind(sockfd int, ip netip.AddrPort) error {
|
||||||
|
d.socket.laddr = ip
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Connect(sockfd int, host string, ip netip.AddrPort) error {
|
||||||
|
var err error
|
||||||
|
var addr = ip.Addr().String()
|
||||||
|
var rport = strconv.Itoa(int(ip.Port()))
|
||||||
|
var lport = strconv.Itoa(int(d.socket.laddr.Port()))
|
||||||
|
|
||||||
|
switch d.socket.protocol {
|
||||||
|
case netdev.IPPROTO_TCP:
|
||||||
|
err = d.ConnectTCPSocket(addr, rport)
|
||||||
|
case netdev.IPPROTO_UDP:
|
||||||
|
err = d.ConnectUDPSocket(addr, rport, lport)
|
||||||
|
case netdev.IPPROTO_TLS:
|
||||||
|
err = d.ConnectSSLSocket(host, rport)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if host == "" {
|
||||||
|
return fmt.Errorf("Connect to %s timed out", ip)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Connect to %s:%d timed out", host, ip.Port())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Listen(sockfd int, backlog int) error {
|
||||||
|
switch d.socket.protocol {
|
||||||
|
case netdev.IPPROTO_UDP:
|
||||||
|
default:
|
||||||
|
return netdev.ErrProtocolNotSupported
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Accept(sockfd int) (int, netip.AddrPort, error) {
|
||||||
|
return -1, netip.AddrPort{}, netdev.ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
|
||||||
|
// Check if we've timed out
|
||||||
|
if !deadline.IsZero() {
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
return -1, netdev.ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := d.StartSocketSend(len(buf))
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
n, err := d.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
_, err = d.Response(1000)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
// Break large bufs into chunks so we don't overrun the hw queue
|
||||||
|
|
||||||
|
chunkSize := 1436
|
||||||
|
for i := 0; i < len(buf); i += chunkSize {
|
||||||
|
end := i + chunkSize
|
||||||
|
if end > len(buf) {
|
||||||
|
end = len(buf)
|
||||||
|
}
|
||||||
|
_, err := d.sendChunk(sockfd, buf[i:end], deadline)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
var length = len(buf)
|
||||||
|
|
||||||
|
// Limit length read size to chunk large read requests
|
||||||
|
if length > 1436 {
|
||||||
|
length = 1436
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Check if we've timed out
|
||||||
|
if !deadline.IsZero() {
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
return -1, netdev.ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := d.ReadSocket(buf[:length])
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
d.mu.Unlock()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
d.mu.Lock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) Close(sockfd int) error {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
d.socket.inUse = false
|
||||||
|
return d.DisconnectSocket()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) SetSockOpt(sockfd int, level int, opt int, value interface{}) error {
|
||||||
|
return netdev.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connected checks if there is communication with the ESP8266/ESP32.
|
// Connected checks if there is communication with the ESP8266/ESP32.
|
||||||
@@ -57,7 +318,7 @@ func (d *Device) Connected() bool {
|
|||||||
d.Execute(Test)
|
d.Execute(Test)
|
||||||
|
|
||||||
// handle response here, should include "OK"
|
// handle response here, should include "OK"
|
||||||
_, err := d.Response(100)
|
_, err := d.Response(1000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -66,12 +327,12 @@ func (d *Device) Connected() bool {
|
|||||||
|
|
||||||
// Write raw bytes to the UART.
|
// Write raw bytes to the UART.
|
||||||
func (d *Device) Write(b []byte) (n int, err error) {
|
func (d *Device) Write(b []byte) (n int, err error) {
|
||||||
return d.bus.Write(b)
|
return d.uart.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read raw bytes from the UART.
|
// Read raw bytes from the UART.
|
||||||
func (d *Device) Read(b []byte) (n int, err error) {
|
func (d *Device) Read(b []byte) (n int, err error) {
|
||||||
return d.bus.Read(b)
|
return d.uart.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// how long in milliseconds to pause after sending AT commands
|
// how long in milliseconds to pause after sending AT commands
|
||||||
@@ -100,9 +361,10 @@ func (d Device) Set(cmd, params string) error {
|
|||||||
// Version returns the ESP8266/ESP32 firmware version info.
|
// Version returns the ESP8266/ESP32 firmware version info.
|
||||||
func (d Device) Version() []byte {
|
func (d Device) Version() []byte {
|
||||||
d.Execute(Version)
|
d.Execute(Version)
|
||||||
r, err := d.Response(100)
|
r, err := d.Response(2000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte("unknown")
|
//return []byte("unknown")
|
||||||
|
return []byte(err.Error())
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -132,16 +394,16 @@ func (d *Device) ReadSocket(b []byte) (n int, err error) {
|
|||||||
d.Response(300)
|
d.Response(300)
|
||||||
|
|
||||||
count := len(b)
|
count := len(b)
|
||||||
if len(b) >= len(d.socketdata) {
|
if len(b) >= len(d.data) {
|
||||||
// copy it all, then clear socket data
|
// copy it all, then clear socket data
|
||||||
count = len(d.socketdata)
|
count = len(d.data)
|
||||||
copy(b, d.socketdata[:count])
|
copy(b, d.data[:count])
|
||||||
d.socketdata = d.socketdata[:0]
|
d.data = d.data[:0]
|
||||||
} else {
|
} else {
|
||||||
// copy all we can, then keep the remaining socket data around
|
// copy all we can, then keep the remaining socket data around
|
||||||
copy(b, d.socketdata[:count])
|
copy(b, d.data[:count])
|
||||||
copy(d.socketdata, d.socketdata[count:])
|
copy(d.data, d.data[count:])
|
||||||
d.socketdata = d.socketdata[:len(d.socketdata)-count]
|
d.data = d.data[:len(d.data)-count]
|
||||||
}
|
}
|
||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
@@ -157,11 +419,11 @@ func (d *Device) Response(timeout int) ([]byte, error) {
|
|||||||
retries := timeout / pause
|
retries := timeout / pause
|
||||||
|
|
||||||
for {
|
for {
|
||||||
size = d.bus.Buffered()
|
size = d.uart.Buffered()
|
||||||
|
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
end += size
|
end += size
|
||||||
d.bus.Read(d.response[start:end])
|
d.uart.Read(d.response[start:end])
|
||||||
|
|
||||||
// if "+IPD" then read socket data
|
// if "+IPD" then read socket data
|
||||||
if strings.Contains(string(d.response[:end]), "+IPD") {
|
if strings.Contains(string(d.response[:end]), "+IPD") {
|
||||||
@@ -204,18 +466,19 @@ func (d *Device) parseIPD(end int) error {
|
|||||||
val := string(d.response[s+5 : e])
|
val := string(d.response[s+5 : e])
|
||||||
|
|
||||||
// TODO: verify count
|
// TODO: verify count
|
||||||
_, err := strconv.Atoi(val)
|
v, err := strconv.Atoi(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// not expected data here. what to do?
|
// not expected data here. what to do?
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// load up the socket data
|
// load up the socket data
|
||||||
d.socketdata = append(d.socketdata, d.response[e+1:end]...)
|
//d.data = append(d.data, d.response[e+1:end]...)
|
||||||
|
d.data = append(d.data, d.response[e+1:e+1+v]...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketDataAvailable returns of there is socket data available
|
// IsSocketDataAvailable returns of there is socket data available
|
||||||
func (d *Device) IsSocketDataAvailable() bool {
|
func (d *Device) IsSocketDataAvailable() bool {
|
||||||
return len(d.socketdata) > 0 || d.bus.Buffered() > 0
|
return len(d.data) > 0 || d.uart.Buffered() > 0
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ func (d *Device) ConnectTCPSocket(addr, port string) error {
|
|||||||
// ConnectUDPSocket creates a new UDP connection for the ESP8266/ESP32.
|
// ConnectUDPSocket creates a new UDP connection for the ESP8266/ESP32.
|
||||||
func (d *Device) ConnectUDPSocket(addr, sendport, listenport string) error {
|
func (d *Device) ConnectUDPSocket(addr, sendport, listenport string) error {
|
||||||
protocol := "UDP"
|
protocol := "UDP"
|
||||||
val := "\"" + protocol + "\",\"" + addr + "\"," + sendport + "," + listenport + ",2"
|
val := "\"" + protocol + "\",\"" + addr + "\"," + sendport + "," + listenport + ",0"
|
||||||
err := d.Set(TCPConnect, val)
|
err := d.Set(TCPConnect, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+1
-4
@@ -44,10 +44,7 @@ func (d *Device) ConnectToAP(ssid, pwd string, ws int) error {
|
|||||||
d.Set(ConnectAP, val)
|
d.Set(ConnectAP, val)
|
||||||
|
|
||||||
_, err := d.Response(ws * 1000)
|
_, err := d.Response(ws * 1000)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisconnectFromAP disconnects the ESP8266/ESP32 from the current access point.
|
// DisconnectFromAP disconnects the ESP8266/ESP32 from the current access point.
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"machine"
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
"tinygo.org/x/drivers/adafruit4650"
|
||||||
|
"tinygo.org/x/tinyfont"
|
||||||
|
"tinygo.org/x/tinyfont/freemono"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
|
||||||
|
dev := adafruit4650.New(machine.I2C0)
|
||||||
|
|
||||||
|
err := dev.Configure()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPlus(&dev)
|
||||||
|
drawHelloWorld(&dev)
|
||||||
|
|
||||||
|
err = dev.Display()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawPlus(d drivers.Displayer) {
|
||||||
|
for i := int16(0); i < 128; i++ {
|
||||||
|
d.SetPixel(i, 32, color.RGBA{R: 1})
|
||||||
|
}
|
||||||
|
for i := int16(0); i < 64; i++ {
|
||||||
|
d.SetPixel(64, i, color.RGBA{R: 1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawHelloWorld(d drivers.Displayer) {
|
||||||
|
tinyfont.WriteLine(d, &freemono.Regular9pt7b, 0, 32, "Hello World!", color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Connects to an MAG3110 I2C magnetometer.
|
// Connects to an DS3231 I2C Real Time Clock (RTC).
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//go:build macropad_rp2040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/encoders"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
enc = encoders.NewQuadratureViaInterrupt(machine.ROT_A, machine.ROT_B)
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
enc.Configure(encoders.QuadratureConfig{
|
||||||
|
Precision: 4,
|
||||||
|
})
|
||||||
|
|
||||||
|
for oldValue := 0; ; {
|
||||||
|
if newValue := enc.Position(); newValue != oldValue {
|
||||||
|
println("value: ", newValue)
|
||||||
|
oldValue = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
// This is a console to a ESP8266/ESP32 running on the device UART1.
|
|
||||||
// Allows you to type AT commands from your computer via the microcontroller.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
|
|
||||||
//
|
|
||||||
// More information on the Espressif AT command set at:
|
|
||||||
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
)
|
|
||||||
|
|
||||||
// change actAsAP to true to act as an access point instead of connecting to one.
|
|
||||||
const actAsAP = false
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
console = machine.Serial
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
// Init esp8266
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Type an AT command then press enter:")
|
|
||||||
prompt()
|
|
||||||
|
|
||||||
input := make([]byte, 64)
|
|
||||||
i := 0
|
|
||||||
for {
|
|
||||||
if console.Buffered() > 0 {
|
|
||||||
data, _ := console.ReadByte()
|
|
||||||
|
|
||||||
switch data {
|
|
||||||
case 13:
|
|
||||||
// return key
|
|
||||||
console.Write([]byte("\r\n"))
|
|
||||||
|
|
||||||
// send command to ESP8266
|
|
||||||
input[i] = byte('\r')
|
|
||||||
input[i+1] = byte('\n')
|
|
||||||
adaptor.Write(input[:i+2])
|
|
||||||
|
|
||||||
// display response
|
|
||||||
r, _ := adaptor.Response(500)
|
|
||||||
console.Write(r)
|
|
||||||
|
|
||||||
// prompt
|
|
||||||
prompt()
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
// just echo the character
|
|
||||||
console.WriteByte(data)
|
|
||||||
input[i] = data
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func prompt() {
|
|
||||||
print("ESPAT>")
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// provide access point
|
|
||||||
func provideAP() {
|
|
||||||
println("Starting wifi network as access point '" + ssid + "'...")
|
|
||||||
adaptor.SetWifiMode(espat.WifiModeAP)
|
|
||||||
adaptor.SetAPConfig(ssid, pass, 7, espat.WifiAPSecurityWPA2_PSK)
|
|
||||||
println("Ready.")
|
|
||||||
ip, _ := adaptor.GetAPIP()
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
// This is a sensor hub that uses a ESP8266/ESP32 running on the device UART1.
|
|
||||||
// It creates a UDP "server" you can use to get info to/from your computer via the microcontroller.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// change actAsAP to true to act as an access point instead of connecting to one.
|
|
||||||
const actAsAP = false
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
// Init esp8266
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
readyled := machine.LED
|
|
||||||
readyled.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
readyled.High()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
laddr := &net.UDPAddr{Port: 2222}
|
|
||||||
println("Loading UDP listener...")
|
|
||||||
conn, _ := net.ListenUDP("UDP", laddr)
|
|
||||||
|
|
||||||
println("Waiting for data...")
|
|
||||||
data := make([]byte, 50)
|
|
||||||
blink := true
|
|
||||||
for {
|
|
||||||
n, _ := conn.Read(data)
|
|
||||||
if n > 0 {
|
|
||||||
println(string(data[:n]))
|
|
||||||
conn.Write([]byte("hello back\r\n"))
|
|
||||||
}
|
|
||||||
blink = !blink
|
|
||||||
if blink {
|
|
||||||
readyled.High()
|
|
||||||
} else {
|
|
||||||
readyled.Low()
|
|
||||||
}
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting UDP...")
|
|
||||||
conn.Close()
|
|
||||||
println("Done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// provide access point
|
|
||||||
func provideAP() {
|
|
||||||
println("Starting wifi network as access point '" + ssid + "'...")
|
|
||||||
adaptor.SetWifiMode(espat.WifiModeAP)
|
|
||||||
adaptor.SetAPConfig(ssid, pass, 7, espat.WifiAPSecurityWPA2_PSK)
|
|
||||||
println("Ready.")
|
|
||||||
ip, _ := adaptor.GetAPIP()
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
|
|
||||||
// It creates a UDP connection you can use to get info to/from your computer via the microcontroller.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the listener aka "hub". Replace with your own info.
|
|
||||||
const hubIP = "0.0.0.0"
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
ip := net.ParseIP(hubIP)
|
|
||||||
raddr := &net.UDPAddr{IP: ip, Port: 2222}
|
|
||||||
laddr := &net.UDPAddr{Port: 2222}
|
|
||||||
|
|
||||||
println("Dialing UDP connection...")
|
|
||||||
conn, _ := net.DialUDP("udp", laddr, raddr)
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Sending data...")
|
|
||||||
conn.Write([]byte("hello\r\n"))
|
|
||||||
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting UDP...")
|
|
||||||
conn.Close()
|
|
||||||
println("Done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
"machine"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
"tinygo.org/x/drivers/net/mqtt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART2
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
console = machine.Serial
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
topic = "tinygo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
time.Sleep(3000 * time.Millisecond)
|
|
||||||
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
println("Publishing MQTT message...")
|
|
||||||
data := []byte("{\"e\":[{ \"n\":\"hello\", \"v\":101 }]}")
|
|
||||||
token := cl.Publish(topic, 0, false, data)
|
|
||||||
token.Wait()
|
|
||||||
if token.Error() != nil {
|
|
||||||
println(token.Error().Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(1000 * 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 ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
// 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/espat"
|
|
||||||
"tinygo.org/x/drivers/net/mqtt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 defaults for the Arduino Nano33 IoT.
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
console = machine.Serial
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
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())
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
println("Publishing MQTT message...")
|
|
||||||
data := []byte("{\"e\":[{ \"n\":\"hello\", \"v\":101 }]}")
|
|
||||||
token := cl.Publish(topicTx, 0, false, data)
|
|
||||||
token.Wait()
|
|
||||||
if token.Error() != nil {
|
|
||||||
println(token.Error().Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1.
|
|
||||||
// It creates a UDP connection you can use to get info to/from your computer via the microcontroller.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
const serverIP = "0.0.0.0"
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// first check if connected
|
|
||||||
if connectToESP() {
|
|
||||||
println("Connected to wifi adaptor.")
|
|
||||||
adaptor.Echo(false)
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
} else {
|
|
||||||
println("")
|
|
||||||
failMessage("Unable to connect to wifi adaptor.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// now make TCP connection
|
|
||||||
ip := net.ParseIP(serverIP)
|
|
||||||
raddr := &net.TCPAddr{IP: ip, Port: 8080}
|
|
||||||
laddr := &net.TCPAddr{Port: 8080}
|
|
||||||
|
|
||||||
println("Dialing TCP connection...")
|
|
||||||
conn, err := net.DialTCP("tcp", laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Sending data...")
|
|
||||||
conn.Write([]byte("hello\r\n"))
|
|
||||||
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting TCP...")
|
|
||||||
conn.Close()
|
|
||||||
println("Done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to ESP8266/ESP32
|
|
||||||
func connectToESP() bool {
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
println("Connecting to wifi adaptor...")
|
|
||||||
if adaptor.Connected() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
println("Connecting to wifi network '" + ssid + "'")
|
|
||||||
|
|
||||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,15 +8,16 @@ import (
|
|||||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||||
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
|
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
|
||||||
"tinygo.org/x/drivers/ili9341"
|
"tinygo.org/x/drivers/ili9341"
|
||||||
|
"tinygo.org/x/drivers/pixel"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BGCOLOR = 0xAD75
|
BGCOLOR = pixel.RGB565BE(0x75AD)
|
||||||
GRIDCOLOR = 0xA815
|
GRIDCOLOR = pixel.RGB565BE(0x15A8)
|
||||||
BGSHADOW = 0x5285
|
BGSHADOW = pixel.RGB565BE(0x8552)
|
||||||
GRIDSHADOW = 0x600C
|
GRIDSHADOW = pixel.RGB565BE(0x0C60)
|
||||||
RED = 0xF800
|
RED = pixel.RGB565BE(0x00F8)
|
||||||
WHITE = 0xFFFF
|
WHITE = pixel.RGB565BE(0xFFFF)
|
||||||
|
|
||||||
YBOTTOM = 123 // Ball Y coord at bottom
|
YBOTTOM = 123 // Ball Y coord at bottom
|
||||||
YBOUNCE = -3.5 // Upward velocity on ball bounce
|
YBOUNCE = -3.5 // Upward velocity on ball bounce
|
||||||
@@ -25,7 +26,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8) * 2]uint8{}
|
frameBuffer = pixel.NewImage[pixel.RGB565BE](graphics.BALLWIDTH+8, graphics.BALLHEIGHT+8)
|
||||||
|
|
||||||
startTime int64
|
startTime int64
|
||||||
frame int64
|
frame int64
|
||||||
@@ -41,7 +42,7 @@ var (
|
|||||||
balloldy float32
|
balloldy float32
|
||||||
|
|
||||||
// Color table for ball rotation effect
|
// Color table for ball rotation effect
|
||||||
palette [16]uint16
|
palette [16]pixel.RGB565BE
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -108,6 +109,7 @@ func main() {
|
|||||||
|
|
||||||
width = maxx - minx + 1
|
width = maxx - minx + 1
|
||||||
height = maxy - miny + 1
|
height = maxy - miny + 1
|
||||||
|
buffer := frameBuffer.Rescale(int(width), int(height))
|
||||||
|
|
||||||
// Ball animation frame # is incremented opposite the ball's X velocity
|
// Ball animation frame # is incremented opposite the ball's X velocity
|
||||||
ballframe -= ballvx * 0.5
|
ballframe -= ballvx * 0.5
|
||||||
@@ -128,7 +130,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only the changed rectangle is drawn into the 'renderbuf' array...
|
// Only the changed rectangle is drawn into the 'renderbuf' array...
|
||||||
var c uint16 //, *destPtr;
|
var c pixel.RGB565BE //, *destPtr;
|
||||||
bx := minx - int16(ballx) // X relative to ball bitmap (can be negative)
|
bx := minx - int16(ballx) // X relative to ball bitmap (can be negative)
|
||||||
by := miny - int16(bally) // Y relative to ball bitmap (can be negative)
|
by := miny - int16(bally) // Y relative to ball bitmap (can be negative)
|
||||||
bgx := minx // X relative to background bitmap (>= 0)
|
bgx := minx // X relative to background bitmap (>= 0)
|
||||||
@@ -149,19 +151,20 @@ func main() {
|
|||||||
(by >= 0) && (by < graphics.BALLHEIGHT) { // inside the ball bitmap area?
|
(by >= 0) && (by < graphics.BALLHEIGHT) { // inside the ball bitmap area?
|
||||||
// Yes, do ball compositing math...
|
// Yes, do ball compositing math...
|
||||||
p = graphics.Ball[int(by*(graphics.BALLWIDTH/2))+int(bx1/2)] // Get packed value (2 pixels)
|
p = graphics.Ball[int(by*(graphics.BALLWIDTH/2))+int(bx1/2)] // Get packed value (2 pixels)
|
||||||
|
var nibble uint8
|
||||||
if (bx1 & 1) != 0 {
|
if (bx1 & 1) != 0 {
|
||||||
c = uint16(p & 0xF)
|
nibble = p & 0xF
|
||||||
} else {
|
} else {
|
||||||
c = uint16(p >> 4)
|
nibble = p >> 4
|
||||||
} // Unpack high or low nybble
|
} // Unpack high or low nybble
|
||||||
if c == 0 { // Outside ball - just draw grid
|
if nibble == 0 { // Outside ball - just draw grid
|
||||||
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
||||||
c = GRIDCOLOR
|
c = GRIDCOLOR
|
||||||
} else {
|
} else {
|
||||||
c = BGCOLOR
|
c = BGCOLOR
|
||||||
}
|
}
|
||||||
} else if c > 1 { // In ball area...
|
} else if nibble > 1 { // In ball area...
|
||||||
c = palette[c]
|
c = palette[nibble]
|
||||||
} else { // In shadow area...
|
} else { // In shadow area...
|
||||||
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
||||||
c = GRIDSHADOW
|
c = GRIDSHADOW
|
||||||
@@ -176,8 +179,7 @@ func main() {
|
|||||||
c = BGCOLOR
|
c = BGCOLOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frameBuffer[(y*int(width)+x)*2] = byte(c >> 8)
|
buffer.Set(x, y, c)
|
||||||
frameBuffer[(y*int(width)+x)*2+1] = byte(c)
|
|
||||||
bx1++ // Increment bitmap position counters (X axis)
|
bx1++ // Increment bitmap position counters (X axis)
|
||||||
bgx1++
|
bgx1++
|
||||||
}
|
}
|
||||||
@@ -188,7 +190,7 @@ func main() {
|
|||||||
bgy++
|
bgy++
|
||||||
}
|
}
|
||||||
|
|
||||||
display.DrawRGBBitmap8(minx, miny, frameBuffer[:width*height*2], width, height)
|
display.DrawBitmap(minx, miny, buffer)
|
||||||
|
|
||||||
// Show approximate frame rate
|
// Show approximate frame rate
|
||||||
frame++
|
frame++
|
||||||
@@ -205,6 +207,7 @@ func DrawBackground() {
|
|||||||
w, h := display.Size()
|
w, h := display.Size()
|
||||||
byteWidth := (w + 7) / 8 // Bitmap scanline pad = whole byte
|
byteWidth := (w + 7) / 8 // Bitmap scanline pad = whole byte
|
||||||
var b uint8
|
var b uint8
|
||||||
|
buffer := frameBuffer.Rescale(int(w), 1)
|
||||||
for j := int16(0); j < h; j++ {
|
for j := int16(0); j < h; j++ {
|
||||||
for k := int16(0); k < w; k++ {
|
for k := int16(0); k < w; k++ {
|
||||||
if k&7 > 0 {
|
if k&7 > 0 {
|
||||||
@@ -213,13 +216,11 @@ func DrawBackground() {
|
|||||||
b = graphics.Background[j*byteWidth+k/8]
|
b = graphics.Background[j*byteWidth+k/8]
|
||||||
}
|
}
|
||||||
if b&0x80 == 0 {
|
if b&0x80 == 0 {
|
||||||
frameBuffer[2*k] = byte(BGCOLOR >> 8)
|
buffer.Set(int(k), 0, BGCOLOR)
|
||||||
frameBuffer[2*k+1] = byte(BGCOLOR & 0xFF)
|
|
||||||
} else {
|
} else {
|
||||||
frameBuffer[2*k] = byte(GRIDCOLOR >> 8)
|
buffer.Set(int(k), 0, GRIDCOLOR)
|
||||||
frameBuffer[2*k+1] = byte(GRIDCOLOR & 0xFF)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
display.DrawRGBBitmap8(0, j, frameBuffer[0:w*2], w, 1)
|
display.DrawBitmap(0, j, buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,20 +23,20 @@ Builds/flashes atcmd console application with simulator instead of actual LoRa r
|
|||||||
tinygo flash -target pico ./examples/lora/lorawan/atcmd/
|
tinygo flash -target pico ./examples/lora/lorawan/atcmd/
|
||||||
```
|
```
|
||||||
|
|
||||||
## PyBadge with LoRa Featherwing
|
## PyBadge with LoRa Featherwing for EU868 region
|
||||||
|
|
||||||
Builds/flashes atcmd console application on PyBadge using LoRa Featherwing (RFM95/SX1276).
|
Builds/flashes atcmd console application on PyBadge using LoRa Featherwing (RFM95/SX1276).
|
||||||
|
|
||||||
```
|
```
|
||||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/atcmd/
|
tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/atcmd/
|
||||||
```
|
```
|
||||||
|
|
||||||
## LoRa-E5
|
## LoRa-E5 for US915 region
|
||||||
|
|
||||||
Builds/flashes atcmd console application on Lora-E5 using onboard SX126x.
|
Builds/flashes atcmd console application on Lora-E5 using onboard SX126x.
|
||||||
|
|
||||||
```
|
```
|
||||||
tinygo flash -target lorae5 ./examples/lora/lorawan/atcmd/
|
tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/atcmd/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Joining a Public Lorawan Network
|
## Joining a Public Lorawan Network
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ var (
|
|||||||
defaultTimeout uint32 = 1000
|
defaultTimeout uint32 = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var reg string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
|
||||||
@@ -45,7 +47,16 @@ func main() {
|
|||||||
otaa = &lorawan.Otaa{}
|
otaa = &lorawan.Otaa{}
|
||||||
lorawan.UseRadio(radio)
|
lorawan.UseRadio(radio)
|
||||||
|
|
||||||
lorawan.UseRegionSettings(region.EU868())
|
switch reg {
|
||||||
|
case "AU915":
|
||||||
|
lorawan.UseRegionSettings(region.AU915())
|
||||||
|
case "EU868":
|
||||||
|
lorawan.UseRegionSettings(region.EU868())
|
||||||
|
case "US915":
|
||||||
|
lorawan.UseRegionSettings(region.US915())
|
||||||
|
default:
|
||||||
|
lorawan.UseRegionSettings(region.EU868())
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if uart.Buffered() > 0 {
|
if uart.Buffered() > 0 {
|
||||||
|
|||||||
@@ -21,16 +21,16 @@ loraConnect: Connected !
|
|||||||
tinygo flash -target pico ./examples/lora/lorawan/basic-demo
|
tinygo flash -target pico ./examples/lora/lorawan/basic-demo
|
||||||
```
|
```
|
||||||
|
|
||||||
## PyBadge with LoRa Featherwing
|
## PyBadge with LoRa Featherwing for EU868 region
|
||||||
|
|
||||||
```
|
```
|
||||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/basic-demo
|
tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/basic-demo
|
||||||
```
|
```
|
||||||
|
|
||||||
## LoRa-E5
|
## LoRa-E5 for US915 region
|
||||||
|
|
||||||
```
|
```
|
||||||
tinygo flash -target lorae5 ./examples/lora/lorawan/basic-demo
|
tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/basic-demo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ import (
|
|||||||
"tinygo.org/x/drivers/lora/lorawan/region"
|
"tinygo.org/x/drivers/lora/lorawan/region"
|
||||||
)
|
)
|
||||||
|
|
||||||
var debug string
|
var (
|
||||||
|
reg string
|
||||||
|
debug string
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LORAWAN_JOIN_TIMEOUT_SEC = 180
|
LORAWAN_JOIN_TIMEOUT_SEC = 180
|
||||||
@@ -67,8 +70,16 @@ func main() {
|
|||||||
|
|
||||||
// Connect the lorawan with the Lora Radio device.
|
// Connect the lorawan with the Lora Radio device.
|
||||||
lorawan.UseRadio(radio)
|
lorawan.UseRadio(radio)
|
||||||
|
switch reg {
|
||||||
lorawan.UseRegionSettings(region.EU868())
|
case "AU915":
|
||||||
|
lorawan.UseRegionSettings(region.AU915())
|
||||||
|
case "EU868":
|
||||||
|
lorawan.UseRegionSettings(region.EU868())
|
||||||
|
case "US915":
|
||||||
|
lorawan.UseRegionSettings(region.US915())
|
||||||
|
default:
|
||||||
|
lorawan.UseRegionSettings(region.EU868())
|
||||||
|
}
|
||||||
|
|
||||||
// Configure AppEUI, DevEUI, APPKey, and public/private Lorawan Network
|
// Configure AppEUI, DevEUI, APPKey, and public/private Lorawan Network
|
||||||
setLorawanKeys()
|
setLorawanKeys()
|
||||||
|
|||||||
@@ -23,13 +23,18 @@ func (sr *SimLoraRadio) Rx(timeoutMs uint32) ([]uint8, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
|
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
|
||||||
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
|
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
|
||||||
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
||||||
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
||||||
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
||||||
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
||||||
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
func (sr *SimLoraRadio) SetHeaderType(headerType uint8) {}
|
||||||
|
func (sr *SimLoraRadio) SetPreambleLength(pLen uint16) {}
|
||||||
|
func (sr *SimLoraRadio) SetPublicNetwork(enabled bool) {}
|
||||||
|
func (sr *SimLoraRadio) SetSyncWord(syncWord uint16) {}
|
||||||
|
func (sr *SimLoraRadio) SetTxPower(txPower int8) {}
|
||||||
|
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
||||||
|
|
||||||
func FirmwareVersion() string {
|
func FirmwareVersion() string {
|
||||||
return "simulator " + CurrentVersion()
|
return "simulator " + CurrentVersion()
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
// This example gets an URL using http.Get(). URL scheme can be http or https.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
//
|
||||||
|
// Some targets (Arduino Nano33 IoT) don't have enough SRAM to run http.Get().
|
||||||
|
// Use the following for those targets:
|
||||||
|
//
|
||||||
|
// examples/net/webclient (for HTTP)
|
||||||
|
// examples/net/tlsclient (for HTTPS)
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := "John Doe"
|
||||||
|
occupation := "gardener"
|
||||||
|
|
||||||
|
params := "name=" + url.QueryEscape(name) + "&" +
|
||||||
|
"occupation=" + url.QueryEscape(occupation)
|
||||||
|
|
||||||
|
path := fmt.Sprintf("https://httpbin.org/get?%s", params)
|
||||||
|
|
||||||
|
cnt := 0
|
||||||
|
for {
|
||||||
|
fmt.Printf("Getting %s\r\n\r\n", path)
|
||||||
|
resp, err := http.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\r\n", err.Error())
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s %s\r\n", resp.Proto, resp.Status)
|
||||||
|
for k, v := range resp.Header {
|
||||||
|
fmt.Printf("%s: %s\r\n", k, strings.Join(v, " "))
|
||||||
|
}
|
||||||
|
fmt.Printf("\r\n")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
println(string(body))
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
cnt++
|
||||||
|
fmt.Printf("-------- %d --------\r\n", cnt)
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// This example gets an URL using http.Head(). URL scheme can be http or https.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
//
|
||||||
|
// Some targets (Arduino Nano33 IoT) don't have enough SRAM to run http.Head().
|
||||||
|
// Use the following for those targets:
|
||||||
|
//
|
||||||
|
// examples/net/webclient (for HTTP)
|
||||||
|
// examples/net/tlsclient (for HTTPS)
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
url string = "https://httpbin.org"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Head(url)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := resp.Write(&buf); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(buf.Bytes()))
|
||||||
|
|
||||||
|
link.NetDisconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
// This example posts an URL using http.Post(). URL scheme can be http or https.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
//
|
||||||
|
// Some targets (Arduino Nano33 IoT) don't have enough SRAM to run http.Post().
|
||||||
|
// Use the following for those targets:
|
||||||
|
//
|
||||||
|
// examples/net/webclient (for HTTP)
|
||||||
|
// examples/net/tlsclient (for HTTPS)
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := "https://httpbin.org/post"
|
||||||
|
data := []byte("{\"name\":\"John Doe\",\"occupation\":\"gardener\"}")
|
||||||
|
|
||||||
|
resp, err := http.Post(path, "application/json", bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(body))
|
||||||
|
|
||||||
|
link.NetDisconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// This example posts an URL using http.PostForm(). URL scheme can be http or https.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
//
|
||||||
|
// Some targets (Arduino Nano33 IoT) don't have enough SRAM to run
|
||||||
|
// http.PostForm(). Use the following for those targets:
|
||||||
|
//
|
||||||
|
// examples/net/webclient (for HTTP)
|
||||||
|
// examples/net/tlsclient (for HTTPS)
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := "https://httpbin.org/post"
|
||||||
|
data := url.Values{
|
||||||
|
"name": {"John Doe"},
|
||||||
|
"occupation": {"gardener"},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.PostForm(path, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
// This example is an MQTT client built with the natiu-mqtt package. It sends
|
||||||
|
// machine.CPUFrequency() readings to the broker every second for 10 seconds.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using
|
||||||
|
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal || challenger_rp2040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mqtt "github.com/soypat/natiu-mqtt"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
broker string = "test.mosquitto.org:1883"
|
||||||
|
topic string = "cpu/freq"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId := "tinygo-client-" + randomString(10)
|
||||||
|
fmt.Printf("ClientId: %s\n", clientId)
|
||||||
|
|
||||||
|
// Get a transport for MQTT packets
|
||||||
|
fmt.Printf("Connecting to MQTT broker at %s\n", broker)
|
||||||
|
conn, err := net.Dial("tcp", broker)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// Create new client
|
||||||
|
client := mqtt.NewClient(mqtt.ClientConfig{
|
||||||
|
Decoder: mqtt.DecoderNoAlloc{make([]byte, 1500)},
|
||||||
|
OnPub: func(_ mqtt.Header, _ mqtt.VariablesPublish, r io.Reader) error {
|
||||||
|
message, _ := io.ReadAll(r)
|
||||||
|
fmt.Printf("Message %s received on topic %s\n", string(message), topic)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Connect client
|
||||||
|
var varconn mqtt.VariablesConnect
|
||||||
|
varconn.SetDefaultMQTT([]byte(clientId))
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
err = client.Connect(ctx, conn, &varconn)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to connect: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to topic
|
||||||
|
ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
err = client.Subscribe(ctx, mqtt.VariablesSubscribe{
|
||||||
|
PacketIdentifier: 23,
|
||||||
|
TopicFilters: []mqtt.SubscribeRequest{
|
||||||
|
{TopicFilter: []byte(topic), QoS: mqtt.QoS0},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to subscribe to", topic, err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Subscribed to topic %s\n", topic)
|
||||||
|
|
||||||
|
// Publish on topic
|
||||||
|
pubFlags, _ := mqtt.NewPublishFlags(mqtt.QoS0, false, false)
|
||||||
|
pubVar := mqtt.VariablesPublish{
|
||||||
|
TopicName: []byte(topic),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if !client.IsConnected() {
|
||||||
|
log.Fatal("client disconnected: ", client.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
freq := float32(machine.CPUFrequency()) / 1000000
|
||||||
|
payload := fmt.Sprintf("%.02fMhz", freq)
|
||||||
|
|
||||||
|
pubVar.PacketIdentifier++
|
||||||
|
err = client.PublishPayload(pubFlags, pubVar, []byte(payload))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("error transmitting message: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
err = client.HandleNext()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("handle next: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Disconnect(errors.New("disconnected gracefully"))
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
// This example is an MQTT client built with the paho-mqtt package. It sends
|
||||||
|
// machine.CPUFrequency() readings to the broker every second for 10 seconds.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using
|
||||||
|
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal || challenger_rp2040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
broker string = "tcp://test.mosquitto.org:1883"
|
||||||
|
)
|
||||||
|
|
||||||
|
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
|
||||||
|
fmt.Printf("Message %s received on topic %s\n", msg.Payload(), msg.Topic())
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
|
||||||
|
fmt.Println("Connected")
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
|
||||||
|
fmt.Printf("Connection Lost: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId := "tinygo-client-" + randomString(10)
|
||||||
|
fmt.Printf("ClientId: %s\n", clientId)
|
||||||
|
|
||||||
|
options := mqtt.NewClientOptions()
|
||||||
|
options.AddBroker(broker)
|
||||||
|
options.SetClientID(clientId)
|
||||||
|
options.SetDefaultPublishHandler(messagePubHandler)
|
||||||
|
options.OnConnect = connectHandler
|
||||||
|
options.OnConnectionLost = connectionLostHandler
|
||||||
|
|
||||||
|
fmt.Printf("Connecting to MQTT broker at %s\n", broker)
|
||||||
|
client := mqtt.NewClient(options)
|
||||||
|
token := client.Connect()
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
panic(token.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
topic := "cpu/freq"
|
||||||
|
token = client.Subscribe(topic, 1, nil)
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
panic(token.Error())
|
||||||
|
}
|
||||||
|
fmt.Printf("Subscribed to topic %s\n", topic)
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
freq := float32(machine.CPUFrequency()) / 1000000
|
||||||
|
payload := fmt.Sprintf("%.02fMhz", freq)
|
||||||
|
token = client.Publish(topic, 0, false, payload)
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
panic(token.Error())
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Disconnect(100)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
// This is an example of an NTP client.
|
||||||
|
//
|
||||||
|
// It creates a UDP connection to request the current time and parse the
|
||||||
|
// response from a NTP server. The system time is set to NTP time.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal || challenger_rp2040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
// IP address of the server aka "hub". Replace with your own info.
|
||||||
|
ntpHost string = "0.pool.ntp.org:123"
|
||||||
|
)
|
||||||
|
|
||||||
|
const NTP_PACKET_SIZE = 48
|
||||||
|
|
||||||
|
var response = make([]byte, NTP_PACKET_SIZE)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.Dial("udp", ntpHost)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Requesting NTP time...")
|
||||||
|
|
||||||
|
t, err := getCurrentTime(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Sprintf("Error getting current time: %v", err))
|
||||||
|
} else {
|
||||||
|
message("NTP time: %v", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.Close()
|
||||||
|
link.NetDisconnect()
|
||||||
|
|
||||||
|
runtime.AdjustTimeOffset(-1 * int64(time.Since(t)))
|
||||||
|
|
||||||
|
for {
|
||||||
|
message("Current time: %v", time.Now())
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCurrentTime(conn net.Conn) (time.Time, error) {
|
||||||
|
if err := sendNTPpacket(conn); err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := conn.Read(response)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if n != NTP_PACKET_SIZE {
|
||||||
|
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseNTPpacket(response), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendNTPpacket(conn net.Conn) error {
|
||||||
|
var request = [48]byte{
|
||||||
|
0xe3,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := conn.Write(request[:])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNTPpacket(r []byte) time.Time {
|
||||||
|
// the timestamp starts at byte 40 of the received packet and is four bytes,
|
||||||
|
// this is NTP time (seconds since Jan 1 1900):
|
||||||
|
t := uint32(r[40])<<24 | uint32(r[41])<<16 | uint32(r[42])<<8 | uint32(r[43])
|
||||||
|
const seventyYears = 2208988800
|
||||||
|
return time.Unix(int64(t-seventyYears), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func message(format string, args ...interface{}) {
|
||||||
|
println(fmt.Sprintf(format, args...), "\r")
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
// This example opens a TCP connection and sends some data using netdev sockets.
|
||||||
|
//
|
||||||
|
// You can open a server to accept connections from this program using:
|
||||||
|
//
|
||||||
|
// nc -lk 8080
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal || challenger_rp2040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netdev"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
addr string = "10.0.0.100:8080"
|
||||||
|
)
|
||||||
|
|
||||||
|
var buf = &bytes.Buffer{}
|
||||||
|
var link netlink.Netlinker
|
||||||
|
var dev netdev.Netdever
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, dev = probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
sendBatch()
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendBatch() {
|
||||||
|
|
||||||
|
addrPort, _ := netip.ParseAddrPort(addr)
|
||||||
|
|
||||||
|
// make TCP connection
|
||||||
|
message("---------------\r\nDialing TCP connection")
|
||||||
|
fd, _ := dev.Socket(netdev.AF_INET, netdev.SOCK_STREAM, netdev.IPPROTO_TCP)
|
||||||
|
err := dev.Connect(fd, "", addrPort)
|
||||||
|
for ; err != nil; err = dev.Connect(fd, "", addrPort) {
|
||||||
|
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 = dev.Send(fd, buf.Bytes(), 0, time.Time{}); err != nil {
|
||||||
|
println("error:", err.Error(), "\r")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
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 := dev.Send(fd, buf.Bytes(), 0, time.Time{}); err != nil {
|
||||||
|
println("error:", err.Error(), "\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Disconnecting TCP...")
|
||||||
|
dev.Close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func message(msg string) {
|
||||||
|
println(msg, "\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,52 +1,60 @@
|
|||||||
// This example opens a TCP connection and sends some data,
|
// This example opens a TCP connection and sends some data, for the purpose of
|
||||||
// for the purpose of testing speed and connectivity.
|
// testing speed and connectivity.
|
||||||
//
|
//
|
||||||
// You can open a server to accept connections from this program using:
|
// You can open a server to accept connections from this program using:
|
||||||
//
|
//
|
||||||
// nc -w 5 -lk 8080
|
// nc -lk 8080
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal || challenger_rp2040 || pico
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// access point info
|
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
pass string
|
||||||
|
addr string = "10.0.0.100:8080"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
const serverIP = ""
|
|
||||||
|
|
||||||
var buf = &bytes.Buffer{}
|
var buf = &bytes.Buffer{}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
initAdaptor()
|
|
||||||
|
|
||||||
connectToAP()
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
sendBatch()
|
sendBatch()
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
println("Done.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendBatch() {
|
func sendBatch() {
|
||||||
|
|
||||||
// make TCP connection
|
// make TCP connection
|
||||||
ip := net.ParseIP(serverIP)
|
|
||||||
raddr := &net.TCPAddr{IP: ip, Port: 8080}
|
|
||||||
laddr := &net.TCPAddr{Port: 8080}
|
|
||||||
|
|
||||||
message("---------------\r\nDialing TCP connection")
|
message("---------------\r\nDialing TCP connection")
|
||||||
conn, err := net.DialTCP("tcp", laddr, raddr)
|
conn, err := net.Dial("tcp", addr)
|
||||||
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
for ; err != nil; conn, err = net.Dial("tcp", addr) {
|
||||||
message(err.Error())
|
message(err.Error())
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
}
|
}
|
||||||
@@ -65,7 +73,7 @@ func sendBatch() {
|
|||||||
"\r---------------------------- i == ", i, " ----------------------------")
|
"\r---------------------------- i == ", i, " ----------------------------")
|
||||||
if w, err = conn.Write(buf.Bytes()); err != nil {
|
if w, err = conn.Write(buf.Bytes()); err != nil {
|
||||||
println("error:", err.Error(), "\r")
|
println("error:", err.Error(), "\r")
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
n += w
|
n += w
|
||||||
}
|
}
|
||||||
@@ -79,34 +87,17 @@ func sendBatch() {
|
|||||||
println("error:", err.Error(), "\r")
|
println("error:", err.Error(), "\r")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting TCP...")
|
println("Disconnecting TCP...")
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil { // error connecting to AP
|
|
||||||
for {
|
|
||||||
println(err)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
ip, err := adaptor.GetClientIP()
|
|
||||||
for ; err != nil; ip, err = adaptor.GetClientIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
func message(msg string) {
|
||||||
println(msg, "\r")
|
println(msg, "\r")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// This example listens on port :8080 for client connections. Bytes
|
||||||
|
// received from the client are echo'ed back to the client. Multiple
|
||||||
|
// clients can connect as the same time, each consuming a client socket,
|
||||||
|
// and being serviced by it's own go func.
|
||||||
|
//
|
||||||
|
// Example test using nc as client to copy file:
|
||||||
|
//
|
||||||
|
// $ nc 10.0.0.2 8080 <file >copy ; cmp file copy
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
port string = ":8080"
|
||||||
|
)
|
||||||
|
|
||||||
|
var buf [1024]byte
|
||||||
|
|
||||||
|
func echo(conn net.Conn) {
|
||||||
|
println("Client", conn.RemoteAddr(), "connected")
|
||||||
|
defer conn.Close()
|
||||||
|
_, err := io.CopyBuffer(conn, conn, buf[:])
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
println("Client", conn.RemoteAddr(), "closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Starting TCP server listening on", port)
|
||||||
|
l, err := net.Listen("tcp", port)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
go echo(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// This example uses TLS to send an HTTPS request to retrieve a webpage
|
||||||
|
//
|
||||||
|
// You shall see "strict-transport-security" header in the response,
|
||||||
|
// this confirms communication is indeed over HTTPS
|
||||||
|
//
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
// HTTPS server address to hit with a GET / request
|
||||||
|
address string = "httpbin.org:443"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conn net.Conn
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
println("Hit an error:", err.Error())
|
||||||
|
panic("BYE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readResponse() {
|
||||||
|
r := bufio.NewReader(conn)
|
||||||
|
resp, err := io.ReadAll(r)
|
||||||
|
check(err)
|
||||||
|
println(string(resp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeConnection() {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialConnection() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
println("\r\n---------------\r\nDialing TLS connection")
|
||||||
|
conn, err = tls.Dial("tcp", address, nil)
|
||||||
|
for ; err != nil; conn, err = tls.Dial("tcp", address, nil) {
|
||||||
|
println("Connection failed:", err.Error())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
println("Connected!\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRequest() {
|
||||||
|
print("Sending HTTPS request...")
|
||||||
|
w := bufio.NewWriter(conn)
|
||||||
|
fmt.Fprintln(w, "GET /get HTTP/1.1")
|
||||||
|
fmt.Fprintln(w, "Host:", strings.Split(address, ":")[0])
|
||||||
|
fmt.Fprintln(w, "User-Agent: TinyGo")
|
||||||
|
fmt.Fprintln(w, "Connection: close")
|
||||||
|
fmt.Fprintln(w)
|
||||||
|
check(w.Flush())
|
||||||
|
println("Sent!\r\n\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
dialConnection()
|
||||||
|
makeRequest()
|
||||||
|
readResponse()
|
||||||
|
closeConnection()
|
||||||
|
println("--------", i, "--------\r\n")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// This example runs on wioterminal. It gets an URL using http.Get() and
|
||||||
|
// displays the output on the wioterminal LCD screen.
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ili9341"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
"tinygo.org/x/tinyfont/proggy"
|
||||||
|
"tinygo.org/x/tinyterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
display = ili9341.NewSPI(
|
||||||
|
machine.SPI3,
|
||||||
|
machine.LCD_DC,
|
||||||
|
machine.LCD_SS_PIN,
|
||||||
|
machine.LCD_RESET,
|
||||||
|
)
|
||||||
|
|
||||||
|
backlight = machine.LCD_BACKLIGHT
|
||||||
|
|
||||||
|
terminal = tinyterm.NewTerminal(display)
|
||||||
|
|
||||||
|
black = color.RGBA{0, 0, 0, 255}
|
||||||
|
white = color.RGBA{255, 255, 255, 255}
|
||||||
|
red = color.RGBA{255, 0, 0, 255}
|
||||||
|
blue = color.RGBA{0, 0, 255, 255}
|
||||||
|
green = color.RGBA{0, 255, 0, 255}
|
||||||
|
|
||||||
|
font = &proggy.TinySZ8pt7b
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
machine.SPI3.Configure(machine.SPIConfig{
|
||||||
|
SCK: machine.LCD_SCK_PIN,
|
||||||
|
SDO: machine.LCD_SDO_PIN,
|
||||||
|
SDI: machine.LCD_SDI_PIN,
|
||||||
|
Frequency: 40000000,
|
||||||
|
})
|
||||||
|
|
||||||
|
display.Configure(ili9341.Config{})
|
||||||
|
display.FillScreen(black)
|
||||||
|
|
||||||
|
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||||
|
backlight.High()
|
||||||
|
|
||||||
|
terminal.Configure(&tinyterm.Config{
|
||||||
|
Font: font,
|
||||||
|
FontHeight: 10,
|
||||||
|
FontOffset: 6,
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Fprintf(terminal, "Connecting to %s...\r\n", ssid)
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := "John Doe"
|
||||||
|
occupation := "gardener"
|
||||||
|
|
||||||
|
params := "name=" + url.QueryEscape(name) + "&" +
|
||||||
|
"occupation=" + url.QueryEscape(occupation)
|
||||||
|
|
||||||
|
path := fmt.Sprintf("https://httpbin.org/get?%s", params)
|
||||||
|
|
||||||
|
cnt := 0
|
||||||
|
for {
|
||||||
|
fmt.Fprintf(terminal, "Getting %s\r\n\r\n", path)
|
||||||
|
resp, err := http.Get(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(terminal, "%s\r\n", err.Error())
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(terminal, "%s %s\r\n", resp.Proto, resp.Status)
|
||||||
|
for k, v := range resp.Header {
|
||||||
|
fmt.Fprintf(terminal, "%s: %s\r\n", k, strings.Join(v, " "))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(terminal, "\r\n")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
fmt.Fprintf(terminal, string(body))
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
cnt++
|
||||||
|
fmt.Fprintf(terminal, "-------- %d --------\r\n", cnt)
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// This example uses TCP to send an HTTP request to retrieve a webpage. The
|
||||||
|
// HTTP request is hand-rolled to avoid the overhead of using http.Get() from
|
||||||
|
// the "net/http" package. See example/net/http-get for the full http.Get()
|
||||||
|
// functionality.
|
||||||
|
//
|
||||||
|
// Example HTTP server:
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import "net/http"
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// w.Write([]byte("hello"))
|
||||||
|
// })
|
||||||
|
// http.ListenAndServe(":8080", nil)
|
||||||
|
// }
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
// HTTP server address to hit with a GET / request
|
||||||
|
address string = "10.0.0.100:8080"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conn net.Conn
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialConnection() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
println("\r\n---------------\r\nDialing TCP connection")
|
||||||
|
conn, err = net.Dial("tcp", address)
|
||||||
|
for ; err != nil; conn, err = net.Dial("tcp", address) {
|
||||||
|
println("Connection failed:", err.Error())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
println("Connected!\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
println("Hit an error:", err.Error())
|
||||||
|
panic("BYE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRequest() {
|
||||||
|
println("Sending HTTP request...")
|
||||||
|
w := bufio.NewWriter(conn)
|
||||||
|
fmt.Fprintln(w, "GET / HTTP/1.1")
|
||||||
|
fmt.Fprintln(w, "Host:", strings.Split(address, ":")[0])
|
||||||
|
fmt.Fprintln(w, "User-Agent: TinyGo")
|
||||||
|
fmt.Fprintln(w, "Connection: close")
|
||||||
|
fmt.Fprintln(w)
|
||||||
|
check(w.Flush())
|
||||||
|
println("Sent!\r\n\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readResponse() {
|
||||||
|
r := bufio.NewReader(conn)
|
||||||
|
resp, err := io.ReadAll(r)
|
||||||
|
check(err)
|
||||||
|
println(string(resp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeConnection() {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
dialConnection()
|
||||||
|
makeRequest()
|
||||||
|
readResponse()
|
||||||
|
closeConnection()
|
||||||
|
println("--------", i, "--------\r\n")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,72 +1,64 @@
|
|||||||
|
// This example listens on port :80 serving a web page. Multiple clients
|
||||||
|
// may connect and be serviced at the same time. IPv4 only. HTTP only.
|
||||||
|
//
|
||||||
|
// $ curl http://10.0.0.2
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"machine"
|
"machine"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
"tinygo.org/x/drivers/netlink"
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// debug = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
pass string
|
||||||
debug = false
|
port string = ":80"
|
||||||
)
|
)
|
||||||
|
|
||||||
var led = machine.LED
|
var led = machine.LED
|
||||||
var backlight = machine.LCD_BACKLIGHT
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
// wait a bit for serial
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
backlight.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
|
|
||||||
err := run()
|
link, _ := probe.Probe()
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
Ssid: ssid,
|
||||||
adaptor.Debug(debug)
|
Passphrase: pass,
|
||||||
adaptor.Configure()
|
})
|
||||||
|
|
||||||
http.UseDriver(adaptor)
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
http.HandleFunc("/", root)
|
http.HandleFunc("/", root)
|
||||||
http.HandleFunc("/hello", hello)
|
http.HandleFunc("/hello", hello)
|
||||||
http.HandleFunc("/cnt", cnt)
|
http.HandleFunc("/cnt", cnt)
|
||||||
http.HandleFunc("/6", sixlines)
|
http.HandleFunc("/6", sixlines)
|
||||||
http.HandleFunc("/off", LED_OFF)
|
http.HandleFunc("/off", LED_OFF)
|
||||||
http.HandleFunc("/on", LED_ON)
|
http.HandleFunc("/on", LED_ON)
|
||||||
if err := http.ListenAndServe(":80", nil); err != nil {
|
|
||||||
message(err.Error())
|
err = http.ListenAndServe(port, nil)
|
||||||
|
for err != nil {
|
||||||
|
fmt.Printf("error: %s\r\n", err.Error())
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func root(w http.ResponseWriter, r *http.Request) {
|
func root(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -101,8 +93,8 @@ func root(w http.ResponseWriter, r *http.Request) {
|
|||||||
<title>TinyGo HTTP Server</title>
|
<title>TinyGo HTTP Server</title>
|
||||||
<script language="javascript" type="text/javascript">
|
<script language="javascript" type="text/javascript">
|
||||||
var counter = 0
|
var counter = 0
|
||||||
function ledOn() { fetch("/on").then(response => response.text()).then(text => { led.innerHTML = "<p>on</p>"; }); }
|
function ledOn() { fetch("/on"); }
|
||||||
function ledOff() { fetch("/off").then(response => response.text()).then(text => { led.innerHTML = "<p>off</p>"; }); }
|
function ledOff() { fetch("/off"); }
|
||||||
function fetchCnt() { fetch("/cnt").then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
function fetchCnt() { fetch("/cnt").then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
||||||
function incrCnt() { counter = counter + 1; fetch("/cnt?cnt=" + counter, { method: 'POST' }).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
function incrCnt() { counter = counter + 1; fetch("/cnt?cnt=" + counter, { method: 'POST' }).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
||||||
function setCnt() { fetch("/cnt", {
|
function setCnt() { fetch("/cnt", {
|
||||||
@@ -141,7 +133,7 @@ func root(w http.ResponseWriter, r *http.Request) {
|
|||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`, access)
|
`, access)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sixlines(w http.ResponseWriter, r *http.Request) {
|
func sixlines(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -155,14 +147,12 @@ func sixlines(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func LED_ON(w http.ResponseWriter, r *http.Request) {
|
func LED_ON(w http.ResponseWriter, r *http.Request) {
|
||||||
led.High()
|
led.High()
|
||||||
backlight.High()
|
|
||||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||||
fmt.Fprintf(w, "led.High()")
|
fmt.Fprintf(w, "led.High()")
|
||||||
}
|
}
|
||||||
|
|
||||||
func LED_OFF(w http.ResponseWriter, r *http.Request) {
|
func LED_OFF(w http.ResponseWriter, r *http.Request) {
|
||||||
led.Low()
|
led.Low()
|
||||||
backlight.Low()
|
|
||||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||||
fmt.Fprintf(w, "led.Low()")
|
fmt.Fprintf(w, "led.Low()")
|
||||||
}
|
}
|
||||||
@@ -187,7 +177,3 @@ func cnt(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set(`Content-Type`, `application/json`)
|
w.Header().Set(`Content-Type`, `application/json`)
|
||||||
fmt.Fprintf(w, `{"cnt": %d}`, counter)
|
fmt.Fprintf(w, `{"cnt": %d}`, counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// This example is a websocket client. It connects to a websocket server
|
||||||
|
// which echos messages back to the client. For server, see
|
||||||
|
//
|
||||||
|
// https://pkg.go.dev/golang.org/x/net/websocket#example-Handler
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using
|
||||||
|
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
url string = "ws://10.0.0.100:8080/echo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
origin := "http://localhost/"
|
||||||
|
ws, err := websocket.Dial(url, "", origin)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
var msg = make([]byte, 512)
|
||||||
|
var n int
|
||||||
|
if n, err = ws.Read(msg); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Received: %s", msg[:n])
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// This example is a websocket server. It listens for websocket clients
|
||||||
|
// to connect and echos messages back to the client. For client, see
|
||||||
|
//
|
||||||
|
// https://pkg.go.dev/golang.org/x/net/websocket#example-Dial
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using
|
||||||
|
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"machine"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
port string = ":8080"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Echo the data received on the WebSocket.
|
||||||
|
func EchoServer(ws *websocket.Conn) {
|
||||||
|
io.Copy(ws, ws)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates a trivial echo server.
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Handle("/echo", websocket.Handler(EchoServer))
|
||||||
|
err = http.ListenAndServe(port, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic("ListenAndServe: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,28 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>TinyGo - A Go Compiler For Small Places</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: rgb(4, 111, 143);
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 299px;
|
||||||
|
height: 255px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>TinyGo - A Go Compiler For Small Places</h1>
|
||||||
|
<img src="images/tinygo-logo.png">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// This example is an HTTP server serving up a static file system
|
||||||
|
//
|
||||||
|
// Note: It may be necessary to increase the stack size when using "net/http".
|
||||||
|
// Use the -stack-size=4KB command line option.
|
||||||
|
|
||||||
|
//go:build ninafw || wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/netlink"
|
||||||
|
"tinygo.org/x/drivers/netlink/probe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ssid string
|
||||||
|
pass string
|
||||||
|
port string = ":80"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed index.html main.go images
|
||||||
|
var fs embed.FS
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// wait a bit for console
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
|
err := link.NetConnect(&netlink.ConnectParams{
|
||||||
|
Ssid: ssid,
|
||||||
|
Passphrase: pass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hfs := http.FileServer(http.FS(fs))
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hfs.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(port, nil))
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
"tinygo.org/x/drivers/pcf8523"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
dev := pcf8523.New(machine.I2C0)
|
||||||
|
|
||||||
|
// make sure the battery takes over if power is lost
|
||||||
|
err := dev.SetPowerManagement(pcf8523.PowerManagement_SwitchOver_ModeStandard)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set RTC once, i.e. from `date -u +"%Y-%m-%dT%H:%M:%SZ"`
|
||||||
|
now, _ := time.Parse(time.RFC3339, "2023-09-18T20:31:38Z")
|
||||||
|
err = dev.SetTime(now)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
ts, err := dev.ReadTime()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
println("tick-tock, it's: " + ts.String())
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
// This is a sensor station that uses a RTL8720DN running on the device UART2.
|
|
||||||
// It creates an MQTT connection that publishes a message every second
|
|
||||||
// to an MQTT broker.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> USB-CDC <--> MCU <--> UART2 <--> RTL8720DN <--> Internet <--> MQTT broker.
|
|
||||||
//
|
|
||||||
// You must install the Paho MQTT package to build this program:
|
|
||||||
//
|
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
|
||||||
//
|
|
||||||
// You can check that mqttpub is running successfully with the following command.
|
|
||||||
//
|
|
||||||
// mosquitto_sub -h test.mosquitto.org -t tinygo
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/mqtt"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// debug = true
|
|
||||||
// server = "tinygo.org"
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
server string = "tcp://test.mosquitto.org:1883"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
var adaptor *rtl8720dn.Driver
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
topic = "tinygo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
// change the UART and pins as needed for platforms other than the WioTerminal.
|
|
||||||
adaptor = rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting MQTT...")
|
|
||||||
cl.Disconnect(100)
|
|
||||||
|
|
||||||
println("Done.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
// This is a sensor station that uses a RTL8720DN running on the device UART2.
|
|
||||||
// It creates an MQTT connection that publishes a message every second
|
|
||||||
// to an MQTT broker.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> USB-CDC <--> MCU <--> UART2 <--> RTL8720DN <--> Internet <--> MQTT broker.
|
|
||||||
//
|
|
||||||
// You must also install the Paho MQTT package to build this program:
|
|
||||||
//
|
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
|
||||||
//
|
|
||||||
// You can check that mqttpub/mqttsub is running successfully with the following command.
|
|
||||||
//
|
|
||||||
// mosquitto_sub -h test.mosquitto.org -t tinygo/tx
|
|
||||||
// mosquitto_pub -h test.mosquitto.org -t tinygo/rx -m "hello world"
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/mqtt"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// debug = true
|
|
||||||
// server = "tinygo.org"
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
server string = "tcp://test.mosquitto.org:1883"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
var adaptor *rtl8720dn.Driver
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
|
||||||
var (
|
|
||||||
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 run() error {
|
|
||||||
// change the UART and pins as needed for platforms other than the WioTerminal.
|
|
||||||
adaptor = rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
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.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func publishing() {
|
|
||||||
for i := 0; ; i++ {
|
|
||||||
println("Publishing MQTT message...")
|
|
||||||
data := []byte(fmt.Sprintf(`{"e":[{"n":"hello %d","v":101}]}`, i))
|
|
||||||
token := cl.Publish(topicTx, 0, false, data)
|
|
||||||
token.Wait()
|
|
||||||
if token.Error() != nil {
|
|
||||||
println(token.Error().Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(20 * 100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
// This is an example of using the rtl8720dn driver to implement a NTP client.
|
|
||||||
// It creates a UDP connection to request the current time and parse the
|
|
||||||
// response from a NTP server.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// ntpHost = "129.6.15.29"
|
|
||||||
// debug = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
ntpHost = "129.6.15.29"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
const NTP_PACKET_SIZE = 48
|
|
||||||
|
|
||||||
var b = make([]byte, NTP_PACKET_SIZE)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
hip := net.ParseIP(ntpHost)
|
|
||||||
raddr := &net.UDPAddr{IP: hip, Port: 123}
|
|
||||||
laddr := &net.UDPAddr{Port: 2390}
|
|
||||||
conn, err := net.DialUDP("udp", laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Requesting NTP time...")
|
|
||||||
t, err := getCurrentTime(conn)
|
|
||||||
if err != nil {
|
|
||||||
message("Error getting current time: %v", err)
|
|
||||||
} else {
|
|
||||||
message("NTP time: %v", t)
|
|
||||||
}
|
|
||||||
runtime.AdjustTimeOffset(-1 * int64(time.Since(t)))
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
message("Current time: %v", time.Now())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
|
|
||||||
if err := sendNTPpacket(conn); err != nil {
|
|
||||||
return time.Time{}, err
|
|
||||||
}
|
|
||||||
clearBuffer()
|
|
||||||
for now := time.Now(); time.Since(now) < time.Second; {
|
|
||||||
time.Sleep(5 * time.Millisecond)
|
|
||||||
if n, err := conn.Read(b); err != nil {
|
|
||||||
return time.Time{}, fmt.Errorf("error reading UDP packet: %w", err)
|
|
||||||
} else if n == 0 {
|
|
||||||
continue // no packet received yet
|
|
||||||
} else if n != NTP_PACKET_SIZE {
|
|
||||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
|
||||||
}
|
|
||||||
return parseNTPpacket(), nil
|
|
||||||
}
|
|
||||||
return time.Time{}, errors.New("no packet received after 1 second")
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendNTPpacket(conn *net.UDPSerialConn) error {
|
|
||||||
clearBuffer()
|
|
||||||
b[0] = 0b11100011 // LI, Version, Mode
|
|
||||||
b[1] = 0 // Stratum, or type of clock
|
|
||||||
b[2] = 6 // Polling Interval
|
|
||||||
b[3] = 0xEC // Peer Clock Precision
|
|
||||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
|
||||||
b[12] = 49
|
|
||||||
b[13] = 0x4E
|
|
||||||
b[14] = 49
|
|
||||||
b[15] = 52
|
|
||||||
if _, err := conn.Write(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseNTPpacket() time.Time {
|
|
||||||
// the timestamp starts at byte 40 of the received packet and is four bytes,
|
|
||||||
// this is NTP time (seconds since Jan 1 1900):
|
|
||||||
t := uint32(b[40])<<24 | uint32(b[41])<<16 | uint32(b[42])<<8 | uint32(b[43])
|
|
||||||
const seventyYears = 2208988800
|
|
||||||
return time.Unix(int64(t-seventyYears), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func clearBuffer() {
|
|
||||||
for i := range b {
|
|
||||||
b[i] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(format string, args ...interface{}) {
|
|
||||||
println(fmt.Sprintf(format, args...), "\r")
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
// This example opens a TCP connection using a device with RTL8720DN 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 (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// serverIP = "192.168.1.119"
|
|
||||||
// debug = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
serverIP = ""
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf = &bytes.Buffer{}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
for {
|
|
||||||
sendBatch()
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
|
||||||
println("Done.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// debug = true
|
|
||||||
// url = "https://www.example.com"
|
|
||||||
// test_root_ca = "..."
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
url string = "https://www.example.com"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set the test_root_ca created by the following command
|
|
||||||
// $ openssl s_client -showcerts -verify 5 -connect www.example.com:443 < /dev/null
|
|
||||||
var test_root_ca = `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
|
||||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
|
||||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
|
||||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
|
||||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
|
||||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
|
||||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
|
||||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
|
||||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
|
||||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
|
||||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
|
||||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
|
||||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
|
||||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
|
||||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
|
||||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
|
||||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
|
||||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
|
||||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
|
||||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
`
|
|
||||||
|
|
||||||
var buf [0x1000]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
adaptor.SetRootCA(&test_root_ca)
|
|
||||||
http.SetBuf(buf[:])
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
// You can send and receive cookies in the following way
|
|
||||||
// import "tinygo.org/x/drivers/net/http/cookiejar"
|
|
||||||
// jar, err := cookiejar.New(nil)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// client := &http.Client{Jar: jar}
|
|
||||||
// http.DefaultClient = client
|
|
||||||
|
|
||||||
cnt := 0
|
|
||||||
for {
|
|
||||||
// Various examples are as follows
|
|
||||||
//
|
|
||||||
// -- Get
|
|
||||||
// resp, err := http.Get(url)
|
|
||||||
//
|
|
||||||
// -- Post
|
|
||||||
// body := `cnt=12`
|
|
||||||
// resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(body))
|
|
||||||
//
|
|
||||||
// -- Post with JSON
|
|
||||||
// body := `{"msg": "hello"}`
|
|
||||||
// resp, err := http.Post(url, "application/json", strings.NewReader(body))
|
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s %s\r\n", resp.Proto, resp.Status)
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
fmt.Printf("%s: %s\r\n", k, strings.Join(v, " "))
|
|
||||||
}
|
|
||||||
fmt.Printf("\r\n")
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(resp.Body)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fmt.Printf("%s\r\n", scanner.Text())
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
cnt++
|
|
||||||
fmt.Printf("-------- %d --------\r\n", cnt)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// hubIP = "192.168.1.118"
|
|
||||||
// debug = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
hubIP = ""
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
http.SetBuf(buf[:])
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
hip := net.ParseIP(hubIP)
|
|
||||||
raddr := &net.UDPAddr{IP: hip, Port: 2222}
|
|
||||||
laddr := &net.UDPAddr{Port: 2222}
|
|
||||||
|
|
||||||
println("Dialing UDP connection...")
|
|
||||||
conn, err := net.DialUDP("udp", laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Sending data...")
|
|
||||||
for i := 0; i < 25; i++ {
|
|
||||||
conn.Write([]byte("hello " + strconv.Itoa(i) + "\r\n"))
|
|
||||||
}
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting UDP...")
|
|
||||||
conn.Close()
|
|
||||||
println("Done.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
ver, err := adaptor.Version()
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
fmt.Printf("RTL8270DN Firmware Version: %s\r\n", ver)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"image/color"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ili9341"
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
|
|
||||||
"tinygo.org/x/tinyfont/proggy"
|
|
||||||
"tinygo.org/x/tinyterm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// If debug is enabled, a serial connection is required.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// debug = false // true
|
|
||||||
// server = "tinygo.org"
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
url = "http://tinygo.org/"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
display = ili9341.NewSPI(
|
|
||||||
machine.SPI3,
|
|
||||||
machine.LCD_DC,
|
|
||||||
machine.LCD_SS_PIN,
|
|
||||||
machine.LCD_RESET,
|
|
||||||
)
|
|
||||||
|
|
||||||
backlight = machine.LCD_BACKLIGHT
|
|
||||||
|
|
||||||
terminal = tinyterm.NewTerminal(display)
|
|
||||||
|
|
||||||
black = color.RGBA{0, 0, 0, 255}
|
|
||||||
white = color.RGBA{255, 255, 255, 255}
|
|
||||||
red = color.RGBA{255, 0, 0, 255}
|
|
||||||
blue = color.RGBA{0, 0, 255, 255}
|
|
||||||
green = color.RGBA{0, 255, 0, 255}
|
|
||||||
|
|
||||||
font = &proggy.TinySZ8pt7b
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
display.FillScreen(black)
|
|
||||||
backlight.High()
|
|
||||||
|
|
||||||
terminal.Configure(&tinyterm.Config{
|
|
||||||
Font: font,
|
|
||||||
FontHeight: 10,
|
|
||||||
FontOffset: 6,
|
|
||||||
})
|
|
||||||
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Fprintf(terminal, "error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
fmt.Fprintf(terminal, "setupRTL8720DN()\r\n")
|
|
||||||
if debug {
|
|
||||||
fmt.Fprintf(terminal, "Running in debug mode.\r\n")
|
|
||||||
fmt.Fprintf(terminal, "A serial connection is required to continue execution.\r\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
http.UseDriver(adaptor)
|
|
||||||
http.SetBuf(buf[:])
|
|
||||||
|
|
||||||
fmt.Fprintf(terminal, "ConnectToAP()\r\n")
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(terminal, "connected\r\n\r\n")
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(terminal, "IP Address : %s\r\n", ip)
|
|
||||||
fmt.Fprintf(terminal, "Mask : %s\r\n", subnet)
|
|
||||||
fmt.Fprintf(terminal, "Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
// You can send and receive cookies in the following way
|
|
||||||
// import "tinygo.org/x/drivers/net/http/cookiejar"
|
|
||||||
// jar, err := cookiejar.New(nil)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// client := &http.Client{Jar: jar}
|
|
||||||
// http.DefaultClient = client
|
|
||||||
|
|
||||||
cnt := 0
|
|
||||||
for {
|
|
||||||
// Various examples are as follows
|
|
||||||
//
|
|
||||||
// -- Get
|
|
||||||
// resp, err := http.Get(url)
|
|
||||||
//
|
|
||||||
// -- Post
|
|
||||||
// body := `cnt=12`
|
|
||||||
// resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(body))
|
|
||||||
//
|
|
||||||
// -- Post with JSON
|
|
||||||
// body := `{"msg": "hello"}`
|
|
||||||
// resp, err := http.Post(url, "application/json", strings.NewReader(body))
|
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(terminal, "%s %s\r\n", resp.Proto, resp.Status)
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
fmt.Fprintf(terminal, "%s: %s\r\n", k, strings.Join(v, " "))
|
|
||||||
}
|
|
||||||
fmt.Printf("\r\n")
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(resp.Body)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fmt.Fprintf(terminal, "%s\r\n", scanner.Text())
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
cnt++
|
|
||||||
fmt.Fprintf(terminal, "-------- %d --------\r\n", cnt)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
machine.SPI3.Configure(machine.SPIConfig{
|
|
||||||
SCK: machine.LCD_SCK_PIN,
|
|
||||||
SDO: machine.LCD_SDO_PIN,
|
|
||||||
SDI: machine.LCD_SDI_PIN,
|
|
||||||
Frequency: 40000000,
|
|
||||||
})
|
|
||||||
display.Configure(ili9341.Config{})
|
|
||||||
|
|
||||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// url = "http://tinygo.org/"
|
|
||||||
// debug = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
url = "http://tinygo.org/"
|
|
||||||
debug = false
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
|
||||||
adaptor.Debug(debug)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
http.UseDriver(adaptor)
|
|
||||||
http.SetBuf(buf[:])
|
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("IP Address : %s\r\n", ip)
|
|
||||||
fmt.Printf("Mask : %s\r\n", subnet)
|
|
||||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
|
||||||
|
|
||||||
// You can send and receive cookies in the following way
|
|
||||||
// import "tinygo.org/x/drivers/net/http/cookiejar"
|
|
||||||
// jar, err := cookiejar.New(nil)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// client := &http.Client{Jar: jar}
|
|
||||||
// http.DefaultClient = client
|
|
||||||
|
|
||||||
cnt := 0
|
|
||||||
for {
|
|
||||||
// Various examples are as follows
|
|
||||||
//
|
|
||||||
// -- Get
|
|
||||||
// resp, err := http.Get(url)
|
|
||||||
//
|
|
||||||
// -- Post
|
|
||||||
// body := `cnt=12`
|
|
||||||
// resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(body))
|
|
||||||
//
|
|
||||||
// -- Post with JSON
|
|
||||||
// body := `{"msg": "hello"}`
|
|
||||||
// resp, err := http.Post(url, "application/json", strings.NewReader(body))
|
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s %s\r\n", resp.Proto, resp.Status)
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
fmt.Printf("%s: %s\r\n", k, strings.Join(v, " "))
|
|
||||||
}
|
|
||||||
fmt.Printf("\r\n")
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(resp.Body)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fmt.Printf("%s\r\n", scanner.Text())
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
cnt++
|
|
||||||
fmt.Printf("-------- %d --------\r\n", cnt)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/seesaw"
|
||||||
|
)
|
||||||
|
|
||||||
|
const readDelay = time.Microsecond * 3000
|
||||||
|
|
||||||
|
// example reading soil moisture with an Adafruit capacitive soil-sensor (4026) powered by a seesaw
|
||||||
|
// https://learn.adafruit.com/adafruit-stemma-soil-sensor-i2c-capacitive-moisture-sensor/overview
|
||||||
|
func main() {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
|
||||||
|
dev := seesaw.New(machine.I2C0)
|
||||||
|
|
||||||
|
dev.Address = 0x36
|
||||||
|
|
||||||
|
// the soil sensor is especially slow, let's give it some more time
|
||||||
|
dev.ReadDelay = readDelay
|
||||||
|
|
||||||
|
var buf [2]byte
|
||||||
|
err := dev.Read(seesaw.ModuleTouchBase, seesaw.FunctionTouchChannelOffset, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
moisture := uint16(buf[0])<<8 | uint16(buf[1])
|
||||||
|
|
||||||
|
println("soil moisture: " + strconv.Itoa(int(moisture)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Example for the SGP30 to be used on a Raspberry Pi pico.
|
||||||
|
// Connect the sensor I2C pins to GP26 and GP27 to test.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/sgp30"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
println("start")
|
||||||
|
|
||||||
|
// Configure the I2C bus.
|
||||||
|
bus := machine.I2C1
|
||||||
|
err := bus.Configure(machine.I2CConfig{
|
||||||
|
SDA: machine.GP26,
|
||||||
|
SCL: machine.GP27,
|
||||||
|
Frequency: 400 * machine.KHz,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
println("could not configure I2C:", bus)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the sensor.
|
||||||
|
sensor := sgp30.New(bus)
|
||||||
|
if !sensor.Connected() {
|
||||||
|
println("sensor not connected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = sensor.Configure(sgp30.Config{})
|
||||||
|
if err != nil {
|
||||||
|
println("sensor could not be configured:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure every second, as recommended by the datasheet.
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
err := sensor.Update(0)
|
||||||
|
if err != nil {
|
||||||
|
println("could not read sensor:", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
println("CO₂ equivalent:", sensor.CO2())
|
||||||
|
println("TVOC ", sensor.TVOC())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/sht4x"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
|
sensor := sht4x.New(machine.I2C0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
temp, humidity, _ := sensor.ReadTemperatureHumidity()
|
||||||
|
t := fmt.Sprintf("%.2f", float32(temp)/1000)
|
||||||
|
h := fmt.Sprintf("%.2f", float32(humidity)/100)
|
||||||
|
println("Temperature: ", t, "°C")
|
||||||
|
println("Humidity: ", h, "%")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// 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,27 +0,0 @@
|
|||||||
//go:build espat
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"tinygo.org/x/drivers/espat"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
uart = machine.UART1
|
|
||||||
tx = machine.PA22
|
|
||||||
rx = machine.PA23
|
|
||||||
|
|
||||||
adaptor *espat.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func initAdaptor() *espat.Device {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
adaptor = espat.New(uart)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
return adaptor
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
//go:build rtl8720dn
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"device/sam"
|
|
||||||
"machine"
|
|
||||||
"runtime/interrupt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
adaptor *rtl8720dn.RTL8720DN
|
|
||||||
|
|
||||||
uart UARTx
|
|
||||||
)
|
|
||||||
|
|
||||||
func initAdaptor() *rtl8720dn.RTL8720DN {
|
|
||||||
adaptor, err := setupRTL8720DN()
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
net.UseDriver(adaptor)
|
|
||||||
|
|
||||||
return adaptor
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleInterrupt(interrupt.Interrupt) {
|
|
||||||
// should reset IRQ
|
|
||||||
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
|
||||||
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
|
||||||
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
machine.RTL8720D_CHIP_PU.Low()
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
machine.RTL8720D_CHIP_PU.High()
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
|
|
||||||
uart = UARTx{
|
|
||||||
UART: &machine.UART{
|
|
||||||
Buffer: machine.NewRingBuffer(),
|
|
||||||
Bus: sam.SERCOM0_USART_INT,
|
|
||||||
SERCOM: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
|
||||||
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
|
||||||
|
|
||||||
rtl := rtl8720dn.New(uart)
|
|
||||||
//rtl.Debug(debug)
|
|
||||||
|
|
||||||
_, err := rtl.Rpc_tcpip_adapter_init()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtl, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type UARTx struct {
|
|
||||||
*machine.UART
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u UARTx) Read(p []byte) (n int, err error) {
|
|
||||||
if u.Buffered() == 0 {
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
return u.UART.Read(p)
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
//go:build wifinina
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// default interface for the Arduino Nano33 IoT.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// ESP32/ESP8266 chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func initAdaptor() *wifinina.Device {
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
return adaptor
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
// This example connects to Access Point and prints some info
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
|
|
||||||
waitSerial()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
|
|
||||||
for {
|
|
||||||
println("----------------------------------------")
|
|
||||||
printSSID()
|
|
||||||
printRSSI()
|
|
||||||
printMac()
|
|
||||||
printIPs()
|
|
||||||
printTime()
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func printSSID() {
|
|
||||||
print("SSID: ")
|
|
||||||
ssid, err := adaptor.GetCurrentSSID()
|
|
||||||
if err != nil {
|
|
||||||
println("Unknown (error: ", err.Error(), ")")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println(ssid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printRSSI() {
|
|
||||||
print("RSSI: ")
|
|
||||||
rssi, err := adaptor.GetCurrentRSSI()
|
|
||||||
if err != nil {
|
|
||||||
println("Unknown (error: ", err.Error(), ")")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println(strconv.Itoa(int(rssi)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func printIPs() {
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
println("IP: Unknown (error: ", err.Error(), ")")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println("IP: ", ip.String())
|
|
||||||
println("Subnet: ", subnet.String())
|
|
||||||
println("Gateway: ", gateway.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func printTime() {
|
|
||||||
print("Time: ")
|
|
||||||
t, err := adaptor.GetTime()
|
|
||||||
for {
|
|
||||||
if err != nil {
|
|
||||||
println("Unknown (error: ", err.Error(), ")")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if t != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
t, err = adaptor.GetTime()
|
|
||||||
}
|
|
||||||
println(time.Unix(int64(t), 0).String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func printMac() {
|
|
||||||
print("MAC: ")
|
|
||||||
mac, err := adaptor.GetMACAddress()
|
|
||||||
if err != nil {
|
|
||||||
println("Unknown (", err.Error(), ")")
|
|
||||||
}
|
|
||||||
println(mac.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to open serial console
|
|
||||||
func waitSerial() {
|
|
||||||
for !machine.Serial.DTR() {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
// 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/
|
|
||||||
//
|
|
||||||
// This example will not work with samd21 or other systems with less than 32KB
|
|
||||||
// of RAM. Use the following if you want to run wifinina on samd21, etc.
|
|
||||||
//
|
|
||||||
// examples/wifinina/webclient
|
|
||||||
// examples/wifinina/tlsclient
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
// Can specify a URL starting with http or https
|
|
||||||
const url = "http://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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [0x400]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
http.SetBuf(buf[:])
|
|
||||||
|
|
||||||
waitSerial()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
// You can send and receive cookies in the following way
|
|
||||||
// import "tinygo.org/x/drivers/net/http/cookiejar"
|
|
||||||
// jar, err := cookiejar.New(nil)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// client := &http.Client{Jar: jar}
|
|
||||||
// http.DefaultClient = client
|
|
||||||
|
|
||||||
cnt := 0
|
|
||||||
for {
|
|
||||||
// Various examples are as follows
|
|
||||||
//
|
|
||||||
// -- Get
|
|
||||||
// resp, err := http.Get(url)
|
|
||||||
//
|
|
||||||
// -- Post
|
|
||||||
// body := `cnt=12`
|
|
||||||
// resp, err = http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(body))
|
|
||||||
//
|
|
||||||
// -- Post with JSON
|
|
||||||
// body := `{"msg": "hello"}`
|
|
||||||
// resp, err := http.Post(url, "application/json", strings.NewReader(body))
|
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%s\r\n", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s %s\r\n", resp.Proto, resp.Status)
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
fmt.Printf("%s: %s\r\n", k, strings.Join(v, " "))
|
|
||||||
}
|
|
||||||
fmt.Printf("\r\n")
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(resp.Body)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fmt.Printf("%s\r\n", scanner.Text())
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
cnt++
|
|
||||||
fmt.Printf("-------- %d --------\r\n", cnt)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to open serial console
|
|
||||||
func waitSerial() {
|
|
||||||
for !machine.Serial.DTR() {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
topic = "tinygo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
time.Sleep(3000 * time.Millisecond)
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
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(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting MQTT...")
|
|
||||||
cl.Disconnect(100)
|
|
||||||
|
|
||||||
println("Done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
println(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
println("IP address: " + 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
println(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
println("IP address: " + 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
// This is an example of using the wifinina driver to implement a NTP client.
|
|
||||||
// It creates a UDP connection to request the current time and parse the
|
|
||||||
// response from a NTP server.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
const ntpHost = "129.6.15.29"
|
|
||||||
|
|
||||||
const NTP_PACKET_SIZE = 48
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
b = make([]byte, NTP_PACKET_SIZE)
|
|
||||||
)
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
|
|
||||||
waitSerial()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
ip := net.ParseIP(ntpHost)
|
|
||||||
raddr := &net.UDPAddr{IP: ip, Port: 123}
|
|
||||||
laddr := &net.UDPAddr{Port: 2390}
|
|
||||||
conn, err := net.DialUDP("udp", laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Requesting NTP time...")
|
|
||||||
t, err := getCurrentTime(conn)
|
|
||||||
if err != nil {
|
|
||||||
message("Error getting current time: %v", err)
|
|
||||||
} else {
|
|
||||||
message("NTP time: %v", t)
|
|
||||||
}
|
|
||||||
runtime.AdjustTimeOffset(-1 * int64(time.Since(t)))
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
message("Current time: %v", time.Now())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to open serial console
|
|
||||||
func waitSerial() {
|
|
||||||
for !machine.Serial.DTR() {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
|
|
||||||
if err := sendNTPpacket(conn); err != nil {
|
|
||||||
return time.Time{}, err
|
|
||||||
}
|
|
||||||
clearBuffer()
|
|
||||||
for now := time.Now(); time.Since(now) < time.Second; {
|
|
||||||
time.Sleep(5 * time.Millisecond)
|
|
||||||
if n, err := conn.Read(b); err != nil {
|
|
||||||
return time.Time{}, fmt.Errorf("error reading UDP packet: %w", err)
|
|
||||||
} else if n == 0 {
|
|
||||||
continue // no packet received yet
|
|
||||||
} else if n != NTP_PACKET_SIZE {
|
|
||||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
|
||||||
}
|
|
||||||
return parseNTPpacket(), nil
|
|
||||||
}
|
|
||||||
return time.Time{}, errors.New("no packet received after 1 second")
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendNTPpacket(conn *net.UDPSerialConn) error {
|
|
||||||
clearBuffer()
|
|
||||||
b[0] = 0b11100011 // LI, Version, Mode
|
|
||||||
b[1] = 0 // Stratum, or type of clock
|
|
||||||
b[2] = 6 // Polling Interval
|
|
||||||
b[3] = 0xEC // Peer Clock Precision
|
|
||||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
|
||||||
b[12] = 49
|
|
||||||
b[13] = 0x4E
|
|
||||||
b[14] = 49
|
|
||||||
b[15] = 52
|
|
||||||
if _, err := conn.Write(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseNTPpacket() time.Time {
|
|
||||||
// the timestamp starts at byte 40 of the received packet and is four bytes,
|
|
||||||
// this is NTP time (seconds since Jan 1 1900):
|
|
||||||
t := uint32(b[40])<<24 | uint32(b[41])<<16 | uint32(b[42])<<8 | uint32(b[43])
|
|
||||||
const seventyYears = 2208988800
|
|
||||||
return time.Unix(int64(t-seventyYears), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func clearBuffer() {
|
|
||||||
for i := range b {
|
|
||||||
b[i] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(format string, args ...interface{}) {
|
|
||||||
println(fmt.Sprintf(format, args...), "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
//go:build nano_rp2040
|
|
||||||
|
|
||||||
// This examples shows how to control RGB LED connected to
|
|
||||||
// NINA-W102 chip on Arduino Nano RP2040 Connect board
|
|
||||||
// Built-in LED code added for API comparison
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LED = machine.LED
|
|
||||||
|
|
||||||
// Arduino Nano RP2040 Connect board RGB LED pins
|
|
||||||
// See https://docs.arduino.cc/static/3525d638b5c76a2d19588d6b41cd02a0/ABX00053-full-pinout.pdf
|
|
||||||
LED_R wifinina.Pin = 27
|
|
||||||
LED_G wifinina.Pin = 25
|
|
||||||
LED_B wifinina.Pin = 26
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
|
|
||||||
// these are the default pins for the Arduino Nano-RP2040 Connect
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
device *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
device = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
device.Configure()
|
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
|
|
||||||
LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
LED_R.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
|
||||||
LED_G.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
|
||||||
LED_B.Configure(wifinina.PinConfig{Mode: wifinina.PinOutput})
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
|
|
||||||
LED.Low() // OFF
|
|
||||||
LED_R.High() // OFF
|
|
||||||
LED_G.High() // OFF
|
|
||||||
LED_B.High() // OFF
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
LED.Low()
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
LED.High()
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
|
||||||
LED_R.Low() // ON
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
LED_R.High() // OFF
|
|
||||||
LED_G.Low() // ON
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
LED_G.High() // OFF
|
|
||||||
LED_B.Low() // ON
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
LED_B.High() // OFF
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf = &bytes.Buffer{}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
// This example opens a TCP connection using a device with WiFiNINA firmware
|
|
||||||
// and sends a HTTPS request to retrieve a webpage
|
|
||||||
//
|
|
||||||
// You shall see "strict-transport-security" header in the response,
|
|
||||||
// this confirms communication is indeed over HTTPS
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/tls"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [256]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
|
|
||||||
waitSerial()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
for {
|
|
||||||
readConnection()
|
|
||||||
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
|
|
||||||
makeHTTPSRequest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to open serial console
|
|
||||||
func waitSerial() {
|
|
||||||
for !machine.Serial.DTR() {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readConnection() {
|
|
||||||
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]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeHTTPSRequest() {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if conn != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
message("\r\n---------------\r\nDialing TCP connection")
|
|
||||||
conn, err = tls.Dial("tcp", server, nil)
|
|
||||||
for ; err != nil; conn, err = tls.Dial("tcp", server, nil) {
|
|
||||||
message("Connection failed: " + err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
println("Connected!\r")
|
|
||||||
|
|
||||||
print("Sending HTTPS request...")
|
|
||||||
fmt.Fprintln(conn, "GET / HTTP/1.1")
|
|
||||||
fmt.Fprintln(conn, "Host:", strings.Split(server, ":")[0])
|
|
||||||
fmt.Fprintln(conn, "User-Agent: TinyGo")
|
|
||||||
fmt.Fprintln(conn, "Connection: close")
|
|
||||||
fmt.Fprintln(conn)
|
|
||||||
println("Sent!\r\n\r")
|
|
||||||
|
|
||||||
lastRequestTime = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
// This is a sensor station that uses a ESP32 running nina-fw over SPI.
|
|
||||||
// It creates a UDP connection you can use to get info to/from your computer via the microcontroller.
|
|
||||||
//
|
|
||||||
// In other words:
|
|
||||||
// Your computer <--> UART0 <--> MCU <--> SPI <--> ESP32
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
|
||||||
const hubIP = ""
|
|
||||||
|
|
||||||
var (
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
// Init esp8266/esp32
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
machine.NINA_SPI.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
// these are the default pins for the Arduino Nano33 IoT.
|
|
||||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
|
||||||
adaptor = wifinina.New(machine.NINA_SPI,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
// now make UDP connection
|
|
||||||
ip := net.ParseIP(hubIP)
|
|
||||||
raddr := &net.UDPAddr{IP: ip, Port: 2222}
|
|
||||||
laddr := &net.UDPAddr{Port: 2222}
|
|
||||||
|
|
||||||
println("Dialing UDP connection...")
|
|
||||||
conn, err := net.DialUDP("udp", laddr, raddr)
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
// send data
|
|
||||||
println("Sending data...")
|
|
||||||
for i := 0; i < 25; i++ {
|
|
||||||
conn.Write([]byte("hello " + strconv.Itoa(i) + "\r\n"))
|
|
||||||
}
|
|
||||||
time.Sleep(1000 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now this code is never reached. Need a way to trigger it...
|
|
||||||
println("Disconnecting UDP...")
|
|
||||||
conn.Close()
|
|
||||||
println("Done.")
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// access point info
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the "example.com" server. Replace with your own info.
|
|
||||||
const server = "93.184.216.34"
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
spi = machine.NINA_SPI
|
|
||||||
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var buf [256]byte
|
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
|
||||||
var conn net.Conn
|
|
||||||
|
|
||||||
func setup() {
|
|
||||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
setup()
|
|
||||||
|
|
||||||
waitSerial()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
for {
|
|
||||||
readConnection()
|
|
||||||
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
|
|
||||||
makeHTTPRequest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to open serial console
|
|
||||||
func waitSerial() {
|
|
||||||
for !machine.Serial.DTR() {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readConnection() {
|
|
||||||
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]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
fmt.Fprintln(conn, "Connection: close")
|
|
||||||
fmt.Fprintln(conn)
|
|
||||||
println("Sent!\r\n\r")
|
|
||||||
|
|
||||||
lastRequestTime = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
"tinygo.org/x/drivers/wifinina"
|
|
||||||
)
|
|
||||||
|
|
||||||
// You can override the settings with the init() in another source code:
|
|
||||||
//
|
|
||||||
// func init() {
|
|
||||||
// ssid = "your-ssid"
|
|
||||||
// pass = "your-password"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Or use -ldflags option on tinygo command to set at compile-time:
|
|
||||||
//
|
|
||||||
// tinygo flash ... -ldflags '-X "main.ssid=xxx" -X "main.pass=xxx"' ...
|
|
||||||
//
|
|
||||||
|
|
||||||
var (
|
|
||||||
ssid string
|
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// this is the ESP chip that has the WIFININA firmware flashed on it
|
|
||||||
adaptor *wifinina.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var led = machine.LED
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
|
|
||||||
err := run()
|
|
||||||
for err != nil {
|
|
||||||
fmt.Printf("error: %s\r\n", err.Error())
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() error {
|
|
||||||
|
|
||||||
spi := machine.NINA_SPI
|
|
||||||
spi.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 8 * 1e6,
|
|
||||||
SDO: machine.NINA_SDO,
|
|
||||||
SDI: machine.NINA_SDI,
|
|
||||||
SCK: machine.NINA_SCK,
|
|
||||||
})
|
|
||||||
|
|
||||||
adaptor = wifinina.New(spi,
|
|
||||||
machine.NINA_CS,
|
|
||||||
machine.NINA_ACK,
|
|
||||||
machine.NINA_GPIO0,
|
|
||||||
machine.NINA_RESETN)
|
|
||||||
adaptor.Configure()
|
|
||||||
|
|
||||||
connectToAP()
|
|
||||||
displayIP()
|
|
||||||
|
|
||||||
http.UseDriver(adaptor)
|
|
||||||
|
|
||||||
http.HandleFunc("/", root)
|
|
||||||
http.HandleFunc("/hello", hello)
|
|
||||||
http.HandleFunc("/cnt", cnt)
|
|
||||||
http.HandleFunc("/6", sixlines)
|
|
||||||
http.HandleFunc("/off", LED_OFF)
|
|
||||||
http.HandleFunc("/on", LED_ON)
|
|
||||||
|
|
||||||
return http.ListenAndServe(":80", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func root(w http.ResponseWriter, r *http.Request) {
|
|
||||||
access := 1
|
|
||||||
|
|
||||||
cookie, err := r.Cookie("access")
|
|
||||||
if err != nil {
|
|
||||||
if err == http.ErrNoCookie {
|
|
||||||
cookie = &http.Cookie{
|
|
||||||
Name: "access",
|
|
||||||
Value: "1",
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
http.Error(w, fmt.Sprintf("%s", err.Error()), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v, err := strconv.ParseInt(cookie.Value, 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("invalid cookie.Value : %s", cookie.Value), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cookie.Value = fmt.Sprintf("%d", v+1)
|
|
||||||
access = int(v) + 1
|
|
||||||
}
|
|
||||||
http.SetCookie(w, cookie)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
|
|
||||||
fmt.Fprintf(w, `
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>TinyGo HTTP Server</title>
|
|
||||||
<script language="javascript" type="text/javascript">
|
|
||||||
var counter = 0
|
|
||||||
function ledOn() { fetch("/on"); }
|
|
||||||
function ledOff() { fetch("/off"); }
|
|
||||||
function fetchCnt() { fetch("/cnt").then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
|
||||||
function incrCnt() { counter = counter + 1; fetch("/cnt?cnt=" + counter, { method: 'POST' }).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
|
||||||
function setCnt() { fetch("/cnt", {
|
|
||||||
method: "POST",
|
|
||||||
body: "cnt=" + document.getElementsByName("cnt")[0].value,
|
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
}).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); return false; }
|
|
||||||
function onLoad() { fetchCnt(); }
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onLoad="onLoad()">
|
|
||||||
<h5>TinyGo HTTP Server</h5>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
access: %d
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<a href="/hello">/hello</a><br>
|
|
||||||
<a href="/6">/6</a><br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
LED<br>
|
|
||||||
<a href="javascript:ledOn();">/on</a><br>
|
|
||||||
<a href="javascript:ledOff();">/off</a><br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="/cnt">/cnt</a><br>
|
|
||||||
cnt: <span id="cnt"></span><br>
|
|
||||||
<a href="javascript:incrCnt()">incrCnt()</a><br>
|
|
||||||
<form id="form1" style="display: inline" onSubmit="return setCnt()">
|
|
||||||
<input type="text" name="cnt">
|
|
||||||
<input type="button" value="set cnt", onClick="setCnt()">
|
|
||||||
</form>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`, access)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sixlines(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// https://fukuno.jig.jp/3267
|
|
||||||
fmt.Fprint(w, `<body onload='onkeydown=e=>K=parseInt(e.key[5]||6,28)/3-8;Z=X=[B=A=12];Y=_=>`+
|
|
||||||
`{for(C=[q=c=i=4];f=i--*K;c-=!Z[h+(K+6?p+K:C[i]=p*A-(p/9|0)*145)])p=B[i];for(c?0:K+6?h+=K:B=C;`+
|
|
||||||
`i=K=q--;f+=Z[A+p])X[p=h+B[q]]=1;h+=A;if(f|B)for(Z=X,X=[l=228],B=[[-7,-20,6,h=17,-9,3,3][t=++t%7]-4,0,1,t-6?-A:2];l--;)`+
|
|
||||||
`for(l%A?l-=l%A*!Z[l]:(P++,c=l+=A);--c>A;)Z[c]=Z[c-A];for(S="";i<240;S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?i%A?"■":"■<br>":" ");`+
|
|
||||||
`D.innerHTML=S+P;setTimeout(Y,i-P)};Y(h=K=t=P=0)'id=D>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LED_ON(w http.ResponseWriter, r *http.Request) {
|
|
||||||
led.High()
|
|
||||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
|
||||||
fmt.Fprintf(w, "led.High()")
|
|
||||||
}
|
|
||||||
|
|
||||||
func LED_OFF(w http.ResponseWriter, r *http.Request) {
|
|
||||||
led.Low()
|
|
||||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
|
||||||
fmt.Fprintf(w, "led.Low()")
|
|
||||||
}
|
|
||||||
|
|
||||||
func hello(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
|
||||||
fmt.Fprintf(w, "hello")
|
|
||||||
}
|
|
||||||
|
|
||||||
var counter int
|
|
||||||
|
|
||||||
func cnt(w http.ResponseWriter, r *http.Request) {
|
|
||||||
r.ParseForm()
|
|
||||||
if r.Method == "POST" {
|
|
||||||
c := r.Form.Get("cnt")
|
|
||||||
if c != "" {
|
|
||||||
i64, _ := strconv.ParseInt(c, 0, 0)
|
|
||||||
counter = int(i64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set(`Content-Type`, `application/json`)
|
|
||||||
fmt.Fprintf(w, `{"cnt": %d}`, counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
const retriesBeforeFailure = 3
|
|
||||||
|
|
||||||
// connect to access point
|
|
||||||
func connectToAP() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
var err error
|
|
||||||
for i := 0; i < retriesBeforeFailure; i++ {
|
|
||||||
println("Connecting to " + ssid)
|
|
||||||
err = adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected.")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error connecting to AP
|
|
||||||
failMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func displayIP() {
|
|
||||||
ip, _, _, err := adaptor.GetIP()
|
|
||||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
|
||||||
message(err.Error())
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
message("IP address: " + ip.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func message(msg string) {
|
|
||||||
println(msg, "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(msg string) {
|
|
||||||
for {
|
|
||||||
println(msg)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ func main() {
|
|||||||
|
|
||||||
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
ws := ws2812.New(neo)
|
ws := ws2812.NewWS2812(neo)
|
||||||
rg := false
|
rg := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
module tinygo.org/x/drivers
|
module tinygo.org/x/drivers
|
||||||
|
|
||||||
go 1.15
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||||
github.com/frankban/quicktest v1.10.2
|
github.com/frankban/quicktest v1.10.2
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
|
github.com/soypat/natiu-mqtt v0.5.1
|
||||||
golang.org/x/net v0.7.0
|
golang.org/x/net v0.7.0
|
||||||
tinygo.org/x/tinyfont v0.3.0
|
tinygo.org/x/tinyfont v0.3.0
|
||||||
tinygo.org/x/tinyterm v0.1.0
|
tinygo.org/x/tinyterm v0.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/go-cmp v0.5.2 // indirect
|
||||||
|
github.com/kr/pretty v0.2.1 // indirect
|
||||||
|
github.com/kr/text v0.1.0 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||||
|
)
|
||||||
|
|||||||
@@ -7,56 +7,22 @@ github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
|||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/hajimehoshi/go-jisx0208 v1.0.0/go.mod h1:yYxEStHL7lt9uL+AbdWgW9gBumwieDoZCiB1f/0X0as=
|
|
||||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/sago35/go-bdf v0.0.0-20200313142241-6c17821c91c4/go.mod h1:rOebXGuMLsXhZAC6mF/TjxONsm45498ZyzVhel++6KM=
|
github.com/soypat/natiu-mqtt v0.5.1 h1:rwaDmlvjzD2+3MCOjMZc4QEkDkNwDzbct2TJbpz+TPc=
|
||||||
|
github.com/soypat/natiu-mqtt v0.5.1/go.mod h1:xEta+cwop9izVCW7xOx2W+ct9PRMqr0gNVkvBPnQTc4=
|
||||||
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
||||||
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
||||||
tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
|
||||||
tinygo.org/x/drivers v0.19.0/go.mod h1:uJD/l1qWzxzLx+vcxaW0eY464N5RAgFi1zTVzASFdqI=
|
|
||||||
tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM=
|
tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM=
|
||||||
tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM=
|
tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM=
|
||||||
tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk=
|
tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk=
|
||||||
tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20=
|
|
||||||
tinygo.org/x/tinyterm v0.1.0 h1:80i+j+KWoxCFa/Xfp6pWbh79x+8zUdMXC1vaKj2QhkY=
|
tinygo.org/x/tinyterm v0.1.0 h1:80i+j+KWoxCFa/Xfp6pWbh79x+8zUdMXC1vaKj2QhkY=
|
||||||
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
|
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
|
"tinygo.org/x/drivers/pixel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -31,6 +32,9 @@ type Device struct {
|
|||||||
rd machine.Pin
|
rd machine.Pin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Image buffer type used in the ili9341.
|
||||||
|
type Image = pixel.Image[pixel.RGB565BE]
|
||||||
|
|
||||||
var cmdBuf [6]byte
|
var cmdBuf [6]byte
|
||||||
|
|
||||||
var initCmd = []byte{
|
var initCmd = []byte{
|
||||||
@@ -173,6 +177,8 @@ func (d *Device) EnableTEOutput(on bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DrawRGBBitmap copies an RGB bitmap to the internal buffer at given coordinates
|
// DrawRGBBitmap copies an RGB bitmap to the internal buffer at given coordinates
|
||||||
|
//
|
||||||
|
// Deprecated: use DrawBitmap instead.
|
||||||
func (d *Device) DrawRGBBitmap(x, y int16, data []uint16, w, h int16) error {
|
func (d *Device) DrawRGBBitmap(x, y int16, data []uint16, w, h int16) error {
|
||||||
k, i := d.Size()
|
k, i := d.Size()
|
||||||
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
||||||
@@ -187,6 +193,8 @@ func (d *Device) DrawRGBBitmap(x, y int16, data []uint16, w, h int16) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DrawRGBBitmap8 copies an RGB bitmap to the internal buffer at given coordinates
|
// DrawRGBBitmap8 copies an RGB bitmap to the internal buffer at given coordinates
|
||||||
|
//
|
||||||
|
// Deprecated: use DrawBitmap instead.
|
||||||
func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
|
func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
|
||||||
k, i := d.Size()
|
k, i := d.Size()
|
||||||
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
|
||||||
@@ -200,6 +208,13 @@ func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrawBitmap copies the bitmap to the internal buffer on the screen at the
|
||||||
|
// given coordinates. It returns once the image data has been sent completely.
|
||||||
|
func (d *Device) DrawBitmap(x, y int16, bitmap Image) error {
|
||||||
|
width, height := bitmap.Size()
|
||||||
|
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
||||||
|
}
|
||||||
|
|
||||||
// FillRectangle fills a rectangle at given coordinates with a color
|
// FillRectangle fills a rectangle at given coordinates with a color
|
||||||
func (d *Device) FillRectangle(x, y, width, height int16, c color.RGBA) error {
|
func (d *Device) FillRectangle(x, y, width, height int16, c color.RGBA) error {
|
||||||
k, i := d.Size()
|
k, i := d.Size()
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ const (
|
|||||||
MHz_868_1 = 868100000
|
MHz_868_1 = 868100000
|
||||||
MHz_868_5 = 868500000
|
MHz_868_5 = 868500000
|
||||||
MHz_902_3 = 902300000
|
MHz_902_3 = 902300000
|
||||||
|
Mhz_903_0 = 903000000
|
||||||
|
MHZ_915_0 = 915000000
|
||||||
MHz_916_8 = 916800000
|
MHz_916_8 = 916800000
|
||||||
MHz_923_3 = 923300000
|
MHz_923_3 = 923300000
|
||||||
)
|
)
|
||||||
|
|||||||
+31
-25
@@ -30,11 +30,11 @@ const (
|
|||||||
var (
|
var (
|
||||||
ActiveRadio lora.Radio
|
ActiveRadio lora.Radio
|
||||||
Retries = 15
|
Retries = 15
|
||||||
regionSettings region.RegionSettings
|
regionSettings region.Settings
|
||||||
)
|
)
|
||||||
|
|
||||||
// UseRegionSettings sets current Lorawan Regional parameters
|
// UseRegionSettings sets current Lorawan Regional parameters
|
||||||
func UseRegionSettings(rs region.RegionSettings) {
|
func UseRegionSettings(rs region.Settings) {
|
||||||
regionSettings = rs
|
regionSettings = rs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,13 +52,13 @@ func SetPublicNetwork(enabled bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ApplyChannelConfig sets current Lora modulation according to current regional settings
|
// ApplyChannelConfig sets current Lora modulation according to current regional settings
|
||||||
func applyChannelConfig(ch *region.Channel) {
|
func applyChannelConfig(ch region.Channel) {
|
||||||
ActiveRadio.SetFrequency(ch.Frequency)
|
ActiveRadio.SetFrequency(ch.Frequency())
|
||||||
ActiveRadio.SetBandwidth(ch.Bandwidth)
|
ActiveRadio.SetBandwidth(ch.Bandwidth())
|
||||||
ActiveRadio.SetCodingRate(ch.CodingRate)
|
ActiveRadio.SetCodingRate(ch.CodingRate())
|
||||||
ActiveRadio.SetSpreadingFactor(ch.SpreadingFactor)
|
ActiveRadio.SetSpreadingFactor(ch.SpreadingFactor())
|
||||||
ActiveRadio.SetPreambleLength(ch.PreambleLength)
|
ActiveRadio.SetPreambleLength(ch.PreambleLength())
|
||||||
ActiveRadio.SetTxPower(ch.TxPowerDBm)
|
ActiveRadio.SetTxPower(ch.TxPowerDBm())
|
||||||
// Lorawan defaults to explicit headers
|
// Lorawan defaults to explicit headers
|
||||||
ActiveRadio.SetHeaderType(lora.HeaderExplicit)
|
ActiveRadio.SetHeaderType(lora.HeaderExplicit)
|
||||||
ActiveRadio.SetCrc(true)
|
ActiveRadio.SetCrc(true)
|
||||||
@@ -84,24 +84,30 @@ func Join(otaa *Otaa, session *Session) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare radio for Join Tx
|
for {
|
||||||
applyChannelConfig(regionSettings.JoinRequestChannel())
|
joinRequestChannel := regionSettings.JoinRequestChannel()
|
||||||
ActiveRadio.SetIqMode(lora.IQStandard)
|
joinAcceptChannel := regionSettings.JoinAcceptChannel()
|
||||||
ActiveRadio.Tx(payload, LORA_TX_TIMEOUT)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for JoinAccept
|
// Prepare radio for Join Tx
|
||||||
applyChannelConfig(regionSettings.JoinAcceptChannel())
|
applyChannelConfig(joinRequestChannel)
|
||||||
ActiveRadio.SetIqMode(lora.IQInverted)
|
ActiveRadio.SetIqMode(lora.IQStandard)
|
||||||
resp, err = ActiveRadio.Rx(LORA_RX_TIMEOUT)
|
ActiveRadio.Tx(payload, LORA_TX_TIMEOUT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp == nil {
|
// Wait for JoinAccept
|
||||||
return ErrNoJoinAcceptReceived
|
if joinAcceptChannel.Frequency() != 0 {
|
||||||
|
applyChannelConfig(joinAcceptChannel)
|
||||||
|
}
|
||||||
|
ActiveRadio.SetIqMode(lora.IQInverted)
|
||||||
|
resp, err = ActiveRadio.Rx(LORA_RX_TIMEOUT)
|
||||||
|
if err == nil && resp != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !joinAcceptChannel.Next() {
|
||||||
|
return ErrNoJoinAcceptReceived
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = otaa.DecodeJoinAccept(resp, session)
|
err = otaa.DecodeJoinAccept(resp, session)
|
||||||
|
|||||||
@@ -7,43 +7,41 @@ const (
|
|||||||
AU915_DEFAULT_TX_POWER_DBM = 20
|
AU915_DEFAULT_TX_POWER_DBM = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
type RegionSettingsAU915 struct {
|
type ChannelAU struct {
|
||||||
joinRequestChannel *Channel
|
channel
|
||||||
joinAcceptChannel *Channel
|
|
||||||
uplinkChannel *Channel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AU915() *RegionSettingsAU915 {
|
func (c *ChannelAU) Next() bool {
|
||||||
return &RegionSettingsAU915{
|
return false
|
||||||
joinRequestChannel: &Channel{lora.MHz_916_8,
|
}
|
||||||
|
|
||||||
|
type SettingsAU915 struct {
|
||||||
|
settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func AU915() *SettingsAU915 {
|
||||||
|
return &SettingsAU915{settings: settings{
|
||||||
|
joinRequestChannel: &ChannelAU{channel: channel{lora.MHz_916_8,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
AU915_DEFAULT_PREAMBLE_LEN,
|
AU915_DEFAULT_PREAMBLE_LEN,
|
||||||
AU915_DEFAULT_TX_POWER_DBM},
|
AU915_DEFAULT_TX_POWER_DBM}},
|
||||||
joinAcceptChannel: &Channel{lora.MHz_923_3,
|
joinAcceptChannel: &ChannelAU{channel: channel{lora.MHz_923_3,
|
||||||
lora.Bandwidth_500_0,
|
lora.Bandwidth_500_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
AU915_DEFAULT_PREAMBLE_LEN,
|
AU915_DEFAULT_PREAMBLE_LEN,
|
||||||
AU915_DEFAULT_TX_POWER_DBM},
|
AU915_DEFAULT_TX_POWER_DBM}},
|
||||||
uplinkChannel: &Channel{lora.MHz_916_8,
|
uplinkChannel: &ChannelAU{channel: channel{lora.MHz_916_8,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
AU915_DEFAULT_PREAMBLE_LEN,
|
AU915_DEFAULT_PREAMBLE_LEN,
|
||||||
AU915_DEFAULT_TX_POWER_DBM},
|
AU915_DEFAULT_TX_POWER_DBM}},
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RegionSettingsAU915) JoinRequestChannel() *Channel {
|
func Next(c *ChannelAU) bool {
|
||||||
return r.joinRequestChannel
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsAU915) JoinAcceptChannel() *Channel {
|
|
||||||
return r.joinAcceptChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsAU915) UplinkChannel() *Channel {
|
|
||||||
return r.uplinkChannel
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package region
|
||||||
|
|
||||||
|
type Channel interface {
|
||||||
|
Next() bool
|
||||||
|
Frequency() uint32
|
||||||
|
Bandwidth() uint8
|
||||||
|
SpreadingFactor() uint8
|
||||||
|
CodingRate() uint8
|
||||||
|
PreambleLength() uint16
|
||||||
|
TxPowerDBm() int8
|
||||||
|
SetFrequency(v uint32)
|
||||||
|
SetBandwidth(v uint8)
|
||||||
|
SetSpreadingFactor(v uint8)
|
||||||
|
SetCodingRate(v uint8)
|
||||||
|
SetPreambleLength(v uint16)
|
||||||
|
SetTxPowerDBm(v int8)
|
||||||
|
}
|
||||||
|
|
||||||
|
type channel struct {
|
||||||
|
frequency uint32
|
||||||
|
bandwidth uint8
|
||||||
|
spreadingFactor uint8
|
||||||
|
codingRate uint8
|
||||||
|
preambleLength uint16
|
||||||
|
txPowerDBm int8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter functions
|
||||||
|
func (c *channel) Frequency() uint32 { return c.frequency }
|
||||||
|
func (c *channel) Bandwidth() uint8 { return c.bandwidth }
|
||||||
|
func (c *channel) SpreadingFactor() uint8 { return c.spreadingFactor }
|
||||||
|
func (c *channel) CodingRate() uint8 { return c.codingRate }
|
||||||
|
func (c *channel) PreambleLength() uint16 { return c.preambleLength }
|
||||||
|
func (c *channel) TxPowerDBm() int8 { return c.txPowerDBm }
|
||||||
|
|
||||||
|
// Set functions
|
||||||
|
func (c *channel) SetFrequency(v uint32) { c.frequency = v }
|
||||||
|
func (c *channel) SetBandwidth(v uint8) { c.bandwidth = v }
|
||||||
|
func (c *channel) SetSpreadingFactor(v uint8) { c.spreadingFactor = v }
|
||||||
|
func (c *channel) SetCodingRate(v uint8) { c.codingRate = v }
|
||||||
|
func (c *channel) SetPreambleLength(v uint16) { c.preambleLength = v }
|
||||||
|
func (c *channel) SetTxPowerDBm(v int8) { c.txPowerDBm = v }
|
||||||
@@ -7,43 +7,37 @@ const (
|
|||||||
EU868_DEFAULT_TX_POWER_DBM = 20
|
EU868_DEFAULT_TX_POWER_DBM = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
type RegionSettingsEU868 struct {
|
type ChannelEU struct {
|
||||||
joinRequestChannel *Channel
|
channel
|
||||||
joinAcceptChannel *Channel
|
|
||||||
uplinkChannel *Channel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func EU868() *RegionSettingsEU868 {
|
func (c *ChannelEU) Next() bool {
|
||||||
return &RegionSettingsEU868{
|
return false
|
||||||
joinRequestChannel: &Channel{lora.MHz_868_1,
|
}
|
||||||
|
|
||||||
|
type SettingsEU868 struct {
|
||||||
|
settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func EU868() *SettingsEU868 {
|
||||||
|
return &SettingsEU868{settings: settings{
|
||||||
|
joinRequestChannel: &ChannelEU{channel: channel{lora.MHz_868_1,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_7,
|
lora.CodingRate4_7,
|
||||||
EU868_DEFAULT_PREAMBLE_LEN,
|
EU868_DEFAULT_PREAMBLE_LEN,
|
||||||
EU868_DEFAULT_TX_POWER_DBM},
|
EU868_DEFAULT_TX_POWER_DBM}},
|
||||||
joinAcceptChannel: &Channel{lora.MHz_868_1,
|
joinAcceptChannel: &ChannelEU{channel: channel{lora.MHz_868_1,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_7,
|
lora.CodingRate4_7,
|
||||||
EU868_DEFAULT_PREAMBLE_LEN,
|
EU868_DEFAULT_PREAMBLE_LEN,
|
||||||
EU868_DEFAULT_TX_POWER_DBM},
|
EU868_DEFAULT_TX_POWER_DBM}},
|
||||||
uplinkChannel: &Channel{lora.MHz_868_1,
|
uplinkChannel: &ChannelEU{channel: channel{lora.MHz_868_1,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor9,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_7,
|
lora.CodingRate4_7,
|
||||||
EU868_DEFAULT_PREAMBLE_LEN,
|
EU868_DEFAULT_PREAMBLE_LEN,
|
||||||
EU868_DEFAULT_TX_POWER_DBM},
|
EU868_DEFAULT_TX_POWER_DBM}},
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsEU868) JoinRequestChannel() *Channel {
|
|
||||||
return r.joinRequestChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsEU868) JoinAcceptChannel() *Channel {
|
|
||||||
return r.joinAcceptChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsEU868) UplinkChannel() *Channel {
|
|
||||||
return r.uplinkChannel
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package region
|
|
||||||
|
|
||||||
type Channel struct {
|
|
||||||
Frequency uint32
|
|
||||||
Bandwidth uint8
|
|
||||||
SpreadingFactor uint8
|
|
||||||
CodingRate uint8
|
|
||||||
PreambleLength uint16
|
|
||||||
TxPowerDBm int8
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegionSettings interface {
|
|
||||||
JoinRequestChannel() *Channel
|
|
||||||
JoinAcceptChannel() *Channel
|
|
||||||
UplinkChannel() *Channel
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package region
|
||||||
|
|
||||||
|
type Settings interface {
|
||||||
|
JoinRequestChannel() Channel
|
||||||
|
JoinAcceptChannel() Channel
|
||||||
|
UplinkChannel() Channel
|
||||||
|
}
|
||||||
|
|
||||||
|
type settings struct {
|
||||||
|
joinRequestChannel Channel
|
||||||
|
joinAcceptChannel Channel
|
||||||
|
uplinkChannel Channel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *settings) JoinRequestChannel() Channel {
|
||||||
|
return r.joinRequestChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *settings) JoinAcceptChannel() Channel {
|
||||||
|
return r.joinAcceptChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *settings) UplinkChannel() Channel {
|
||||||
|
return r.uplinkChannel
|
||||||
|
}
|
||||||
@@ -3,49 +3,80 @@ package region
|
|||||||
import "tinygo.org/x/drivers/lora"
|
import "tinygo.org/x/drivers/lora"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
US915_DEFAULT_PREAMBLE_LEN = 8
|
US915_DEFAULT_PREAMBLE_LEN = 8
|
||||||
US915_DEFAULT_TX_POWER_DBM = 20
|
US915_DEFAULT_TX_POWER_DBM = 20
|
||||||
|
US915_FREQUENCY_INCREMENT_DR_0 = 200000 // only for 125 kHz Bandwidth
|
||||||
|
US915_FREQUENCY_INCREMENT_DR_4 = 1600000 // only for 500 kHz Bandwidth
|
||||||
)
|
)
|
||||||
|
|
||||||
type RegionSettingsUS915 struct {
|
type ChannelUS struct {
|
||||||
joinRequestChannel *Channel
|
channel
|
||||||
joinAcceptChannel *Channel
|
|
||||||
uplinkChannel *Channel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/#us902-928-ism-band
|
func (c *ChannelUS) Next() bool {
|
||||||
|
switch c.Bandwidth() {
|
||||||
|
case lora.Bandwidth_125_0:
|
||||||
|
freq, ok := stepFrequency125(c.frequency)
|
||||||
|
if ok {
|
||||||
|
c.frequency = freq
|
||||||
|
} else {
|
||||||
|
c.frequency = lora.Mhz_903_0
|
||||||
|
c.bandwidth = lora.Bandwidth_500_0
|
||||||
|
}
|
||||||
|
case lora.Bandwidth_500_0:
|
||||||
|
freq, ok := stepFrequency500(c.frequency)
|
||||||
|
if ok {
|
||||||
|
c.frequency = freq
|
||||||
|
} else {
|
||||||
|
// there are no more frequencies to check after sweeping all 8 500 kHz channels
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func US915() *RegionSettingsUS915 {
|
return true
|
||||||
return &RegionSettingsUS915{
|
}
|
||||||
joinRequestChannel: &Channel{lora.MHz_902_3,
|
|
||||||
|
func stepFrequency125(freq uint32) (uint32, bool) {
|
||||||
|
f := freq + US915_FREQUENCY_INCREMENT_DR_0
|
||||||
|
if f >= lora.MHZ_915_0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func stepFrequency500(freq uint32) (uint32, bool) {
|
||||||
|
f := freq + US915_FREQUENCY_INCREMENT_DR_4
|
||||||
|
if f >= lora.MHZ_915_0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, true
|
||||||
|
}
|
||||||
|
|
||||||
|
type SettingsUS915 struct {
|
||||||
|
settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func US915() *SettingsUS915 {
|
||||||
|
return &SettingsUS915{settings: settings{
|
||||||
|
joinRequestChannel: &ChannelUS{channel: channel{lora.MHz_902_3,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_125_0,
|
||||||
lora.SpreadingFactor10,
|
lora.SpreadingFactor10,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
US915_DEFAULT_PREAMBLE_LEN,
|
US915_DEFAULT_PREAMBLE_LEN,
|
||||||
US915_DEFAULT_TX_POWER_DBM},
|
US915_DEFAULT_TX_POWER_DBM}},
|
||||||
joinAcceptChannel: &Channel{lora.MHz_923_3,
|
joinAcceptChannel: &ChannelUS{channel: channel{0,
|
||||||
lora.Bandwidth_500_0,
|
lora.Bandwidth_500_0,
|
||||||
lora.SpreadingFactor7,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
US915_DEFAULT_PREAMBLE_LEN,
|
US915_DEFAULT_PREAMBLE_LEN,
|
||||||
US915_DEFAULT_TX_POWER_DBM},
|
US915_DEFAULT_TX_POWER_DBM}},
|
||||||
uplinkChannel: &Channel{lora.MHz_902_3,
|
uplinkChannel: &ChannelUS{channel: channel{lora.Mhz_903_0,
|
||||||
lora.Bandwidth_125_0,
|
lora.Bandwidth_500_0,
|
||||||
lora.SpreadingFactor7,
|
lora.SpreadingFactor9,
|
||||||
lora.CodingRate4_5,
|
lora.CodingRate4_5,
|
||||||
US915_DEFAULT_PREAMBLE_LEN,
|
US915_DEFAULT_PREAMBLE_LEN,
|
||||||
US915_DEFAULT_TX_POWER_DBM},
|
US915_DEFAULT_TX_POWER_DBM}},
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsUS915) JoinRequestChannel() *Channel {
|
|
||||||
return r.joinRequestChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsUS915) JoinAcceptChannel() *Channel {
|
|
||||||
return r.joinAcceptChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RegionSettingsUS915) UplinkChannel() *Channel {
|
|
||||||
return r.uplinkChannel
|
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-1
@@ -236,16 +236,83 @@ 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
|
||||||
@@ -255,6 +322,50 @@ 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,44 +0,0 @@
|
|||||||
package net
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrWiFiMissingSSID = errors.New("missing SSID")
|
|
||||||
ErrWiFiConnectTimeout = errors.New("WiFi connect timeout")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Adapter interface is used to communicate with the network adapter.
|
|
||||||
type Adapter interface {
|
|
||||||
// functions used to connect/disconnect to/from an access point
|
|
||||||
ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error
|
|
||||||
Disconnect() error
|
|
||||||
GetClientIP() (string, error)
|
|
||||||
|
|
||||||
// these functions are used once the adapter is connected to the network
|
|
||||||
GetDNS(domain string) (string, error)
|
|
||||||
ConnectTCPSocket(addr, port string) error
|
|
||||||
ConnectSSLSocket(addr, port string) error
|
|
||||||
ConnectUDPSocket(addr, sendport, listenport string) error
|
|
||||||
DisconnectSocket() error
|
|
||||||
StartSocketSend(size int) error
|
|
||||||
Write(b []byte) (n int, err error)
|
|
||||||
ReadSocket(b []byte) (n int, err error)
|
|
||||||
IsSocketDataAvailable() bool
|
|
||||||
|
|
||||||
// FIXME: this is really specific to espat, and maybe shouldn't be part
|
|
||||||
// of the driver interface
|
|
||||||
Response(timeout int) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ActiveDevice Adapter
|
|
||||||
|
|
||||||
func UseDriver(a Adapter) {
|
|
||||||
// TODO: rethink and refactor this
|
|
||||||
if ActiveDevice != nil {
|
|
||||||
panic("net.ActiveDevice is already set")
|
|
||||||
}
|
|
||||||
ActiveDevice = a
|
|
||||||
}
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Client is an HTTP client. Its zero value (DefaultClient) is a
|
|
||||||
// usable client that uses DefaultTransport.
|
|
||||||
//
|
|
||||||
// The Client's Transport typically has internal state (cached TCP
|
|
||||||
// connections), so Clients should be reused instead of created as
|
|
||||||
// needed. Clients are safe for concurrent use by multiple goroutines.
|
|
||||||
//
|
|
||||||
// A Client is higher-level than a RoundTripper (such as Transport)
|
|
||||||
// and additionally handles HTTP details such as cookies and
|
|
||||||
// redirects.
|
|
||||||
//
|
|
||||||
// When following redirects, the Client will forward all headers set on the
|
|
||||||
// initial Request except:
|
|
||||||
//
|
|
||||||
// • when forwarding sensitive headers like "Authorization",
|
|
||||||
// "WWW-Authenticate", and "Cookie" to untrusted targets.
|
|
||||||
// These headers will be ignored when following a redirect to a domain
|
|
||||||
// that is not a subdomain match or exact match of the initial domain.
|
|
||||||
// For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com"
|
|
||||||
// will forward the sensitive headers, but a redirect to "bar.com" will not.
|
|
||||||
//
|
|
||||||
// • when forwarding the "Cookie" header with a non-nil cookie Jar.
|
|
||||||
// Since each redirect may mutate the state of the cookie jar,
|
|
||||||
// a redirect may possibly alter a cookie set in the initial request.
|
|
||||||
// When forwarding the "Cookie" header, any mutated cookies will be omitted,
|
|
||||||
// with the expectation that the Jar will insert those mutated cookies
|
|
||||||
// with the updated values (assuming the origin matches).
|
|
||||||
// If Jar is nil, the initial cookies are forwarded without change.
|
|
||||||
type Client struct {
|
|
||||||
// Transport specifies the mechanism by which individual
|
|
||||||
// HTTP requests are made.
|
|
||||||
// If nil, DefaultTransport is used.
|
|
||||||
Transport RoundTripper
|
|
||||||
|
|
||||||
// CheckRedirect specifies the policy for handling redirects.
|
|
||||||
// If CheckRedirect is not nil, the client calls it before
|
|
||||||
// following an HTTP redirect. The arguments req and via are
|
|
||||||
// the upcoming request and the requests made already, oldest
|
|
||||||
// first. If CheckRedirect returns an error, the Client's Get
|
|
||||||
// method returns both the previous Response (with its Body
|
|
||||||
// closed) and CheckRedirect's error (wrapped in a url.Error)
|
|
||||||
// instead of issuing the Request req.
|
|
||||||
// As a special case, if CheckRedirect returns ErrUseLastResponse,
|
|
||||||
// then the most recent response is returned with its body
|
|
||||||
// unclosed, along with a nil error.
|
|
||||||
//
|
|
||||||
// If CheckRedirect is nil, the Client uses its default policy,
|
|
||||||
// which is to stop after 10 consecutive requests.
|
|
||||||
CheckRedirect func(req *Request, via []*Request) error
|
|
||||||
|
|
||||||
// Jar specifies the cookie jar.
|
|
||||||
//
|
|
||||||
// The Jar is used to insert relevant cookies into every
|
|
||||||
// outbound Request and is updated with the cookie values
|
|
||||||
// of every inbound Response. The Jar is consulted for every
|
|
||||||
// redirect that the Client follows.
|
|
||||||
//
|
|
||||||
// If Jar is nil, cookies are only sent if they are explicitly
|
|
||||||
// set on the Request.
|
|
||||||
Jar CookieJar
|
|
||||||
|
|
||||||
// Timeout specifies a time limit for requests made by this
|
|
||||||
// Client. The timeout includes connection time, any
|
|
||||||
// redirects, and reading the response body. The timer remains
|
|
||||||
// running after Get, Head, Post, or Do return and will
|
|
||||||
// interrupt reading of the Response.Body.
|
|
||||||
//
|
|
||||||
// A Timeout of zero means no timeout.
|
|
||||||
//
|
|
||||||
// The Client cancels requests to the underlying Transport
|
|
||||||
// as if the Request's Context ended.
|
|
||||||
//
|
|
||||||
// For compatibility, the Client will also use the deprecated
|
|
||||||
// CancelRequest method on Transport if found. New
|
|
||||||
// RoundTripper implementations should use the Request's Context
|
|
||||||
// for cancellation instead of implementing CancelRequest.
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultClient is the default Client and is used by Get, Head, and Post.
|
|
||||||
var DefaultClient = &Client{}
|
|
||||||
|
|
||||||
// RoundTripper is an interface representing the ability to execute a
|
|
||||||
// single HTTP transaction, obtaining the Response for a given Request.
|
|
||||||
//
|
|
||||||
// A RoundTripper must be safe for concurrent use by multiple
|
|
||||||
// goroutines.
|
|
||||||
type RoundTripper interface {
|
|
||||||
// RoundTrip executes a single HTTP transaction, returning
|
|
||||||
// a Response for the provided Request.
|
|
||||||
//
|
|
||||||
// RoundTrip should not attempt to interpret the response. In
|
|
||||||
// particular, RoundTrip must return err == nil if it obtained
|
|
||||||
// a response, regardless of the response's HTTP status code.
|
|
||||||
// A non-nil err should be reserved for failure to obtain a
|
|
||||||
// response. Similarly, RoundTrip should not attempt to
|
|
||||||
// handle higher-level protocol details such as redirects,
|
|
||||||
// authentication, or cookies.
|
|
||||||
//
|
|
||||||
// RoundTrip should not modify the request, except for
|
|
||||||
// consuming and closing the Request's Body. RoundTrip may
|
|
||||||
// read fields of the request in a separate goroutine. Callers
|
|
||||||
// should not mutate or reuse the request until the Response's
|
|
||||||
// Body has been closed.
|
|
||||||
//
|
|
||||||
// RoundTrip must always close the body, including on errors,
|
|
||||||
// but depending on the implementation may do so in a separate
|
|
||||||
// goroutine even after RoundTrip returns. This means that
|
|
||||||
// callers wanting to reuse the body for subsequent requests
|
|
||||||
// must arrange to wait for the Close call before doing so.
|
|
||||||
//
|
|
||||||
// The Request's URL and Header fields must be initialized.
|
|
||||||
RoundTrip(*Request) (*Response, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get issues a GET to the specified URL. If the response is one of
|
|
||||||
// the following redirect codes, Get follows the redirect, up to a
|
|
||||||
// maximum of 10 redirects:
|
|
||||||
//
|
|
||||||
// 301 (Moved Permanently)
|
|
||||||
// 302 (Found)
|
|
||||||
// 303 (See Other)
|
|
||||||
// 307 (Temporary Redirect)
|
|
||||||
// 308 (Permanent Redirect)
|
|
||||||
//
|
|
||||||
// An error is returned if there were too many redirects or if there
|
|
||||||
// was an HTTP protocol error. A non-2xx response doesn't cause an
|
|
||||||
// error. Any returned error will be of type *url.Error. The url.Error
|
|
||||||
// value's Timeout method will report true if request timed out or was
|
|
||||||
// canceled.
|
|
||||||
//
|
|
||||||
// When err is nil, resp always contains a non-nil resp.Body.
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// Get is a wrapper around DefaultClient.Get.
|
|
||||||
//
|
|
||||||
// To make a request with custom headers, use NewRequest and
|
|
||||||
// DefaultClient.Do.
|
|
||||||
func Get(url string) (resp *Response, err error) {
|
|
||||||
return DefaultClient.Get(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get issues a GET to the specified URL. If the response is one of the
|
|
||||||
// following redirect codes, Get follows the redirect after calling the
|
|
||||||
// Client's CheckRedirect function:
|
|
||||||
//
|
|
||||||
// 301 (Moved Permanently)
|
|
||||||
// 302 (Found)
|
|
||||||
// 303 (See Other)
|
|
||||||
// 307 (Temporary Redirect)
|
|
||||||
// 308 (Permanent Redirect)
|
|
||||||
//
|
|
||||||
// An error is returned if the Client's CheckRedirect function fails
|
|
||||||
// or if there was an HTTP protocol error. A non-2xx response doesn't
|
|
||||||
// cause an error. Any returned error will be of type *url.Error. The
|
|
||||||
// url.Error value's Timeout method will report true if the request
|
|
||||||
// timed out.
|
|
||||||
//
|
|
||||||
// When err is nil, resp always contains a non-nil resp.Body.
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// To make a request with custom headers, use NewRequest and Client.Do.
|
|
||||||
func (c *Client) Get(url string) (resp *Response, err error) {
|
|
||||||
req, err := NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.Do(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post issues a POST to the specified URL.
|
|
||||||
//
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// If the provided body is an io.Closer, it is closed after the
|
|
||||||
// request.
|
|
||||||
//
|
|
||||||
// Post is a wrapper around DefaultClient.Post.
|
|
||||||
//
|
|
||||||
// To set custom headers, use NewRequest and DefaultClient.Do.
|
|
||||||
//
|
|
||||||
// See the Client.Do method documentation for details on how redirects
|
|
||||||
// are handled.
|
|
||||||
func Post(url, contentType string, body io.Reader) (resp *Response, err error) {
|
|
||||||
return DefaultClient.Post(url, contentType, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post issues a POST to the specified URL.
|
|
||||||
//
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// If the provided body is an io.Closer, it is closed after the
|
|
||||||
// request.
|
|
||||||
//
|
|
||||||
// To set custom headers, use NewRequest and Client.Do.
|
|
||||||
//
|
|
||||||
// See the Client.Do method documentation for details on how redirects
|
|
||||||
// are handled.
|
|
||||||
func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error) {
|
|
||||||
req, err := NewRequest("POST", url, body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", contentType)
|
|
||||||
return c.Do(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostForm issues a POST to the specified URL, with data's keys and
|
|
||||||
// values URL-encoded as the request body.
|
|
||||||
//
|
|
||||||
// The Content-Type header is set to application/x-www-form-urlencoded.
|
|
||||||
// To set other headers, use NewRequest and DefaultClient.Do.
|
|
||||||
//
|
|
||||||
// When err is nil, resp always contains a non-nil resp.Body.
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// PostForm is a wrapper around DefaultClient.PostForm.
|
|
||||||
//
|
|
||||||
// See the Client.Do method documentation for details on how redirects
|
|
||||||
// are handled.
|
|
||||||
//
|
|
||||||
// To make a request with a specified context.Context, use NewRequestWithContext
|
|
||||||
// and DefaultClient.Do.
|
|
||||||
func PostForm(url string, data url.Values) (resp *Response, err error) {
|
|
||||||
return DefaultClient.PostForm(url, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostForm issues a POST to the specified URL,
|
|
||||||
// with data's keys and values URL-encoded as the request body.
|
|
||||||
//
|
|
||||||
// The Content-Type header is set to application/x-www-form-urlencoded.
|
|
||||||
// To set other headers, use NewRequest and Client.Do.
|
|
||||||
//
|
|
||||||
// When err is nil, resp always contains a non-nil resp.Body.
|
|
||||||
// Caller should close resp.Body when done reading from it.
|
|
||||||
//
|
|
||||||
// See the Client.Do method documentation for details on how redirects
|
|
||||||
// are handled.
|
|
||||||
//
|
|
||||||
// To make a request with a specified context.Context, use NewRequestWithContext
|
|
||||||
// and Client.Do.
|
|
||||||
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
|
|
||||||
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
|
||||||
}
|
|
||||||
@@ -1,435 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/textproto"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
|
|
||||||
// HTTP response or the Cookie header of an HTTP request.
|
|
||||||
//
|
|
||||||
// See https://tools.ietf.org/html/rfc6265 for details.
|
|
||||||
type Cookie struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
|
|
||||||
Path string // optional
|
|
||||||
Domain string // optional
|
|
||||||
Expires time.Time // optional
|
|
||||||
RawExpires string // for reading cookies only
|
|
||||||
|
|
||||||
// MaxAge=0 means no 'Max-Age' attribute specified.
|
|
||||||
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
|
|
||||||
// MaxAge>0 means Max-Age attribute present and given in seconds
|
|
||||||
MaxAge int
|
|
||||||
Secure bool
|
|
||||||
HttpOnly bool
|
|
||||||
SameSite SameSite
|
|
||||||
Raw string
|
|
||||||
Unparsed []string // Raw text of unparsed attribute-value pairs
|
|
||||||
}
|
|
||||||
|
|
||||||
// SameSite allows a server to define a cookie attribute making it impossible for
|
|
||||||
// the browser to send this cookie along with cross-site requests. The main
|
|
||||||
// goal is to mitigate the risk of cross-origin information leakage, and provide
|
|
||||||
// some protection against cross-site request forgery attacks.
|
|
||||||
//
|
|
||||||
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
|
|
||||||
type SameSite int
|
|
||||||
|
|
||||||
const (
|
|
||||||
SameSiteDefaultMode SameSite = iota + 1
|
|
||||||
SameSiteLaxMode
|
|
||||||
SameSiteStrictMode
|
|
||||||
SameSiteNoneMode
|
|
||||||
)
|
|
||||||
|
|
||||||
// readSetCookies parses all "Set-Cookie" values from
|
|
||||||
// the header h and returns the successfully parsed Cookies.
|
|
||||||
func readSetCookies(h Header) []*Cookie {
|
|
||||||
cookieCount := len(h["Set-Cookie"])
|
|
||||||
if cookieCount == 0 {
|
|
||||||
return []*Cookie{}
|
|
||||||
}
|
|
||||||
cookies := make([]*Cookie, 0, cookieCount)
|
|
||||||
for _, line := range h["Set-Cookie"] {
|
|
||||||
parts := strings.Split(textproto.TrimString(line), ";")
|
|
||||||
if len(parts) == 1 && parts[0] == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts[0] = textproto.TrimString(parts[0])
|
|
||||||
j := strings.Index(parts[0], "=")
|
|
||||||
if j < 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name, value := parts[0][:j], parts[0][j+1:]
|
|
||||||
if !isCookieNameValid(name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
value, ok := parseCookieValue(value, true)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c := &Cookie{
|
|
||||||
Name: name,
|
|
||||||
Value: value,
|
|
||||||
Raw: line,
|
|
||||||
}
|
|
||||||
for i := 1; i < len(parts); i++ {
|
|
||||||
parts[i] = textproto.TrimString(parts[i])
|
|
||||||
if len(parts[i]) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
attr, val := parts[i], ""
|
|
||||||
if j := strings.Index(attr, "="); j >= 0 {
|
|
||||||
attr, val = attr[:j], attr[j+1:]
|
|
||||||
}
|
|
||||||
lowerAttr := strings.ToLower(attr)
|
|
||||||
val, ok = parseCookieValue(val, false)
|
|
||||||
if !ok {
|
|
||||||
c.Unparsed = append(c.Unparsed, parts[i])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch lowerAttr {
|
|
||||||
case "samesite":
|
|
||||||
lowerVal := strings.ToLower(val)
|
|
||||||
switch lowerVal {
|
|
||||||
case "lax":
|
|
||||||
c.SameSite = SameSiteLaxMode
|
|
||||||
case "strict":
|
|
||||||
c.SameSite = SameSiteStrictMode
|
|
||||||
case "none":
|
|
||||||
c.SameSite = SameSiteNoneMode
|
|
||||||
default:
|
|
||||||
c.SameSite = SameSiteDefaultMode
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
case "secure":
|
|
||||||
c.Secure = true
|
|
||||||
continue
|
|
||||||
case "httponly":
|
|
||||||
c.HttpOnly = true
|
|
||||||
continue
|
|
||||||
case "domain":
|
|
||||||
c.Domain = val
|
|
||||||
continue
|
|
||||||
case "max-age":
|
|
||||||
secs, err := strconv.Atoi(val)
|
|
||||||
if err != nil || secs != 0 && val[0] == '0' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if secs <= 0 {
|
|
||||||
secs = -1
|
|
||||||
}
|
|
||||||
c.MaxAge = secs
|
|
||||||
continue
|
|
||||||
case "expires":
|
|
||||||
c.RawExpires = val
|
|
||||||
exptime, err := time.Parse(time.RFC1123, val)
|
|
||||||
if err != nil {
|
|
||||||
exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val)
|
|
||||||
if err != nil {
|
|
||||||
c.Expires = time.Time{}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.Expires = exptime.UTC()
|
|
||||||
continue
|
|
||||||
case "path":
|
|
||||||
c.Path = val
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c.Unparsed = append(c.Unparsed, parts[i])
|
|
||||||
}
|
|
||||||
cookies = append(cookies, c)
|
|
||||||
}
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
|
|
||||||
// The provided cookie must have a valid Name. Invalid cookies may be
|
|
||||||
// silently dropped.
|
|
||||||
func SetCookie(w ResponseWriter, cookie *Cookie) {
|
|
||||||
if v := cookie.String(); v != "" {
|
|
||||||
w.Header().Add("Set-Cookie", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the serialization of the cookie for use in a Cookie
|
|
||||||
// header (if only Name and Value are set) or a Set-Cookie response
|
|
||||||
// header (if other fields are set).
|
|
||||||
// If c is nil or c.Name is invalid, the empty string is returned.
|
|
||||||
func (c *Cookie) String() string {
|
|
||||||
if c == nil || !isCookieNameValid(c.Name) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// extraCookieLength derived from typical length of cookie attributes
|
|
||||||
// see RFC 6265 Sec 4.1.
|
|
||||||
const extraCookieLength = 110
|
|
||||||
var b strings.Builder
|
|
||||||
b.Grow(len(c.Name) + len(c.Value) + len(c.Domain) + len(c.Path) + extraCookieLength)
|
|
||||||
b.WriteString(c.Name)
|
|
||||||
b.WriteRune('=')
|
|
||||||
b.WriteString(sanitizeCookieValue(c.Value))
|
|
||||||
|
|
||||||
if len(c.Path) > 0 {
|
|
||||||
b.WriteString("; Path=")
|
|
||||||
b.WriteString(sanitizeCookiePath(c.Path))
|
|
||||||
}
|
|
||||||
if len(c.Domain) > 0 {
|
|
||||||
if validCookieDomain(c.Domain) {
|
|
||||||
// A c.Domain containing illegal characters is not
|
|
||||||
// sanitized but simply dropped which turns the cookie
|
|
||||||
// into a host-only cookie. A leading dot is okay
|
|
||||||
// but won't be sent.
|
|
||||||
d := c.Domain
|
|
||||||
if d[0] == '.' {
|
|
||||||
d = d[1:]
|
|
||||||
}
|
|
||||||
b.WriteString("; Domain=")
|
|
||||||
b.WriteString(d)
|
|
||||||
} else {
|
|
||||||
log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", c.Domain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var buf [len(TimeFormat)]byte
|
|
||||||
if validCookieExpires(c.Expires) {
|
|
||||||
b.WriteString("; Expires=")
|
|
||||||
b.Write(c.Expires.UTC().AppendFormat(buf[:0], TimeFormat))
|
|
||||||
}
|
|
||||||
if c.MaxAge > 0 {
|
|
||||||
b.WriteString("; Max-Age=")
|
|
||||||
b.Write(strconv.AppendInt(buf[:0], int64(c.MaxAge), 10))
|
|
||||||
} else if c.MaxAge < 0 {
|
|
||||||
b.WriteString("; Max-Age=0")
|
|
||||||
}
|
|
||||||
if c.HttpOnly {
|
|
||||||
b.WriteString("; HttpOnly")
|
|
||||||
}
|
|
||||||
if c.Secure {
|
|
||||||
b.WriteString("; Secure")
|
|
||||||
}
|
|
||||||
switch c.SameSite {
|
|
||||||
case SameSiteDefaultMode:
|
|
||||||
// Skip, default mode is obtained by not emitting the attribute.
|
|
||||||
case SameSiteNoneMode:
|
|
||||||
b.WriteString("; SameSite=None")
|
|
||||||
case SameSiteLaxMode:
|
|
||||||
b.WriteString("; SameSite=Lax")
|
|
||||||
case SameSiteStrictMode:
|
|
||||||
b.WriteString("; SameSite=Strict")
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// readCookies parses all "Cookie" values from the header h and
|
|
||||||
// returns the successfully parsed Cookies.
|
|
||||||
//
|
|
||||||
// if filter isn't empty, only cookies of that name are returned
|
|
||||||
func readCookies(h Header, filter string) []*Cookie {
|
|
||||||
lines := h["Cookie"]
|
|
||||||
if len(lines) == 0 {
|
|
||||||
return []*Cookie{}
|
|
||||||
}
|
|
||||||
|
|
||||||
cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
|
|
||||||
for _, line := range lines {
|
|
||||||
line = textproto.TrimString(line)
|
|
||||||
|
|
||||||
var part string
|
|
||||||
for len(line) > 0 { // continue since we have rest
|
|
||||||
if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
|
|
||||||
part, line = line[:splitIndex], line[splitIndex+1:]
|
|
||||||
} else {
|
|
||||||
part, line = line, ""
|
|
||||||
}
|
|
||||||
part = textproto.TrimString(part)
|
|
||||||
if len(part) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name, val := part, ""
|
|
||||||
if j := strings.Index(part, "="); j >= 0 {
|
|
||||||
name, val = name[:j], name[j+1:]
|
|
||||||
}
|
|
||||||
if !isCookieNameValid(name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if filter != "" && filter != name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val, ok := parseCookieValue(val, true)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cookies = append(cookies, &Cookie{Name: name, Value: val})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
|
|
||||||
// validCookieDomain reports whether v is a valid cookie domain-value.
|
|
||||||
func validCookieDomain(v string) bool {
|
|
||||||
if isCookieDomainName(v) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if net.ParseIP(v) != nil && !strings.Contains(v, ":") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// validCookieExpires reports whether v is a valid cookie expires-value.
|
|
||||||
func validCookieExpires(t time.Time) bool {
|
|
||||||
// IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601
|
|
||||||
return t.Year() >= 1601
|
|
||||||
}
|
|
||||||
|
|
||||||
// isCookieDomainName reports whether s is a valid domain name or a valid
|
|
||||||
// domain name with a leading dot '.'. It is almost a direct copy of
|
|
||||||
// package net's isDomainName.
|
|
||||||
func isCookieDomainName(s string) bool {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(s) > 255 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if s[0] == '.' {
|
|
||||||
// A cookie a domain attribute may start with a leading dot.
|
|
||||||
s = s[1:]
|
|
||||||
}
|
|
||||||
last := byte('.')
|
|
||||||
ok := false // Ok once we've seen a letter.
|
|
||||||
partlen := 0
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
switch {
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
|
|
||||||
// No '_' allowed here (in contrast to package net).
|
|
||||||
ok = true
|
|
||||||
partlen++
|
|
||||||
case '0' <= c && c <= '9':
|
|
||||||
// fine
|
|
||||||
partlen++
|
|
||||||
case c == '-':
|
|
||||||
// Byte before dash cannot be dot.
|
|
||||||
if last == '.' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
partlen++
|
|
||||||
case c == '.':
|
|
||||||
// Byte before dot cannot be dot, dash.
|
|
||||||
if last == '.' || last == '-' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if partlen > 63 || partlen == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
partlen = 0
|
|
||||||
}
|
|
||||||
last = c
|
|
||||||
}
|
|
||||||
if last == '-' || partlen > 63 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
|
|
||||||
|
|
||||||
func sanitizeCookieName(n string) string {
|
|
||||||
return cookieNameSanitizer.Replace(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanitizeCookieValue produces a suitable cookie-value from v.
|
|
||||||
// https://tools.ietf.org/html/rfc6265#section-4.1.1
|
|
||||||
// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
|
|
||||||
// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
|
||||||
//
|
|
||||||
// ; US-ASCII characters excluding CTLs,
|
|
||||||
// ; whitespace DQUOTE, comma, semicolon,
|
|
||||||
// ; and backslash
|
|
||||||
//
|
|
||||||
// We loosen this as spaces and commas are common in cookie values
|
|
||||||
// but we produce a quoted cookie-value if and only if v contains
|
|
||||||
// commas or spaces.
|
|
||||||
// See https://golang.org/issue/7243 for the discussion.
|
|
||||||
func sanitizeCookieValue(v string) string {
|
|
||||||
v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
|
|
||||||
if len(v) == 0 {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if strings.IndexByte(v, ' ') >= 0 || strings.IndexByte(v, ',') >= 0 {
|
|
||||||
return `"` + v + `"`
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func validCookieValueByte(b byte) bool {
|
|
||||||
return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\'
|
|
||||||
}
|
|
||||||
|
|
||||||
// path-av = "Path=" path-value
|
|
||||||
// path-value = <any CHAR except CTLs or ";">
|
|
||||||
func sanitizeCookiePath(v string) string {
|
|
||||||
return sanitizeOrWarn("Cookie.Path", validCookiePathByte, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func validCookiePathByte(b byte) bool {
|
|
||||||
return 0x20 <= b && b < 0x7f && b != ';'
|
|
||||||
}
|
|
||||||
|
|
||||||
func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string {
|
|
||||||
ok := true
|
|
||||||
for i := 0; i < len(v); i++ {
|
|
||||||
if valid(v[i]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("net/http: invalid byte %q in %s; dropping invalid bytes", v[i], fieldName)
|
|
||||||
ok = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
buf := make([]byte, 0, len(v))
|
|
||||||
for i := 0; i < len(v); i++ {
|
|
||||||
if b := v[i]; valid(b) {
|
|
||||||
buf = append(buf, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
|
|
||||||
// Strip the quotes, if present.
|
|
||||||
if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
|
|
||||||
raw = raw[1 : len(raw)-1]
|
|
||||||
}
|
|
||||||
for i := 0; i < len(raw); i++ {
|
|
||||||
if !validCookieValueByte(raw[i]) {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return raw, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func isCookieNameValid(raw string) bool {
|
|
||||||
if raw == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.IndexFunc(raw, isNotToken) < 0
|
|
||||||
}
|
|
||||||
@@ -1,504 +0,0 @@
|
|||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package cookiejar implements an in-memory RFC 6265-compliant http.CookieJar.
|
|
||||||
package cookiejar
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
|
||||||
"tinygo.org/x/drivers/net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PublicSuffixList provides the public suffix of a domain. For example:
|
|
||||||
// - the public suffix of "example.com" is "com",
|
|
||||||
// - the public suffix of "foo1.foo2.foo3.co.uk" is "co.uk", and
|
|
||||||
// - the public suffix of "bar.pvt.k12.ma.us" is "pvt.k12.ma.us".
|
|
||||||
//
|
|
||||||
// Implementations of PublicSuffixList must be safe for concurrent use by
|
|
||||||
// multiple goroutines.
|
|
||||||
//
|
|
||||||
// An implementation that always returns "" is valid and may be useful for
|
|
||||||
// testing but it is not secure: it means that the HTTP server for foo.com can
|
|
||||||
// set a cookie for bar.com.
|
|
||||||
//
|
|
||||||
// A public suffix list implementation is in the package
|
|
||||||
// golang.org/x/net/publicsuffix.
|
|
||||||
type PublicSuffixList interface {
|
|
||||||
// PublicSuffix returns the public suffix of domain.
|
|
||||||
//
|
|
||||||
// TODO: specify which of the caller and callee is responsible for IP
|
|
||||||
// addresses, for leading and trailing dots, for case sensitivity, and
|
|
||||||
// for IDN/Punycode.
|
|
||||||
PublicSuffix(domain string) string
|
|
||||||
|
|
||||||
// String returns a description of the source of this public suffix
|
|
||||||
// list. The description will typically contain something like a time
|
|
||||||
// stamp or version number.
|
|
||||||
String() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options are the options for creating a new Jar.
|
|
||||||
type Options struct {
|
|
||||||
// PublicSuffixList is the public suffix list that determines whether
|
|
||||||
// an HTTP server can set a cookie for a domain.
|
|
||||||
//
|
|
||||||
// A nil value is valid and may be useful for testing but it is not
|
|
||||||
// secure: it means that the HTTP server for foo.co.uk can set a cookie
|
|
||||||
// for bar.co.uk.
|
|
||||||
PublicSuffixList PublicSuffixList
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jar implements the http.CookieJar interface from the net/http package.
|
|
||||||
type Jar struct {
|
|
||||||
psList PublicSuffixList
|
|
||||||
|
|
||||||
// mu locks the remaining fields.
|
|
||||||
mu sync.Mutex
|
|
||||||
|
|
||||||
// entries is a set of entries, keyed by their eTLD+1 and subkeyed by
|
|
||||||
// their name/domain/path.
|
|
||||||
entries map[string]map[string]entry
|
|
||||||
|
|
||||||
// nextSeqNum is the next sequence number assigned to a new cookie
|
|
||||||
// created SetCookies.
|
|
||||||
nextSeqNum uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new cookie jar. A nil *Options is equivalent to a zero
|
|
||||||
// Options.
|
|
||||||
func New(o *Options) (*Jar, error) {
|
|
||||||
jar := &Jar{
|
|
||||||
entries: make(map[string]map[string]entry),
|
|
||||||
}
|
|
||||||
if o != nil {
|
|
||||||
jar.psList = o.PublicSuffixList
|
|
||||||
}
|
|
||||||
return jar, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// entry is the internal representation of a cookie.
|
|
||||||
//
|
|
||||||
// This struct type is not used outside of this package per se, but the exported
|
|
||||||
// fields are those of RFC 6265.
|
|
||||||
type entry struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
Domain string
|
|
||||||
Path string
|
|
||||||
SameSite string
|
|
||||||
Secure bool
|
|
||||||
HttpOnly bool
|
|
||||||
Persistent bool
|
|
||||||
HostOnly bool
|
|
||||||
Expires time.Time
|
|
||||||
Creation time.Time
|
|
||||||
LastAccess time.Time
|
|
||||||
|
|
||||||
// seqNum is a sequence number so that Cookies returns cookies in a
|
|
||||||
// deterministic order, even for cookies that have equal Path length and
|
|
||||||
// equal Creation time. This simplifies testing.
|
|
||||||
seqNum uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// id returns the domain;path;name triple of e as an id.
|
|
||||||
func (e *entry) id() string {
|
|
||||||
return fmt.Sprintf("%s;%s;%s", e.Domain, e.Path, e.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shouldSend determines whether e's cookie qualifies to be included in a
|
|
||||||
// request to host/path. It is the caller's responsibility to check if the
|
|
||||||
// cookie is expired.
|
|
||||||
func (e *entry) shouldSend(https bool, host, path string) bool {
|
|
||||||
return e.domainMatch(host) && e.pathMatch(path) && (https || !e.Secure)
|
|
||||||
}
|
|
||||||
|
|
||||||
// domainMatch implements "domain-match" of RFC 6265 section 5.1.3.
|
|
||||||
func (e *entry) domainMatch(host string) bool {
|
|
||||||
if e.Domain == host {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return !e.HostOnly && hasDotSuffix(host, e.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathMatch implements "path-match" according to RFC 6265 section 5.1.4.
|
|
||||||
func (e *entry) pathMatch(requestPath string) bool {
|
|
||||||
if requestPath == e.Path {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(requestPath, e.Path) {
|
|
||||||
if e.Path[len(e.Path)-1] == '/' {
|
|
||||||
return true // The "/any/" matches "/any/path" case.
|
|
||||||
} else if requestPath[len(e.Path)] == '/' {
|
|
||||||
return true // The "/any" matches "/any/path" case.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasDotSuffix reports whether s ends in "."+suffix.
|
|
||||||
func hasDotSuffix(s, suffix string) bool {
|
|
||||||
return len(s) > len(suffix) && s[len(s)-len(suffix)-1] == '.' && s[len(s)-len(suffix):] == suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cookies implements the Cookies method of the http.CookieJar interface.
|
|
||||||
//
|
|
||||||
// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
|
|
||||||
func (j *Jar) Cookies(u *url.URL) (cookies []*http.Cookie) {
|
|
||||||
return j.cookies(u, time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// cookies is like Cookies but takes the current time as a parameter.
|
|
||||||
func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) {
|
|
||||||
if u.Scheme != "http" && u.Scheme != "https" {
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
host, err := canonicalHost(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
key := jarKey(host, j.psList)
|
|
||||||
|
|
||||||
j.mu.Lock()
|
|
||||||
defer j.mu.Unlock()
|
|
||||||
|
|
||||||
submap := j.entries[key]
|
|
||||||
if submap == nil {
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
|
|
||||||
https := u.Scheme == "https"
|
|
||||||
path := u.Path
|
|
||||||
if path == "" {
|
|
||||||
path = "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
modified := false
|
|
||||||
var selected []entry
|
|
||||||
for id, e := range submap {
|
|
||||||
if e.Persistent && !e.Expires.After(now) {
|
|
||||||
delete(submap, id)
|
|
||||||
modified = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !e.shouldSend(https, host, path) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
e.LastAccess = now
|
|
||||||
submap[id] = e
|
|
||||||
selected = append(selected, e)
|
|
||||||
modified = true
|
|
||||||
}
|
|
||||||
if modified {
|
|
||||||
if len(submap) == 0 {
|
|
||||||
delete(j.entries, key)
|
|
||||||
} else {
|
|
||||||
j.entries[key] = submap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort according to RFC 6265 section 5.4 point 2: by longest
|
|
||||||
// path and then by earliest creation time.
|
|
||||||
sort.Slice(selected, func(i, j int) bool {
|
|
||||||
s := selected
|
|
||||||
if len(s[i].Path) != len(s[j].Path) {
|
|
||||||
return len(s[i].Path) > len(s[j].Path)
|
|
||||||
}
|
|
||||||
if !s[i].Creation.Equal(s[j].Creation) {
|
|
||||||
return s[i].Creation.Before(s[j].Creation)
|
|
||||||
}
|
|
||||||
return s[i].seqNum < s[j].seqNum
|
|
||||||
})
|
|
||||||
for _, e := range selected {
|
|
||||||
cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value})
|
|
||||||
}
|
|
||||||
|
|
||||||
return cookies
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCookies implements the SetCookies method of the http.CookieJar interface.
|
|
||||||
//
|
|
||||||
// It does nothing if the URL's scheme is not HTTP or HTTPS.
|
|
||||||
func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
|
|
||||||
j.setCookies(u, cookies, time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// setCookies is like SetCookies but takes the current time as parameter.
|
|
||||||
func (j *Jar) setCookies(u *url.URL, cookies []*http.Cookie, now time.Time) {
|
|
||||||
if len(cookies) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if u.Scheme != "http" && u.Scheme != "https" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
host, err := canonicalHost(u.Host)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
key := jarKey(host, j.psList)
|
|
||||||
defPath := defaultPath(u.Path)
|
|
||||||
|
|
||||||
j.mu.Lock()
|
|
||||||
defer j.mu.Unlock()
|
|
||||||
|
|
||||||
submap := j.entries[key]
|
|
||||||
|
|
||||||
modified := false
|
|
||||||
for _, cookie := range cookies {
|
|
||||||
e, remove, err := j.newEntry(cookie, now, defPath, host)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
id := e.id()
|
|
||||||
if remove {
|
|
||||||
if submap != nil {
|
|
||||||
if _, ok := submap[id]; ok {
|
|
||||||
delete(submap, id)
|
|
||||||
modified = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if submap == nil {
|
|
||||||
submap = make(map[string]entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if old, ok := submap[id]; ok {
|
|
||||||
e.Creation = old.Creation
|
|
||||||
e.seqNum = old.seqNum
|
|
||||||
} else {
|
|
||||||
e.Creation = now
|
|
||||||
e.seqNum = j.nextSeqNum
|
|
||||||
j.nextSeqNum++
|
|
||||||
}
|
|
||||||
e.LastAccess = now
|
|
||||||
submap[id] = e
|
|
||||||
modified = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if modified {
|
|
||||||
if len(submap) == 0 {
|
|
||||||
delete(j.entries, key)
|
|
||||||
} else {
|
|
||||||
j.entries[key] = submap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// canonicalHost strips port from host if present and returns the canonicalized
|
|
||||||
// host name.
|
|
||||||
func canonicalHost(host string) (string, error) {
|
|
||||||
var err error
|
|
||||||
host = strings.ToLower(host)
|
|
||||||
if hasPort(host) {
|
|
||||||
host, _, err = net.SplitHostPort(host)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(host, ".") {
|
|
||||||
// Strip trailing dot from fully qualified domain names.
|
|
||||||
host = host[:len(host)-1]
|
|
||||||
}
|
|
||||||
return toASCII(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasPort reports whether host contains a port number. host may be a host
|
|
||||||
// name, an IPv4 or an IPv6 address.
|
|
||||||
func hasPort(host string) bool {
|
|
||||||
colons := strings.Count(host, ":")
|
|
||||||
if colons == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if colons == 1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return host[0] == '[' && strings.Contains(host, "]:")
|
|
||||||
}
|
|
||||||
|
|
||||||
// jarKey returns the key to use for a jar.
|
|
||||||
func jarKey(host string, psl PublicSuffixList) string {
|
|
||||||
if isIP(host) {
|
|
||||||
return host
|
|
||||||
}
|
|
||||||
|
|
||||||
var i int
|
|
||||||
if psl == nil {
|
|
||||||
i = strings.LastIndex(host, ".")
|
|
||||||
if i <= 0 {
|
|
||||||
return host
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
suffix := psl.PublicSuffix(host)
|
|
||||||
if suffix == host {
|
|
||||||
return host
|
|
||||||
}
|
|
||||||
i = len(host) - len(suffix)
|
|
||||||
if i <= 0 || host[i-1] != '.' {
|
|
||||||
// The provided public suffix list psl is broken.
|
|
||||||
// Storing cookies under host is a safe stopgap.
|
|
||||||
return host
|
|
||||||
}
|
|
||||||
// Only len(suffix) is used to determine the jar key from
|
|
||||||
// here on, so it is okay if psl.PublicSuffix("www.buggy.psl")
|
|
||||||
// returns "com" as the jar key is generated from host.
|
|
||||||
}
|
|
||||||
prevDot := strings.LastIndex(host[:i-1], ".")
|
|
||||||
return host[prevDot+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// isIP reports whether host is an IP address.
|
|
||||||
func isIP(host string) bool {
|
|
||||||
return net.ParseIP(host) != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultPath returns the directory part of an URL's path according to
|
|
||||||
// RFC 6265 section 5.1.4.
|
|
||||||
func defaultPath(path string) string {
|
|
||||||
if len(path) == 0 || path[0] != '/' {
|
|
||||||
return "/" // Path is empty or malformed.
|
|
||||||
}
|
|
||||||
|
|
||||||
i := strings.LastIndex(path, "/") // Path starts with "/", so i != -1.
|
|
||||||
if i == 0 {
|
|
||||||
return "/" // Path has the form "/abc".
|
|
||||||
}
|
|
||||||
return path[:i] // Path is either of form "/abc/xyz" or "/abc/xyz/".
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEntry creates an entry from a http.Cookie c. now is the current time and
|
|
||||||
// is compared to c.Expires to determine deletion of c. defPath and host are the
|
|
||||||
// default-path and the canonical host name of the URL c was received from.
|
|
||||||
//
|
|
||||||
// remove records whether the jar should delete this cookie, as it has already
|
|
||||||
// expired with respect to now. In this case, e may be incomplete, but it will
|
|
||||||
// be valid to call e.id (which depends on e's Name, Domain and Path).
|
|
||||||
//
|
|
||||||
// A malformed c.Domain will result in an error.
|
|
||||||
func (j *Jar) newEntry(c *http.Cookie, now time.Time, defPath, host string) (e entry, remove bool, err error) {
|
|
||||||
e.Name = c.Name
|
|
||||||
|
|
||||||
if c.Path == "" || c.Path[0] != '/' {
|
|
||||||
e.Path = defPath
|
|
||||||
} else {
|
|
||||||
e.Path = c.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Domain, e.HostOnly, err = j.domainAndType(host, c.Domain)
|
|
||||||
if err != nil {
|
|
||||||
return e, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxAge takes precedence over Expires.
|
|
||||||
if c.MaxAge < 0 {
|
|
||||||
return e, true, nil
|
|
||||||
} else if c.MaxAge > 0 {
|
|
||||||
e.Expires = now.Add(time.Duration(c.MaxAge) * time.Second)
|
|
||||||
e.Persistent = true
|
|
||||||
} else {
|
|
||||||
if c.Expires.IsZero() {
|
|
||||||
e.Expires = endOfTime
|
|
||||||
e.Persistent = false
|
|
||||||
} else {
|
|
||||||
if !c.Expires.After(now) {
|
|
||||||
return e, true, nil
|
|
||||||
}
|
|
||||||
e.Expires = c.Expires
|
|
||||||
e.Persistent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Value = c.Value
|
|
||||||
e.Secure = c.Secure
|
|
||||||
e.HttpOnly = c.HttpOnly
|
|
||||||
|
|
||||||
switch c.SameSite {
|
|
||||||
case http.SameSiteDefaultMode:
|
|
||||||
e.SameSite = "SameSite"
|
|
||||||
case http.SameSiteStrictMode:
|
|
||||||
e.SameSite = "SameSite=Strict"
|
|
||||||
case http.SameSiteLaxMode:
|
|
||||||
e.SameSite = "SameSite=Lax"
|
|
||||||
}
|
|
||||||
|
|
||||||
return e, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errIllegalDomain = errors.New("cookiejar: illegal cookie domain attribute")
|
|
||||||
errMalformedDomain = errors.New("cookiejar: malformed cookie domain attribute")
|
|
||||||
errNoHostname = errors.New("cookiejar: no host name available (IP only)")
|
|
||||||
)
|
|
||||||
|
|
||||||
// endOfTime is the time when session (non-persistent) cookies expire.
|
|
||||||
// This instant is representable in most date/time formats (not just
|
|
||||||
// Go's time.Time) and should be far enough in the future.
|
|
||||||
var endOfTime = time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC)
|
|
||||||
|
|
||||||
// domainAndType determines the cookie's domain and hostOnly attribute.
|
|
||||||
func (j *Jar) domainAndType(host, domain string) (string, bool, error) {
|
|
||||||
if domain == "" {
|
|
||||||
// No domain attribute in the SetCookie header indicates a
|
|
||||||
// host cookie.
|
|
||||||
return host, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if isIP(host) {
|
|
||||||
// According to RFC 6265 domain-matching includes not being
|
|
||||||
// an IP address.
|
|
||||||
// TODO: This might be relaxed as in common browsers.
|
|
||||||
return "", false, errNoHostname
|
|
||||||
}
|
|
||||||
|
|
||||||
// From here on: If the cookie is valid, it is a domain cookie (with
|
|
||||||
// the one exception of a public suffix below).
|
|
||||||
// See RFC 6265 section 5.2.3.
|
|
||||||
if domain[0] == '.' {
|
|
||||||
domain = domain[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domain) == 0 || domain[0] == '.' {
|
|
||||||
// Received either "Domain=." or "Domain=..some.thing",
|
|
||||||
// both are illegal.
|
|
||||||
return "", false, errMalformedDomain
|
|
||||||
}
|
|
||||||
domain = strings.ToLower(domain)
|
|
||||||
|
|
||||||
if domain[len(domain)-1] == '.' {
|
|
||||||
// We received stuff like "Domain=www.example.com.".
|
|
||||||
// Browsers do handle such stuff (actually differently) but
|
|
||||||
// RFC 6265 seems to be clear here (e.g. section 4.1.2.3) in
|
|
||||||
// requiring a reject. 4.1.2.3 is not normative, but
|
|
||||||
// "Domain Matching" (5.1.3) and "Canonicalized Host Names"
|
|
||||||
// (5.1.2) are.
|
|
||||||
return "", false, errMalformedDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 6265 section 5.3 #5.
|
|
||||||
if j.psList != nil {
|
|
||||||
if ps := j.psList.PublicSuffix(domain); ps != "" && !hasDotSuffix(domain, ps) {
|
|
||||||
if host == domain {
|
|
||||||
// This is the one exception in which a cookie
|
|
||||||
// with a domain attribute is a host cookie.
|
|
||||||
return host, true, nil
|
|
||||||
}
|
|
||||||
return "", false, errIllegalDomain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The domain must domain-match host: www.mycompany.com cannot
|
|
||||||
// set cookies for .ourcompetitors.com.
|
|
||||||
if host != domain && !hasDotSuffix(host, domain) {
|
|
||||||
return "", false, errIllegalDomain
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain, false, nil
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cookiejar
|
|
||||||
|
|
||||||
// This file implements the Punycode algorithm from RFC 3492.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These parameter values are specified in section 5.
|
|
||||||
//
|
|
||||||
// All computation is done with int32s, so that overflow behavior is identical
|
|
||||||
// regardless of whether int is 32-bit or 64-bit.
|
|
||||||
const (
|
|
||||||
base int32 = 36
|
|
||||||
damp int32 = 700
|
|
||||||
initialBias int32 = 72
|
|
||||||
initialN int32 = 128
|
|
||||||
skew int32 = 38
|
|
||||||
tmax int32 = 26
|
|
||||||
tmin int32 = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// encode encodes a string as specified in section 6.3 and prepends prefix to
|
|
||||||
// the result.
|
|
||||||
//
|
|
||||||
// The "while h < length(input)" line in the specification becomes "for
|
|
||||||
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
|
|
||||||
func encode(prefix, s string) (string, error) {
|
|
||||||
output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
|
|
||||||
copy(output, prefix)
|
|
||||||
delta, n, bias := int32(0), initialN, initialBias
|
|
||||||
b, remaining := int32(0), int32(0)
|
|
||||||
for _, r := range s {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
b++
|
|
||||||
output = append(output, byte(r))
|
|
||||||
} else {
|
|
||||||
remaining++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h := b
|
|
||||||
if b > 0 {
|
|
||||||
output = append(output, '-')
|
|
||||||
}
|
|
||||||
for remaining != 0 {
|
|
||||||
m := int32(0x7fffffff)
|
|
||||||
for _, r := range s {
|
|
||||||
if m > r && r >= n {
|
|
||||||
m = r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delta += (m - n) * (h + 1)
|
|
||||||
if delta < 0 {
|
|
||||||
return "", fmt.Errorf("cookiejar: invalid label %q", s)
|
|
||||||
}
|
|
||||||
n = m
|
|
||||||
for _, r := range s {
|
|
||||||
if r < n {
|
|
||||||
delta++
|
|
||||||
if delta < 0 {
|
|
||||||
return "", fmt.Errorf("cookiejar: invalid label %q", s)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r > n {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
q := delta
|
|
||||||
for k := base; ; k += base {
|
|
||||||
t := k - bias
|
|
||||||
if t < tmin {
|
|
||||||
t = tmin
|
|
||||||
} else if t > tmax {
|
|
||||||
t = tmax
|
|
||||||
}
|
|
||||||
if q < t {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
output = append(output, encodeDigit(t+(q-t)%(base-t)))
|
|
||||||
q = (q - t) / (base - t)
|
|
||||||
}
|
|
||||||
output = append(output, encodeDigit(q))
|
|
||||||
bias = adapt(delta, h+1, h == b)
|
|
||||||
delta = 0
|
|
||||||
h++
|
|
||||||
remaining--
|
|
||||||
}
|
|
||||||
delta++
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
return string(output), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeDigit(digit int32) byte {
|
|
||||||
switch {
|
|
||||||
case 0 <= digit && digit < 26:
|
|
||||||
return byte(digit + 'a')
|
|
||||||
case 26 <= digit && digit < 36:
|
|
||||||
return byte(digit + ('0' - 26))
|
|
||||||
}
|
|
||||||
panic("cookiejar: internal error in punycode encoding")
|
|
||||||
}
|
|
||||||
|
|
||||||
// adapt is the bias adaptation function specified in section 6.1.
|
|
||||||
func adapt(delta, numPoints int32, firstTime bool) int32 {
|
|
||||||
if firstTime {
|
|
||||||
delta /= damp
|
|
||||||
} else {
|
|
||||||
delta /= 2
|
|
||||||
}
|
|
||||||
delta += delta / numPoints
|
|
||||||
k := int32(0)
|
|
||||||
for delta > ((base-tmin)*tmax)/2 {
|
|
||||||
delta /= base - tmin
|
|
||||||
k += base
|
|
||||||
}
|
|
||||||
return k + (base-tmin+1)*delta/(delta+skew)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strictly speaking, the remaining code below deals with IDNA (RFC 5890 and
|
|
||||||
// friends) and not Punycode (RFC 3492) per se.
|
|
||||||
|
|
||||||
// acePrefix is the ASCII Compatible Encoding prefix.
|
|
||||||
const acePrefix = "xn--"
|
|
||||||
|
|
||||||
// toASCII converts a domain or domain label to its ASCII form. For example,
|
|
||||||
// toASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
|
|
||||||
// toASCII("golang") is "golang".
|
|
||||||
func toASCII(s string) (string, error) {
|
|
||||||
if ascii(s) {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
labels := strings.Split(s, ".")
|
|
||||||
for i, label := range labels {
|
|
||||||
if !ascii(label) {
|
|
||||||
a, err := encode(acePrefix, label)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
labels[i] = a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(labels, "."), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ascii(s string) bool {
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if s[i] >= utf8.RuneSelf {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
type DeviceDriver interface {
|
|
||||||
ListenAndServe(addr string, handler Handler) error
|
|
||||||
}
|
|
||||||
|
|
||||||
var ActiveDevice DeviceDriver
|
|
||||||
|
|
||||||
func UseDriver(driver DeviceDriver) {
|
|
||||||
// TODO: rethink and refactor this
|
|
||||||
if ActiveDevice != nil {
|
|
||||||
panic("net.ActiveDevice is already set")
|
|
||||||
}
|
|
||||||
ActiveDevice = driver
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user