mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-27 11:08:41 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 71eef4196f | |||
| 6301627338 | |||
| b7bbecc456 | |||
| 30f540c29f | |||
| 6d431e0726 | |||
| f308f8fce0 | |||
| 1c2b802f47 | |||
| ce80e7582f | |||
| 109cab4f3b | |||
| 07216d3051 | |||
| d688fa3f3f | |||
| dd44f9220b | |||
| ee3842f639 | |||
| 1bf1a11067 | |||
| 848f5def03 | |||
| 4a0bcba87c | |||
| 7d983647ad | |||
| 831982ad33 | |||
| 9063f46313 | |||
| 2a621dc3b1 | |||
| 7dbca2a543 | |||
| 50b6f18cc2 | |||
| bb0e6b8ba8 | |||
| 5eeba138a4 | |||
| 1095629f62 | |||
| bf0b383176 | |||
| f206f6f56f | |||
| a0293643b3 | |||
| 60801ba852 | |||
| a74770b2e6 | |||
| 3ed09d3fe1 | |||
| 22581dfd58 | |||
| 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 |
@@ -0,0 +1,2 @@
|
||||
# These are supported funding model platforms
|
||||
open_collective: tinygo
|
||||
+125
@@ -1,3 +1,128 @@
|
||||
0.28.0
|
||||
---
|
||||
- **new devices**
|
||||
- **epd2in66b**
|
||||
- Waveshare 2.66inch E-Paper Display Module (B) for Raspberry Pi Pico (#673)
|
||||
- **mcp9808**
|
||||
- Add driver for MCP9808 i2c temperature sensor (#676)
|
||||
|
||||
- **enhancements**
|
||||
- **encoders**
|
||||
- add atsamd21, atsamd51, atsame5x
|
||||
- **pixel**
|
||||
- add support for Monochrome types such as the SSD1306 display
|
||||
- **rtl8720dn**
|
||||
- implement ConnectModeAP
|
||||
- **servo**
|
||||
- add function SetAngle() to simplify API for most common use case
|
||||
- **ssd1306**
|
||||
- add DrawBitmap() function to complete Displayer interface
|
||||
- add rotation functions for Displayer interface
|
||||
- add Sleep() function for Displayer interface
|
||||
- **uc8151**
|
||||
- improvements to speed and also add flicker-free mode based on @antirez code example
|
||||
- update to support all functions needed by tinygl and board package Displayer interface
|
||||
- **wifinina**
|
||||
- implement ConnectModeAP
|
||||
|
||||
- **bugfixes**
|
||||
- **ft6336**
|
||||
- ignore bogus touch events
|
||||
- **pixel**
|
||||
- fix Image[Monochrome].Set for larger images
|
||||
- **uc8151**
|
||||
- correct DrawBitmap() also refactor SendCommand() and SendData() for clarity
|
||||
- **ws2812**
|
||||
- Fix typo and move initialization of neo to init()
|
||||
|
||||
- **examples**
|
||||
- **ws2812**
|
||||
- Simplify examples/ws2812
|
||||
|
||||
|
||||
0.27.0
|
||||
---
|
||||
- **core**
|
||||
- prepare for CGo changes in TinyGo
|
||||
|
||||
- **new devices**
|
||||
- **adafruit4650**
|
||||
- support for Adafruit 4650 feather OLED
|
||||
- **net**
|
||||
- new networking support based on tinygo net package
|
||||
- **pixel**
|
||||
- add package for efficiently working with raw pixel buffers
|
||||
- **rotary**
|
||||
- Adding driver for rotary encoder support
|
||||
- **seesaw**
|
||||
- Adding support for Adafruit Seesaw platform
|
||||
- **sgp30**
|
||||
- add SGP30 air quality sensor
|
||||
- **sk6812**
|
||||
- added support for SK6812 to WS2812 device (#610)
|
||||
|
||||
- **enhancements**
|
||||
- **epd2in13**
|
||||
- add Sleep method like other displays
|
||||
- unify rotation configuration with other displays
|
||||
- use better black/white approximation
|
||||
- **ili9341**
|
||||
- add DrawBitmap method
|
||||
- **lora/lorawan**
|
||||
- LoRa WAN US915 Support
|
||||
- LoRa WAN add setter functions
|
||||
- refactor shared functionality for channels/regions
|
||||
- **mcp2515**
|
||||
- Add more line speeds to mcp2515.go (#626)
|
||||
- **rtl8720dn**
|
||||
- use drivers package version as the driver version
|
||||
- **ssd1306**
|
||||
- improvements needed for Thumby SPI display
|
||||
- **st7735**
|
||||
- make the display generic over RGB565 and RGB444
|
||||
- **st7789**
|
||||
- add DrawBitmap method
|
||||
- make the display generic over RGB565 and RGB444
|
||||
- **wifinina**
|
||||
- add ResetIsHigh cfg switch for MKR 1010 (copied from #561)
|
||||
- maintenence. Also see PR #4085 in the main TinyGo repo
|
||||
- use drivers package version as the driver version
|
||||
|
||||
- **bugfixes**
|
||||
- **adxl345**
|
||||
- Use int16 for ADXL345 readings (#656)
|
||||
- **at24cx**
|
||||
- fixed the description of the device struct
|
||||
- **rtl8720dn**
|
||||
- allow connecting to open wifi access points
|
||||
- fix check for bad Wifi connect
|
||||
- **sh1106**
|
||||
- fix I2C interface and add smoketest
|
||||
- fixed the description of the device struct
|
||||
- **wifinina**
|
||||
- add 'unknown failure' reason code for AP connect
|
||||
- fix concurrency issues with multiple sockets
|
||||
- fix wifinina UDP send
|
||||
|
||||
- **examples**
|
||||
- **ds3231**
|
||||
- fix the description in the example
|
||||
- **lorawan**
|
||||
- add missing functions for simulated interface
|
||||
- modify atcmd and basic demo to support choosing any one of the supported regions at compile time by using ldflags
|
||||
- **net**
|
||||
- all networking examples now using netdev and netlink.
|
||||
|
||||
- **build**
|
||||
- **all**
|
||||
- fix broken testrunner
|
||||
- migrated legacy I2C
|
||||
- add natiu package for tests
|
||||
- **smoketest**
|
||||
- add stack-size param for net tests.
|
||||
- allow stack-size flag as it is needed for net examples
|
||||
|
||||
|
||||
0.26.0
|
||||
---
|
||||
- **core**
|
||||
|
||||
@@ -1,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
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
||||
@@ -19,7 +19,7 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst
|
||||
# Recursively find all *_test.go files from cwd & reduce to unique dir names
|
||||
HAS_TESTS = $(sort $(dir $(call rwildcard,,*_test.go)))
|
||||
# Exclude anything we explicitly don't want to test for whatever reason
|
||||
EXCLUDE_TESTS = image
|
||||
EXCLUDE_TESTS = image waveshare-epd/epd2in66b
|
||||
TESTS = $(filter-out $(addsuffix /%,$(EXCLUDE_TESTS)),$(HAS_TESTS))
|
||||
|
||||
unit-test:
|
||||
|
||||
+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,7 @@
|
||||
[](https://pkg.go.dev/tinygo.org/x/drivers) [](https://github.com/tinygo-org/drivers/actions/workflows/build.yml)
|
||||
|
||||
|
||||
This package provides a collection of 101 different hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
|
||||
This package provides a collection of over 100 different hardware drivers for devices such as sensors, displays, wireless adaptors, and actuators, that can be used together with [TinyGo](https://tinygo.org).
|
||||
|
||||
For the complete list, please see:
|
||||
https://tinygo.org/docs/reference/devices/
|
||||
@@ -16,7 +16,7 @@ go get tinygo.org/x/drivers
|
||||
|
||||
## How to use
|
||||
|
||||
Here is an example in TinyGo that uses the BMP180 digital barometer:
|
||||
Here is an example in TinyGo that uses the BMP180 digital barometer. This example should work on any board that supports I2C:
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -53,6 +53,28 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Examples Using GPIO or SPI
|
||||
|
||||
If compiling these examples directly you are likely to need to make minor changes to the defined variables to map the pins for the board you are using. For example, this block in main.go:
|
||||
|
||||
```golang
|
||||
var (
|
||||
spi = machine.SPI0
|
||||
csPin = machine.D5
|
||||
)
|
||||
```
|
||||
|
||||
It might not be obvious, but you need to change these to match how you wired your specific board. Constants are [defined for each supported microcontroller](https://tinygo.org/docs/reference/microcontrollers/).
|
||||
|
||||
For example, to change the definitions for use on a Raspberry Pi Pico using typical wiring, you might need to do this:
|
||||
|
||||
```golang
|
||||
var (
|
||||
spi = machine.SPI0
|
||||
csPin = machine.GP17
|
||||
)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Your contributions are welcome!
|
||||
|
||||
+7
-7
@@ -95,16 +95,16 @@ func (d *Device) Restart() {
|
||||
func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
|
||||
rx, ry, rz := d.ReadRawAcceleration()
|
||||
|
||||
x = d.dataFormat.convertToIS(rx)
|
||||
y = d.dataFormat.convertToIS(ry)
|
||||
z = d.dataFormat.convertToIS(rz)
|
||||
x = int32(d.dataFormat.convertToIS(rx))
|
||||
y = int32(d.dataFormat.convertToIS(ry))
|
||||
z = int32(d.dataFormat.convertToIS(rz))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis
|
||||
// from the adxl345.
|
||||
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
|
||||
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
|
||||
data := []byte{0, 0, 0, 0, 0, 0}
|
||||
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data)
|
||||
|
||||
@@ -140,7 +140,7 @@ func (d *Device) SetRange(sensorRange Range) bool {
|
||||
}
|
||||
|
||||
// convertToIS adjusts the raw values from the adxl345 with the range configuration
|
||||
func (d *dataFormat) convertToIS(rawValue int32) int32 {
|
||||
func (d *dataFormat) convertToIS(rawValue int16) int16 {
|
||||
switch d.sensorRange {
|
||||
case RANGE_2G:
|
||||
return rawValue * 4 // rawValue * 2 * 1000 / 512
|
||||
@@ -190,6 +190,6 @@ func (b *bwRate) toByte() (bits uint8) {
|
||||
}
|
||||
|
||||
// readInt converts two bytes to int16
|
||||
func readIntLE(msb byte, lsb byte) int32 {
|
||||
return int32(uint16(msb) | uint16(lsb)<<8)
|
||||
func readIntLE(msb byte, lsb byte) int16 {
|
||||
return int16(uint16(msb) | uint16(lsb)<<8)
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ type OneWireDevice interface {
|
||||
Write(uint8)
|
||||
Read() uint8
|
||||
Select([]uint8) error
|
||||
Сrc8([]uint8, int) uint8
|
||||
Сrc8([]uint8) uint8
|
||||
}
|
||||
|
||||
// Device wraps a connection to an 1-Wire devices.
|
||||
@@ -69,7 +69,7 @@ func (d Device) ReadTemperatureRaw(romid []uint8) ([]uint8, error) {
|
||||
for i := 0; i < 9; i++ {
|
||||
spb[i] = d.owd.Read()
|
||||
}
|
||||
if d.owd.Сrc8(spb, 8) != spb[8] {
|
||||
if d.owd.Сrc8(spb) != 0 {
|
||||
return nil, errReadTemperature
|
||||
}
|
||||
return spb[:2:2], nil
|
||||
|
||||
@@ -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 || sam || (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()
|
||||
}
|
||||
+296
-34
@@ -15,41 +15,302 @@
|
||||
//
|
||||
// AT command set:
|
||||
// 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"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"machine"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/netdev"
|
||||
"tinygo.org/x/drivers/netlink"
|
||||
)
|
||||
|
||||
// Device wraps UART connection to the ESP8266/ESP32.
|
||||
type Device struct {
|
||||
bus drivers.UART
|
||||
type Config struct {
|
||||
// UART config
|
||||
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
|
||||
response []byte
|
||||
|
||||
// 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.
|
||||
var ActiveDevice *Device
|
||||
|
||||
// New returns a new espat driver. Pass in a fully configured UART bus.
|
||||
func New(b drivers.UART) *Device {
|
||||
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
|
||||
func NewDevice(cfg *Config) *Device {
|
||||
return &Device{
|
||||
cfg: cfg,
|
||||
response: make([]byte, 1500),
|
||||
data: make([]byte, 0, 1500),
|
||||
}
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication.
|
||||
func (d Device) Configure() {
|
||||
ActiveDevice = &d
|
||||
net.ActiveDevice = ActiveDevice
|
||||
func (d *Device) NetConnect(params *netlink.ConnectParams) error {
|
||||
|
||||
if len(params.Ssid) == 0 {
|
||||
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)) {
|
||||
fmt.Printf("\r\n%s\r\n", netlink.ErrNotSupported)
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -57,7 +318,7 @@ func (d *Device) Connected() bool {
|
||||
d.Execute(Test)
|
||||
|
||||
// handle response here, should include "OK"
|
||||
_, err := d.Response(100)
|
||||
_, err := d.Response(1000)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -66,12 +327,12 @@ func (d *Device) Connected() bool {
|
||||
|
||||
// Write raw bytes to the UART.
|
||||
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.
|
||||
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
|
||||
@@ -100,9 +361,10 @@ func (d Device) Set(cmd, params string) error {
|
||||
// Version returns the ESP8266/ESP32 firmware version info.
|
||||
func (d Device) Version() []byte {
|
||||
d.Execute(Version)
|
||||
r, err := d.Response(100)
|
||||
r, err := d.Response(2000)
|
||||
if err != nil {
|
||||
return []byte("unknown")
|
||||
//return []byte("unknown")
|
||||
return []byte(err.Error())
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -132,16 +394,16 @@ func (d *Device) ReadSocket(b []byte) (n int, err error) {
|
||||
d.Response(300)
|
||||
|
||||
count := len(b)
|
||||
if len(b) >= len(d.socketdata) {
|
||||
if len(b) >= len(d.data) {
|
||||
// copy it all, then clear socket data
|
||||
count = len(d.socketdata)
|
||||
copy(b, d.socketdata[:count])
|
||||
d.socketdata = d.socketdata[:0]
|
||||
count = len(d.data)
|
||||
copy(b, d.data[:count])
|
||||
d.data = d.data[:0]
|
||||
} else {
|
||||
// copy all we can, then keep the remaining socket data around
|
||||
copy(b, d.socketdata[:count])
|
||||
copy(d.socketdata, d.socketdata[count:])
|
||||
d.socketdata = d.socketdata[:len(d.socketdata)-count]
|
||||
copy(b, d.data[:count])
|
||||
copy(d.data, d.data[count:])
|
||||
d.data = d.data[:len(d.data)-count]
|
||||
}
|
||||
|
||||
return count, nil
|
||||
@@ -157,11 +419,11 @@ func (d *Device) Response(timeout int) ([]byte, error) {
|
||||
retries := timeout / pause
|
||||
|
||||
for {
|
||||
size = d.bus.Buffered()
|
||||
size = d.uart.Buffered()
|
||||
|
||||
if size > 0 {
|
||||
end += size
|
||||
d.bus.Read(d.response[start:end])
|
||||
d.uart.Read(d.response[start:end])
|
||||
|
||||
// if "+IPD" then read socket data
|
||||
if strings.Contains(string(d.response[:end]), "+IPD") {
|
||||
@@ -204,18 +466,18 @@ func (d *Device) parseIPD(end int) error {
|
||||
val := string(d.response[s+5 : e])
|
||||
|
||||
// TODO: verify count
|
||||
_, err := strconv.Atoi(val)
|
||||
v, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
// not expected data here. what to do?
|
||||
return err
|
||||
}
|
||||
|
||||
// load up the socket data
|
||||
d.socketdata = append(d.socketdata, d.response[e+1:end]...)
|
||||
d.data = append(d.data, d.response[e+1:e+1+v]...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsSocketDataAvailable returns of there is socket data available
|
||||
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.
|
||||
func (d *Device) ConnectUDPSocket(addr, sendport, listenport string) error {
|
||||
protocol := "UDP"
|
||||
val := "\"" + protocol + "\",\"" + addr + "\"," + sendport + "," + listenport + ",2"
|
||||
val := "\"" + protocol + "\",\"" + addr + "\"," + sendport + "," + listenport + ",0"
|
||||
err := d.Set(TCPConnect, val)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-4
@@ -44,10 +44,7 @@ func (d *Device) ConnectToAP(ssid, pwd string, ws int) error {
|
||||
d.Set(ConnectAP, val)
|
||||
|
||||
_, err := d.Response(ws * 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// DisconnectFromAP disconnects the ESP8266/ESP32 from the current access point.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/ina219"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
dev := ina219.New(machine.I2C0)
|
||||
dev.Configure()
|
||||
|
||||
for {
|
||||
busVoltage, shuntVoltage, current, power, err := dev.Measurements()
|
||||
if err != nil {
|
||||
println("Error reading measurements", err)
|
||||
}
|
||||
|
||||
println("Bus Voltage:", busVoltage, "V")
|
||||
println("Shunt Voltage:", shuntVoltage/100, "mV")
|
||||
println("Current:", current, "mA")
|
||||
println("Power:", power, "mW")
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/mcp9808"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//tinygo monitor
|
||||
time.Sleep(time.Millisecond * 5000)
|
||||
|
||||
//Configure I2C (in this case, I2C0 on RPI Pico), and wire the module accordingly
|
||||
machine.I2C0.Configure(machine.I2CConfig{
|
||||
SCL: machine.GP1,
|
||||
SDA: machine.GP0,
|
||||
})
|
||||
|
||||
//Create sensor
|
||||
sensor := mcp9808.New(machine.I2C0)
|
||||
if !sensor.Connected() {
|
||||
println("MCP9808 not found")
|
||||
return
|
||||
} else {
|
||||
println("MCP9808 found")
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
|
||||
//Set resolution
|
||||
sensor.SetResolution(mcp9808.Maximum)
|
||||
|
||||
time.Sleep(time.Millisecond * 1000)
|
||||
|
||||
//Read temp.
|
||||
temp, err := sensor.ReadTemperature()
|
||||
if err != nil {
|
||||
println("MCP9808 error reading temperature")
|
||||
println(err.Error())
|
||||
return
|
||||
} else {
|
||||
fmt.Printf("Temperature: %.2f \n", temp)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -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,
|
||||
// for the purpose of testing speed and connectivity.
|
||||
// This example opens a TCP connection 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
|
||||
// nc -lk 8080
|
||||
|
||||
//go:build ninafw || wioterminal || challenger_rp2040 || pico
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"machine"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/netlink"
|
||||
"tinygo.org/x/drivers/netlink/probe"
|
||||
)
|
||||
|
||||
var (
|
||||
// access point info
|
||||
ssid 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{}
|
||||
|
||||
func main() {
|
||||
initAdaptor()
|
||||
|
||||
connectToAP()
|
||||
waitSerial()
|
||||
|
||||
link, _ := probe.Probe()
|
||||
|
||||
err := link.NetConnect(&netlink.ConnectParams{
|
||||
Ssid: ssid,
|
||||
Passphrase: pass,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
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) {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
for ; err != nil; conn, err = net.Dial("tcp", addr) {
|
||||
message(err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
@@ -65,7 +73,7 @@ func sendBatch() {
|
||||
"\r---------------------------- i == ", i, " ----------------------------")
|
||||
if w, err = conn.Write(buf.Bytes()); err != nil {
|
||||
println("error:", err.Error(), "\r")
|
||||
continue
|
||||
break
|
||||
}
|
||||
n += w
|
||||
}
|
||||
@@ -79,34 +87,17 @@ func sendBatch() {
|
||||
println("error:", err.Error(), "\r")
|
||||
}
|
||||
|
||||
// Right now this code is never reached. Need a way to trigger it...
|
||||
println("Disconnecting TCP...")
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
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) {
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"machine"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net/http"
|
||||
"tinygo.org/x/drivers/rtl8720dn"
|
||||
"tinygo.org/x/drivers/netlink"
|
||||
"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 (
|
||||
ssid string
|
||||
pass string
|
||||
debug = false
|
||||
ssid string
|
||||
pass string
|
||||
port string = ":80"
|
||||
)
|
||||
|
||||
var led = machine.LED
|
||||
var backlight = machine.LCD_BACKLIGHT
|
||||
|
||||
func main() {
|
||||
|
||||
// wait a bit for serial
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
backlight.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
err := run()
|
||||
for err != nil {
|
||||
fmt.Printf("error: %s\r\n", err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
link, _ := probe.Probe()
|
||||
|
||||
func run() error {
|
||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
||||
adaptor.Debug(debug)
|
||||
adaptor.Configure()
|
||||
|
||||
http.UseDriver(adaptor)
|
||||
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
err := link.NetConnect(&netlink.ConnectParams{
|
||||
Ssid: ssid,
|
||||
Passphrase: pass,
|
||||
})
|
||||
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("/hello", hello)
|
||||
http.HandleFunc("/cnt", cnt)
|
||||
http.HandleFunc("/6", sixlines)
|
||||
http.HandleFunc("/off", LED_OFF)
|
||||
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) {
|
||||
@@ -101,8 +93,8 @@ func root(w http.ResponseWriter, r *http.Request) {
|
||||
<title>TinyGo HTTP Server</title>
|
||||
<script language="javascript" type="text/javascript">
|
||||
var counter = 0
|
||||
function ledOn() { fetch("/on").then(response => response.text()).then(text => { led.innerHTML = "<p>on</p>"; }); }
|
||||
function ledOff() { fetch("/off").then(response => response.text()).then(text => { led.innerHTML = "<p>off</p>"; }); }
|
||||
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", {
|
||||
@@ -141,7 +133,7 @@ func root(w http.ResponseWriter, r *http.Request) {
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
`, access)
|
||||
`, access)
|
||||
}
|
||||
|
||||
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) {
|
||||
led.High()
|
||||
backlight.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()
|
||||
backlight.Low()
|
||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||
fmt.Fprintf(w, "led.Low()")
|
||||
}
|
||||
@@ -187,7 +177,3 @@ func cnt(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(`Content-Type`, `application/json`)
|
||||
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,28 @@
|
||||
// Connects to a pcf8591 ADC via I2C.
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8591"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{})
|
||||
adc := pcf8591.New(i2c)
|
||||
adc.Configure()
|
||||
|
||||
// get "CH0" aka "machine.ADC" interface to channel 0 from ADC.
|
||||
p := adc.CH0
|
||||
|
||||
for {
|
||||
val := p.Get()
|
||||
println(val)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -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)))
|
||||
}
|
||||
+19
-13
@@ -25,19 +25,25 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
println("setting to 0°")
|
||||
s.SetMicroseconds(1000)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 45°")
|
||||
s.SetMicroseconds(1500)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 90°")
|
||||
s.SetMicroseconds(2000)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
println("setting to 0°")
|
||||
s.SetAngle(0)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 45°")
|
||||
s.SetAngle(45)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 90°")
|
||||
s.SetAngle(90)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 135°")
|
||||
s.SetAngle(135)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
println("setting to 180°")
|
||||
s.SetAngle(180)
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Capacitive touch sensing example.
|
||||
//
|
||||
// This capacitive touch sensor works by charging a normal GPIO pin, then slowly
|
||||
// discharging it through a 1MΩ resistor and seeing how long it takes to go from
|
||||
// high to low.
|
||||
//
|
||||
// Use as follows:
|
||||
// - Change touchPin below as needed.
|
||||
// - Connect this pin to some metal surface, like a piece of aluminimum foil.
|
||||
// Make sure this surface is covered (using paper, Scotch tape, etc).
|
||||
// - Also connect this same pin to ground through a 1MΩ resistor.
|
||||
//
|
||||
// This sensor is very sensitive to noise on the power source, so you should
|
||||
// probably try to limit it by running from a battery for example. Especially
|
||||
// phone chargers can produce a lot of noise.
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/touch/capacitive"
|
||||
)
|
||||
|
||||
const touchPin = machine.GP16 // Raspberry Pi Pico
|
||||
|
||||
func main() {
|
||||
time.Sleep(time.Second * 2)
|
||||
println("start")
|
||||
|
||||
led := machine.LED
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
led.Low()
|
||||
|
||||
// Configure the array of GPIO pins used for capacitive touch sensing.
|
||||
// We're using only one pin.
|
||||
array := capacitive.NewArray([]machine.Pin{touchPin})
|
||||
|
||||
// Use a dynamic threshold, meaning the GPIO pin is automatically calibrated
|
||||
// and re-calibrated to adjust for varying environments (e.g. changing
|
||||
// humidity).
|
||||
array.SetDynamicThreshold(100)
|
||||
|
||||
wasTouching := false
|
||||
for i := uint32(0); ; i++ {
|
||||
// Update the GPIO pin. This must be called very often.
|
||||
array.Update()
|
||||
touching := array.Touching(0)
|
||||
|
||||
// Indicate whether the pin is touched via the LED.
|
||||
led.Set(touching)
|
||||
|
||||
// Print something when the touch state changed.
|
||||
if wasTouching != touching {
|
||||
wasTouching = touching
|
||||
if touching {
|
||||
println(" touch!")
|
||||
} else {
|
||||
println(" release!")
|
||||
}
|
||||
}
|
||||
|
||||
// Print the current value, as a debugging aid. It's not really meant to
|
||||
// be used directly.
|
||||
if i%128 == 32 {
|
||||
println("touch value:", array.RawValue(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
-12
@@ -3,7 +3,9 @@ package main
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/uc8151"
|
||||
)
|
||||
|
||||
@@ -14,30 +16,56 @@ func main() {
|
||||
led = machine.LED
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
Frequency: 12000000,
|
||||
Frequency: 12 * machine.MHz,
|
||||
SCK: machine.EPD_SCK_PIN,
|
||||
SDO: machine.EPD_SDO_PIN,
|
||||
})
|
||||
|
||||
display = uc8151.New(machine.SPI0, machine.EPD_CS_PIN, machine.EPD_DC_PIN, machine.EPD_RESET_PIN, machine.EPD_BUSY_PIN)
|
||||
display.Configure(uc8151.Config{
|
||||
Rotation: uc8151.ROTATION_270,
|
||||
Speed: uc8151.MEDIUM,
|
||||
Blocking: true,
|
||||
Rotation: drivers.Rotation270,
|
||||
Speed: uc8151.TURBO,
|
||||
FlickerFree: true,
|
||||
Blocking: false,
|
||||
})
|
||||
black := color.RGBA{1, 1, 1, 255}
|
||||
|
||||
display.ClearBuffer()
|
||||
display.Display()
|
||||
for i := int16(0); i < 37; i++ {
|
||||
for j := int16(0); j < 16; j++ {
|
||||
if (i+j)%2 == 0 {
|
||||
showRect(i*8, j*8, 8, 8, black)
|
||||
display.ClearDisplay()
|
||||
|
||||
mod := int16(1)
|
||||
for {
|
||||
// checkerboard
|
||||
for i := int16(0); i < 11; i++ {
|
||||
if mod == 1 {
|
||||
mod = 0
|
||||
} else {
|
||||
mod = 1
|
||||
}
|
||||
|
||||
display.ClearBuffer()
|
||||
for i := int16(0); i < 37; i++ {
|
||||
for j := int16(0); j < 16; j++ {
|
||||
if (i+j)%2 == mod {
|
||||
showRect(i*8, j*8, 8, 8, black)
|
||||
}
|
||||
}
|
||||
}
|
||||
display.Display()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
// moving line
|
||||
for i := int16(16); i < 21; i++ {
|
||||
display.ClearBuffer()
|
||||
for j := int16(0); j < 16; j++ {
|
||||
if (i+j)%2 == 0 {
|
||||
showRect(i*8, j*8, 8, 8, black)
|
||||
}
|
||||
display.Display()
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
display.Display()
|
||||
}
|
||||
|
||||
func showRect(x int16, y int16, w int16, h int16, c color.RGBA) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/waveshare-epd/epd1in54"
|
||||
"tinygo.org/x/tinyfont"
|
||||
"tinygo.org/x/tinyfont/gophers"
|
||||
)
|
||||
|
||||
var (
|
||||
spi0 = machine.SPI0
|
||||
cs = machine.D10
|
||||
dc = machine.D9
|
||||
rst = machine.D6
|
||||
busy = machine.D5
|
||||
|
||||
black = color.RGBA{R: 1, G: 1, B: 1, A: 255}
|
||||
)
|
||||
|
||||
func main() {
|
||||
display := epd1in54.New(spi0, cs, dc, rst, busy)
|
||||
|
||||
display.LDirInit(epd1in54.Config{})
|
||||
display.Clear()
|
||||
display.ClearBuffer()
|
||||
|
||||
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 150, 0, "A B C", black, tinyfont.ROTATION_90)
|
||||
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 100, 0, "D E F", black, tinyfont.ROTATION_90)
|
||||
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 50, 0, "G H I", black, tinyfont.ROTATION_90)
|
||||
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 0, 0, "J K L", black, tinyfont.ROTATION_90)
|
||||
|
||||
display.Display()
|
||||
display.Sleep()
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/waveshare-epd/epd2in66b"
|
||||
"tinygo.org/x/tinyfont"
|
||||
"tinygo.org/x/tinyfont/freemono"
|
||||
)
|
||||
|
||||
var (
|
||||
black = color.RGBA{0, 0, 0, 0xff}
|
||||
white = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||
red = color.RGBA{0xff, 0, 0, 0xff}
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
machine.SPI1.Configure(machine.SPIConfig{
|
||||
Frequency: epd2in66b.Baudrate,
|
||||
})
|
||||
|
||||
println("started")
|
||||
|
||||
// in case you have a Pico module, you can directly use
|
||||
// dev, err := epd2in66b.NewPicoModule()
|
||||
|
||||
display := epd2in66b.New(machine.SPI1)
|
||||
|
||||
cfg := epd2in66b.Config{
|
||||
DataPin: machine.GP8,
|
||||
ChipSelectPin: machine.GP9,
|
||||
ResetPin: machine.GP12,
|
||||
BusyPin: machine.GP13,
|
||||
}
|
||||
err := display.Configure(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = display.Reset()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
println("draw checkerboard")
|
||||
drawCheckerBoard(&display)
|
||||
|
||||
println("draw 'hello'")
|
||||
tinyfont.WriteLineRotated(&display, &freemono.Bold24pt7b, 40, 10, "Hello!", white, tinyfont.ROTATION_90)
|
||||
tinyfont.WriteLineRotated(&display, &freemono.Bold12pt7b, 10, 10, "tinygo rocks", white, tinyfont.ROTATION_90)
|
||||
err = display.Display()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func drawCheckerBoard(display drivers.Displayer) {
|
||||
s := 8
|
||||
width, height := display.Size()
|
||||
for x := 0; x <= int(width)-s; x += s {
|
||||
for y := 0; y <= int(height)-s; y += s {
|
||||
c := red
|
||||
if (x/s)%2 == (y/s)%2 {
|
||||
c = black
|
||||
}
|
||||
|
||||
showRect(display, x, y, s, s, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showRect(display drivers.Displayer, x int, y int, w int, h int, c color.RGBA) {
|
||||
for i := x; i < x+w; i++ {
|
||||
for j := y; j < y+h; j++ {
|
||||
display.SetPixel(int16(i), int16(j), c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo = machine.D2
|
||||
var led = machine.LED
|
||||
func init() {
|
||||
// Replace neo in the code below to match the pin
|
||||
// that you are using if different.
|
||||
neo = machine.D2
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// This is the pin assignment for the Digispark only.
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = 0
|
||||
var led = machine.LED
|
||||
func init() {
|
||||
// This is the pin assignment for the Digispark only.
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
neo = machine.Pin(0)
|
||||
}
|
||||
|
||||
@@ -12,14 +12,15 @@ import (
|
||||
"tinygo.org/x/drivers/ws2812"
|
||||
)
|
||||
|
||||
var leds [10]color.RGBA
|
||||
var (
|
||||
neo machine.Pin
|
||||
leds [10]color.RGBA
|
||||
)
|
||||
|
||||
func main() {
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
ws := ws2812.New(neo)
|
||||
ws := ws2812.NewWS2812(neo)
|
||||
rg := false
|
||||
|
||||
for {
|
||||
@@ -35,7 +36,6 @@ func main() {
|
||||
}
|
||||
|
||||
ws.WriteColors(leds[:])
|
||||
led.Set(rg)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3 && !thingplus_rp2040
|
||||
//go:build !digispark && !arduino
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = machine.WS2812
|
||||
var led = machine.LED
|
||||
func init() {
|
||||
// Replace neo in the code below to match the pin
|
||||
// that you are using if different.
|
||||
neo = machine.WS2812
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//go:build qtpy || m5stamp_c3
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = machine.WS2812
|
||||
var led = machine.NoPin
|
||||
@@ -1,12 +0,0 @@
|
||||
//go:build thingplus_rp2040
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
// This is the pin assignment for the internal neopixel of the
|
||||
// Sparkfun thingplus rp2040.
|
||||
// Replace neo and led in the code below to match the pin
|
||||
// that you are using if different.
|
||||
var neo machine.Pin = machine.GPIO8
|
||||
var led = machine.LED
|
||||
+2
-1
@@ -80,7 +80,8 @@ func (d *Device) Read() []byte {
|
||||
func (d *Device) ReadTouchPoint() touch.Point {
|
||||
d.Read()
|
||||
z := 0xFFFFF
|
||||
if d.buf[0] == 0 {
|
||||
switch d.buf[0] {
|
||||
case 0, 255:
|
||||
z = 0
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// Package gbadisplay implements a simple driver for the GameBoy Advance
|
||||
// display.
|
||||
package gbadisplay
|
||||
|
||||
import (
|
||||
"device/gba"
|
||||
"errors"
|
||||
"image/color"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
|
||||
"tinygo.org/x/drivers/pixel"
|
||||
)
|
||||
|
||||
// Image buffer type used by the GameBoy Advance.
|
||||
type Image = pixel.Image[pixel.RGB555]
|
||||
|
||||
const (
|
||||
displayWidth = 240
|
||||
displayHeight = 160
|
||||
)
|
||||
|
||||
var (
|
||||
errOutOfBounds = errors.New("rectangle coordinates outside display area")
|
||||
)
|
||||
|
||||
type Device struct{}
|
||||
|
||||
// New returns a new GameBoy Advance display object.
|
||||
func New() Device {
|
||||
return Device{}
|
||||
}
|
||||
|
||||
var displayFrameBuffer = (*[160 * 240]volatile.Register16)(unsafe.Pointer(uintptr(gba.MEM_VRAM)))
|
||||
|
||||
type Config struct {
|
||||
// TODO: add more display modes here.
|
||||
}
|
||||
|
||||
// Configure the display as a regular 15bpp framebuffer.
|
||||
func (d Device) Configure(config Config) {
|
||||
// Use video mode 3 (in BG2, a 16bpp bitmap in VRAM) and Enable BG2.
|
||||
gba.DISP.DISPCNT.Set(gba.DISPCNT_BGMODE_3<<gba.DISPCNT_BGMODE_Pos |
|
||||
gba.DISPCNT_SCREENDISPLAY_BG2_ENABLE<<gba.DISPCNT_SCREENDISPLAY_BG2_Pos)
|
||||
}
|
||||
|
||||
// Size returns the fixed size of this display.
|
||||
func (d Device) Size() (x, y int16) {
|
||||
return displayWidth, displayHeight
|
||||
}
|
||||
|
||||
// Display is a no-op: the display framebuffer is modified directly.
|
||||
func (d Device) Display() error {
|
||||
// Nothing to do here.
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPixel changes the pixel at (x, y) to the given color.
|
||||
func (d Device) SetPixel(x, y int16, c color.RGBA) {
|
||||
if x < 0 || y < 0 || x >= displayWidth || y > displayHeight {
|
||||
// Out of bounds, so ignore.
|
||||
return
|
||||
}
|
||||
val := pixel.NewColor[pixel.RGB555](c.R, c.G, c.B)
|
||||
displayFrameBuffer[(int(y))*240+int(x)].Set(uint16(val))
|
||||
}
|
||||
|
||||
// DrawBitmap updates the rectangle at (x, y) to the image stored in buf.
|
||||
func (d Device) DrawBitmap(x, y int16, buf Image) error {
|
||||
width, height := buf.Size()
|
||||
if x < 0 || y < 0 || int(x)+width > displayWidth || int(y)+height > displayHeight {
|
||||
return errOutOfBounds
|
||||
}
|
||||
|
||||
// TODO: try to do a 4-byte memcpy if possible. That should significantly
|
||||
// speed up the copying of this image.
|
||||
for bufY := 0; bufY < int(height); bufY++ {
|
||||
for bufX := 0; bufX < int(width); bufX++ {
|
||||
val := buf.Get(bufX, bufY)
|
||||
displayFrameBuffer[(int(y)+bufY)*240+int(x)+bufX].Set(uint16(val))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -6,6 +6,7 @@ require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||
github.com/frankban/quicktest v1.10.2
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/soypat/natiu-mqtt v0.5.1
|
||||
golang.org/x/net v0.7.0
|
||||
tinygo.org/x/tinyfont v0.3.0
|
||||
tinygo.org/x/tinyterm v0.1.0
|
||||
@@ -15,6 +16,5 @@ 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/text v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
)
|
||||
|
||||
@@ -12,11 +12,11 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
||||
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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
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=
|
||||
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/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
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=
|
||||
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package ina219
|
||||
|
||||
type Config struct {
|
||||
// BusVoltageRange sets the bus voltage range.
|
||||
BusVoltageRange BusVoltageRange
|
||||
|
||||
// PGA sets the programmable gain amplifier.
|
||||
PGA PGA
|
||||
|
||||
// BusADC sets the bus ADC resolution.
|
||||
BusADC BusADC
|
||||
|
||||
// ShuntADC sets the shunt ADC resolution.
|
||||
ShuntADC ShuntADC
|
||||
|
||||
// Mode sets the operating mode.
|
||||
Mode Mode
|
||||
|
||||
// Calibration sets the calibration value for the expected
|
||||
// voltage and current values.
|
||||
Calibration Calibration
|
||||
|
||||
// 1000 / uA per bit
|
||||
CurrentDivider float32
|
||||
|
||||
// 1mW per bit
|
||||
PowerMultiplier float32
|
||||
}
|
||||
|
||||
// RegisterValue returns the register value of the configuration.
|
||||
func (c *Config) RegisterValue() uint16 {
|
||||
return c.BusVoltageRange.RegisterValue() |
|
||||
c.PGA.RegisterValue() |
|
||||
c.BusADC.RegisterValue() |
|
||||
c.ShuntADC.RegisterValue() |
|
||||
c.Mode.RegisterValue()
|
||||
}
|
||||
|
||||
// Generate a new configuration from a register value.
|
||||
func NewConfig(config int16, calibration int16) Config {
|
||||
return Config{
|
||||
BusVoltageRange: BusVoltageRange(config >> 13 & 0x1),
|
||||
PGA: PGA(config >> 11 & 0x3),
|
||||
BusADC: BusADC(config >> 7 & 0xF),
|
||||
ShuntADC: ShuntADC(config >> 3 & 0xF),
|
||||
Mode: Mode(config & 0x7),
|
||||
Calibration: Calibration(calibration),
|
||||
}
|
||||
}
|
||||
|
||||
// Configurations from
|
||||
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
|
||||
var (
|
||||
// Config32V2A is a configuration for a 32V 2A range.
|
||||
Config32V2A = Config{
|
||||
BusVoltageRange: Range32V,
|
||||
PGA: PGA8,
|
||||
BusADC: ADC12,
|
||||
ShuntADC: SADC12,
|
||||
Mode: ModeContShuntBus,
|
||||
Calibration: Calibration16V400mA,
|
||||
CurrentDivider: 10.0,
|
||||
PowerMultiplier: 2.0,
|
||||
}
|
||||
|
||||
// Config32V1A is a configuration for a 32V 1A range.
|
||||
Config32V1A = Config{
|
||||
BusVoltageRange: Range32V,
|
||||
PGA: PGA8,
|
||||
BusADC: ADC12,
|
||||
ShuntADC: SADC12,
|
||||
Mode: ModeContShuntBus,
|
||||
Calibration: Calibration32V1A,
|
||||
CurrentDivider: 25.0,
|
||||
PowerMultiplier: 0.8,
|
||||
}
|
||||
|
||||
// Config16V400mA is a configuration for a 16V 400mA range.
|
||||
Config16V400mA = Config{
|
||||
BusVoltageRange: Range16V,
|
||||
PGA: PGA1,
|
||||
BusADC: ADC12,
|
||||
ShuntADC: SADC12,
|
||||
Mode: ModeContShuntBus,
|
||||
Calibration: Calibration16V400mA,
|
||||
CurrentDivider: 20.0,
|
||||
PowerMultiplier: 1.0,
|
||||
}
|
||||
)
|
||||
|
||||
// BusVoltageRange is the bus voltage range.
|
||||
type BusVoltageRange int8
|
||||
|
||||
const (
|
||||
Range16V BusVoltageRange = 0 // 0-16V
|
||||
Range32V BusVoltageRange = 1 // 0-32V
|
||||
)
|
||||
|
||||
func (r BusVoltageRange) RegisterValue() uint16 {
|
||||
return uint16(r) << 13
|
||||
}
|
||||
|
||||
// PGA is the programmable gain amplifier.
|
||||
type PGA int8
|
||||
|
||||
const (
|
||||
PGA1 PGA = 0 // 40mV
|
||||
PGA2 PGA = 1 // 80mV
|
||||
PGA4 PGA = 2 // 160mV
|
||||
PGA8 PGA = 3 // 320mV
|
||||
)
|
||||
|
||||
func (p PGA) RegisterValue() uint16 {
|
||||
return uint16(p) << 11
|
||||
}
|
||||
|
||||
// BusADC is the bus ADC resolution.
|
||||
type BusADC int8
|
||||
|
||||
const (
|
||||
ADC9 BusADC = 0 // 9-bit
|
||||
ADC10 BusADC = 1 // 10-bit
|
||||
ADC11 BusADC = 2 // 11-bit
|
||||
ADC12 BusADC = 3 // 12-bit
|
||||
)
|
||||
|
||||
func (b BusADC) RegisterValue() uint16 {
|
||||
return uint16(b) << 7
|
||||
}
|
||||
|
||||
// ShuntADC is the shunt ADC resolution.
|
||||
type ShuntADC int8
|
||||
|
||||
const (
|
||||
SADC9 ShuntADC = 0 // 9-bit
|
||||
SADC10 ShuntADC = 1 // 10-bit
|
||||
SADC11 ShuntADC = 2 // 11-bit
|
||||
SADC12 ShuntADC = 3 // 12-bit
|
||||
)
|
||||
|
||||
func (s ShuntADC) RegisterValue() uint16 {
|
||||
return uint16(s) << 3
|
||||
}
|
||||
|
||||
// Mode is the operating mode.
|
||||
type Mode int8
|
||||
|
||||
const (
|
||||
ModePowerDown Mode = 0 // power-down
|
||||
ModeTrigShunt Mode = 1 // triggered shunt voltage
|
||||
ModeTrigBus Mode = 2 // triggered bus voltage
|
||||
ModeTrigShuntBus Mode = 3 // triggered shunt and bus voltage
|
||||
ModeADCOff Mode = 4 // ADC off
|
||||
ModeContShunt Mode = 5 // continuous shunt voltage
|
||||
ModeContBus Mode = 6 // continuous bus voltage
|
||||
ModeContShuntBus Mode = 7 // continuous shunt and bus voltage
|
||||
)
|
||||
|
||||
// ModeTriggered is a mask for triggered modes.
|
||||
const ModeTriggeredMask Mode = 0x4
|
||||
|
||||
// ModeTriggered returns true if the mode is a triggered mode.
|
||||
func ModeTriggered(m Mode) bool {
|
||||
return m != ModePowerDown && m&ModeTriggeredMask == 0
|
||||
}
|
||||
|
||||
func (m Mode) RegisterValue() uint16 {
|
||||
return uint16(m)
|
||||
}
|
||||
|
||||
// Calibration is the calibration register for the INA219. Values from:
|
||||
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
|
||||
type Calibration uint16
|
||||
|
||||
const (
|
||||
Calibration32V2A Calibration = 4096
|
||||
Calibration32V1A Calibration = 10240
|
||||
Calibration16V400mA Calibration = 8192
|
||||
)
|
||||
|
||||
func (c Calibration) RegisterValue() uint16 {
|
||||
return uint16(c)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ina219
|
||||
|
||||
type ErrOverflow struct{}
|
||||
|
||||
func (e ErrOverflow) Error() string { return "overflow" }
|
||||
|
||||
type ErrNotReady struct{}
|
||||
|
||||
func (e ErrNotReady) Error() string { return "not ready" }
|
||||
|
||||
type ErrConfigMismatch struct{}
|
||||
|
||||
func (e ErrConfigMismatch) Error() string { return "config mismatch" }
|
||||
@@ -0,0 +1,202 @@
|
||||
package ina219
|
||||
|
||||
import (
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/internal/legacy"
|
||||
)
|
||||
|
||||
// An INA219 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
config Config
|
||||
}
|
||||
|
||||
// Create a new INA219 device with the default configuration
|
||||
// and the given I2C bus at the default address.
|
||||
//
|
||||
// Set Address after New to change the address.
|
||||
//
|
||||
// Call Configure after New to write the configuration to the
|
||||
// device. If you don't call Configure, the device may have a
|
||||
// different configuration and the power divider and current
|
||||
// multiplier are probably wrong.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: Address,
|
||||
config: Config32V2A,
|
||||
}
|
||||
}
|
||||
|
||||
// Set the configuration for the device. This only changes the
|
||||
// configuration in memory, not on the device. Call Configure
|
||||
// to write the configuration to the device.
|
||||
func (d *Device) SetConfig(config Config) {
|
||||
d.config = config
|
||||
}
|
||||
|
||||
// Write the current configuration to the device.
|
||||
func (d *Device) Configure() (err error) {
|
||||
if err = d.WriteRegister(
|
||||
RegConfig,
|
||||
d.config.RegisterValue(),
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = d.WriteRegister(
|
||||
RegCalibration,
|
||||
d.config.Calibration.RegisterValue(),
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var readConfig Config
|
||||
// make sure the configuration is read back correctly
|
||||
if readConfig, err = d.ReadConfig(); err != nil {
|
||||
return
|
||||
} else if readConfig.RegisterValue() != d.config.RegisterValue() {
|
||||
err = ErrConfigMismatch{}
|
||||
} else if readConfig.Calibration.RegisterValue() != d.config.Calibration.RegisterValue() {
|
||||
err = ErrConfigMismatch{}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Trigger a conversion. This is only necessary if the device is in
|
||||
// trigger mode. In continuous mode (the default), the device will
|
||||
// automatically trigger conversions and this has no effect. See
|
||||
// config.go.
|
||||
//
|
||||
// Triggering a conversion or reading the "power" register resets
|
||||
// the conversion ready bit.
|
||||
func (d *Device) Trigger() (err error) {
|
||||
// Only trigger if the mode is one of the triggered modes.
|
||||
if ModeTriggered(d.config.Mode) {
|
||||
err = d.WriteRegister(RegConfig, d.config.RegisterValue())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Measurements reads the bus voltage, shunt voltage, current, and power
|
||||
// from the device.
|
||||
func (d *Device) Measurements() (
|
||||
busVoltage int16,
|
||||
shuntVoltage int16,
|
||||
current float32,
|
||||
power float32,
|
||||
err error,
|
||||
) {
|
||||
// Attempt to read bus voltage first, so we can check for overflow
|
||||
// or conversion not ready.
|
||||
if busVoltage, err = d.BusVoltage(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Read the rest of the values, reading Power last, which resets
|
||||
// the conversion ready bit (relevant for triggered modes).
|
||||
if shuntVoltage, err = d.ShuntVoltage(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if current, err = d.Current(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if power, err = d.Power(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// BusVoltage reads the "bus" voltage in millivolts.
|
||||
//
|
||||
// It returns an error if the value is invalid due to overflow
|
||||
// or if the conversion is not ready yet. In a continuous mode
|
||||
// there should always be a measurement available after the
|
||||
// device is ready. See above notes on Trigger.
|
||||
func (d *Device) BusVoltage() (voltage int16, err error) {
|
||||
val, err := d.ReadRegister(RegBusVoltage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// The overflow bit is set, so the values are invalid.
|
||||
if val&(1<<0) != 0 {
|
||||
err = ErrOverflow{}
|
||||
return
|
||||
}
|
||||
|
||||
// The conversion is not ready yet.
|
||||
if ModeTriggered(d.config.Mode) && val&(1<<1) != 0 {
|
||||
err = ErrNotReady{}
|
||||
return
|
||||
}
|
||||
|
||||
voltage = (int16(val) >> 3) * 4
|
||||
return
|
||||
}
|
||||
|
||||
// ShuntVoltage reads the "shunt" voltage in 100ths of a millivolt.
|
||||
func (d *Device) ShuntVoltage() (voltage int16, err error) {
|
||||
return d.ReadRegister(RegShuntVoltage)
|
||||
}
|
||||
|
||||
// Current reads the current in milliamps.
|
||||
func (d *Device) Current() (current float32, err error) {
|
||||
val, err := d.ReadRegister(RegCurrent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
current = float32(val) / d.config.CurrentDivider
|
||||
return
|
||||
}
|
||||
|
||||
// Power reads the power in milliwatts.
|
||||
func (d *Device) Power() (power float32, err error) {
|
||||
val, err := d.ReadRegister(RegPower)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
power = float32(val) * d.config.PowerMultiplier
|
||||
return
|
||||
}
|
||||
|
||||
// Read the configuration from the device.
|
||||
func (d *Device) ReadConfig() (config Config, err error) {
|
||||
var cfg, cal int16
|
||||
if cfg, err = d.ReadRegister(RegConfig); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cal, err = d.ReadRegister(RegCalibration); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config = NewConfig(cfg, cal)
|
||||
return
|
||||
}
|
||||
|
||||
// Read a register from the device.
|
||||
func (d *Device) ReadRegister(reg uint8) (val int16, err error) {
|
||||
buf := make([]byte, 2)
|
||||
|
||||
err = legacy.ReadRegister(d.bus, uint8(d.Address), reg, buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
val = int16(buf[0])<<8 | int16(buf[1]&0xff)
|
||||
return
|
||||
}
|
||||
|
||||
// Write to a register on the device.
|
||||
func (d *Device) WriteRegister(reg uint8, val uint16) error {
|
||||
buf := []byte{byte(val >> 8), byte(val & 0xff)}
|
||||
return legacy.WriteRegister(d.bus, uint8(d.Address), reg, buf)
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package ina219
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"tinygo.org/x/drivers/tester"
|
||||
)
|
||||
|
||||
func TestDefaultAddress(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
dev := New(bus)
|
||||
c.Assert(dev.Address, qt.Equals, uint16(Address))
|
||||
}
|
||||
|
||||
func TestBusVoltage(t *testing.T) {
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegBusVoltage: (4200 << 3) / 4, // 4.2V
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
voltage, err := dev.BusVoltage()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(voltage, qt.Equals, int16(4200))
|
||||
})
|
||||
|
||||
t.Run("overflow", func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegBusVoltage: (1 >> 0), // overflow
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
_, err := dev.BusVoltage()
|
||||
c.Assert(err, qt.Not(qt.IsNil))
|
||||
c.Assert(err, qt.ErrorMatches, ErrOverflow{}.Error())
|
||||
})
|
||||
|
||||
t.Run("not ready", func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegBusVoltage: ((4200 << 3) / 4) | (1 << 1), // not ready
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
dev.config.Mode = ModeTrigBus
|
||||
_, err := dev.BusVoltage()
|
||||
c.Assert(err, qt.Not(qt.IsNil))
|
||||
c.Assert(err, qt.ErrorMatches, ErrNotReady{}.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestShuntVoltage(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegShuntVoltage: 0x1234,
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
voltage, err := dev.ShuntVoltage()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(voltage, qt.Equals, int16(0x1234))
|
||||
}
|
||||
|
||||
func TestCurrent(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegCurrent: 420 * 6.9, // 420mA
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
dev.config.CurrentDivider = 6.9
|
||||
current, err := dev.Current()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(current, qt.Equals, float32(420))
|
||||
}
|
||||
|
||||
func TestPower(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegPower: 420 / 0.8, // 420mW
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
dev.config.PowerMultiplier = 0.8
|
||||
power, err := dev.Power()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(power, qt.Equals, float32(420))
|
||||
}
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
// use the default configurations
|
||||
for _, tc := range []Config{
|
||||
Config16V400mA,
|
||||
Config32V2A,
|
||||
Config32V1A,
|
||||
} {
|
||||
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||
t.Run(n, func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegConfig: tc.RegisterValue(),
|
||||
RegCalibration: tc.Calibration.RegisterValue(),
|
||||
}
|
||||
bus.AddDevice(fake)
|
||||
|
||||
dev := New(bus)
|
||||
config, err := dev.ReadConfig()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(config.BusADC, qt.Equals, tc.BusADC)
|
||||
c.Assert(config.BusVoltageRange, qt.Equals, tc.BusVoltageRange)
|
||||
c.Assert(config.Calibration, qt.Equals, tc.Calibration)
|
||||
c.Assert(config.Mode, qt.Equals, tc.Mode)
|
||||
c.Assert(config.PGA, qt.Equals, tc.PGA)
|
||||
c.Assert(config.ShuntADC, qt.Equals, tc.ShuntADC)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteConfig(t *testing.T) {
|
||||
// use the default configurations
|
||||
for _, tc := range []Config{
|
||||
Config16V400mA,
|
||||
Config32V2A,
|
||||
Config32V1A,
|
||||
} {
|
||||
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||
t.Run(n, func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
bus.AddDevice(fake)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegConfig: 0,
|
||||
RegCalibration: 0,
|
||||
}
|
||||
|
||||
dev := New(bus)
|
||||
dev.config = tc
|
||||
err := dev.Configure()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(fake.Registers[RegConfig], qt.Equals, tc.RegisterValue())
|
||||
c.Assert(fake.Registers[RegCalibration], qt.Equals, tc.Calibration.RegisterValue())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetConfig(t *testing.T) {
|
||||
for _, tc := range []Config{
|
||||
Config16V400mA,
|
||||
Config32V2A,
|
||||
Config32V1A,
|
||||
} {
|
||||
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
|
||||
t.Run(n, func(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
dev := New(bus)
|
||||
dev.SetConfig(tc)
|
||||
c.Assert(dev.config, qt.Equals, tc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrigger(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
bus.AddDevice(fake)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegConfig: Config32V2A.RegisterValue(),
|
||||
}
|
||||
|
||||
dev := New(bus)
|
||||
dev.config = Config32V2A
|
||||
dev.config.Mode = ModeTrigBus
|
||||
err := dev.Trigger()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(fake.Registers[RegConfig], qt.Equals, dev.config.RegisterValue())
|
||||
}
|
||||
|
||||
func TestMeasurements(t *testing.T) {
|
||||
bvVal := int16(4200)
|
||||
svVal := int16(1234)
|
||||
iVal := float32(420)
|
||||
pVal := float32(420)
|
||||
|
||||
c := qt.New(t)
|
||||
bus := tester.NewI2CBus(c)
|
||||
fake := tester.NewI2CDevice16(c, Address)
|
||||
bus.AddDevice(fake)
|
||||
fake.Registers = map[uint8]uint16{
|
||||
RegBusVoltage: uint16(((4200 << 3) / 4) | (1 << 1)),
|
||||
RegShuntVoltage: uint16(svVal),
|
||||
RegCurrent: uint16(iVal * Config16V400mA.CurrentDivider),
|
||||
RegPower: uint16(pVal / Config16V400mA.PowerMultiplier),
|
||||
}
|
||||
|
||||
dev := New(bus)
|
||||
dev.config = Config16V400mA
|
||||
bv, sv, i, p, err := dev.Measurements()
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(bv, qt.Equals, bvVal)
|
||||
c.Assert(sv, qt.Equals, svVal)
|
||||
c.Assert(i, qt.Equals, iVal)
|
||||
c.Assert(p, qt.Equals, pVal)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ina219
|
||||
|
||||
// The default I2C address for this device.
|
||||
const Address = 0x40
|
||||
|
||||
const (
|
||||
RegConfig uint8 = 0x0
|
||||
RegShuntVoltage uint8 = 0x1
|
||||
RegBusVoltage uint8 = 0x2
|
||||
RegPower uint8 = 0x3
|
||||
RegCurrent uint8 = 0x4
|
||||
RegCalibration uint8 = 0x5
|
||||
)
|
||||
+112
-1
@@ -236,16 +236,83 @@ func (d *Device) getMode() (byte, error) {
|
||||
}
|
||||
|
||||
func (d *Device) configRate(speed, clock byte) error {
|
||||
// TODO: add another baudrate
|
||||
var cfg1, cfg2, cfg3 byte
|
||||
set := true
|
||||
switch clock {
|
||||
case Clock16MHz:
|
||||
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:
|
||||
cfg1 = mcp16mHz500kBpsCfg1
|
||||
cfg2 = mcp16mHz500kBpsCfg2
|
||||
cfg3 = mcp16mHz500kBpsCfg3
|
||||
case CAN666kBps:
|
||||
cfg1 = mcp16mHz666kBpsCfg1
|
||||
cfg2 = mcp16mHz666kBpsCfg2
|
||||
cfg3 = mcp16mHz666kBpsCfg3
|
||||
case CAN1000kBps:
|
||||
cfg1 = mcp16mHz1000kBpsCfg1
|
||||
cfg2 = mcp16mHz1000kBpsCfg2
|
||||
@@ -255,6 +322,50 @@ func (d *Device) configRate(speed, clock byte) error {
|
||||
}
|
||||
case Clock8MHz:
|
||||
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:
|
||||
cfg1 = mcp8mHz500kBpsCfg1
|
||||
cfg2 = mcp8mHz500kBpsCfg2
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor
|
||||
//
|
||||
// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf
|
||||
// Module: https://www.adafruit.com/product/1782
|
||||
// Only implemented: temperature reading, resolution read & set
|
||||
package mcp9808
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
}
|
||||
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus, MCP9808_I2CADDR_DEFAULT}
|
||||
}
|
||||
|
||||
func (d *Device) Connected() bool {
|
||||
data := make([]byte, 2)
|
||||
d.Read(MCP9808_REG_DEVICE_ID, &data)
|
||||
return binary.BigEndian.Uint16(data) == MCP9808_DEVICE_ID
|
||||
}
|
||||
|
||||
func (d *Device) ReadTemperature() (float64, error) {
|
||||
data := make([]byte, 2)
|
||||
var temp float64
|
||||
if err := d.Read(MCP9808_REG_AMBIENT_TEMP, &data); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
data[0] = data[0] & 0x1F
|
||||
if data[0]&0x10 == 0x10 {
|
||||
data[0] = data[0] & 0x0F
|
||||
temp = float64(data[0])*16 + float64(data[1])/16.0 - 256
|
||||
}
|
||||
temp = float64(data[0])*16 + float64(data[1])/16.0
|
||||
return temp, nil
|
||||
}
|
||||
|
||||
func (d *Device) ReadResolution() (resolution, error) {
|
||||
data := make([]byte, 2)
|
||||
err := d.Read(MCP9808_REG_RESOLUTION, &data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch data[0] {
|
||||
case 0:
|
||||
return Low, nil
|
||||
case 1:
|
||||
return Medium, nil
|
||||
case 2:
|
||||
return High, nil
|
||||
case 3:
|
||||
return Maximum, nil
|
||||
|
||||
default:
|
||||
return 0, errors.New("unknown resolution")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) SetResolution(r resolution) error {
|
||||
switch r {
|
||||
case Low:
|
||||
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x00}); err != nil {
|
||||
return err
|
||||
}
|
||||
case Medium:
|
||||
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x01}); err != nil {
|
||||
return err
|
||||
}
|
||||
case High:
|
||||
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x02}); err != nil {
|
||||
return err
|
||||
}
|
||||
case Maximum:
|
||||
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x03}); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Device) Write(register byte, data []byte) error {
|
||||
buf := append([]byte{register}, data...)
|
||||
return d.bus.Tx(d.Address, buf, nil)
|
||||
}
|
||||
|
||||
func (d *Device) Read(register byte, data *[]byte) error {
|
||||
return d.bus.Tx(d.Address, []byte{register}, *data)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor
|
||||
//
|
||||
// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf
|
||||
// Module: https://www.adafruit.com/product/1782
|
||||
package mcp9808
|
||||
|
||||
// Constants/addresses used for I2C.
|
||||
const (
|
||||
MCP9808_DEVICE_ID = 0x0400
|
||||
MCP9808_MANUF_ID = 0x0054
|
||||
|
||||
MCP9808_I2CADDR_DEFAULT = 0x18 //default I2C address
|
||||
MCP9808_REG_CONFIG = 0x01 //MCP9808 config register
|
||||
|
||||
MCP9808_REG_CONFIG_SHUTDOWN = 0x0100 //shutdown config
|
||||
MCP9808_REG_CONFIG_CRITLOCKED = 0x0080 //critical trip lock
|
||||
MCP9808_REG_CONFIG_WINLOCKED = 0x0040 //alarm window lock
|
||||
MCP9808_REG_CONFIG_INTCLR = 0x0020 //interrupt clear
|
||||
MCP9808_REG_CONFIG_ALERTSTAT = 0x0010 //alert output status
|
||||
MCP9808_REG_CONFIG_ALERTCTRL = 0x0008 //alert output control
|
||||
MCP9808_REG_CONFIG_ALERTSEL = 0x0004 //alert output select
|
||||
MCP9808_REG_CONFIG_ALERTPOL = 0x0002 //alert output polarity
|
||||
MCP9808_REG_CONFIG_ALERTMODE = 0x0001 //alert output mode
|
||||
|
||||
MCP9808_REG_UPPER_TEMP = 0x02 //upper alert boundary
|
||||
MCP9808_REG_LOWER_TEMP = 0x03 //lower alert boundery
|
||||
MCP9808_REG_CRIT_TEMP = 0x04 //critical temperature
|
||||
MCP9808_REG_AMBIENT_TEMP = 0x05 //ambient temperature
|
||||
MCP9808_REG_MANUF_ID = 0x06 //manufacturer ID
|
||||
MCP9808_REG_DEVICE_ID = 0x07 //device ID
|
||||
MCP9808_REG_RESOLUTION = 0x08 //resolution
|
||||
)
|
||||
|
||||
/*
|
||||
======= ============ ==============
|
||||
value resolution reading Time
|
||||
======= ============ ==============
|
||||
|
||||
0 0.5°C 30 ms
|
||||
1 0.25°C 65 ms
|
||||
2 0.125°C 130 ms
|
||||
3 0.0625°C 250 ms
|
||||
|
||||
======= ============ ==============
|
||||
*/
|
||||
type resolution uint8
|
||||
|
||||
const (
|
||||
Low resolution = iota
|
||||
Medium
|
||||
High
|
||||
Maximum
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user