mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 18:48:41 +00:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0eabf16c36 | |||
| f9db7a6d0f | |||
| d6a420bb08 | |||
| c7229ddba6 | |||
| 744fda5eec | |||
| 027c91272e | |||
| 5847506ba6 | |||
| e35e6b8e13 | |||
| 408851a9f5 | |||
| bd88b70511 | |||
| 34da2d208a | |||
| 5cb360a4bf | |||
| 51b604ce97 | |||
| ec680be784 | |||
| 5fb935001e | |||
| 297ad416d3 | |||
| 3fa08112db | |||
| b639f7b12e | |||
| 28d625abfd | |||
| 228e57cf98 | |||
| 6cf1eb86e5 | |||
| 857ab80ae6 | |||
| a31ba26a6c | |||
| 303ec94529 | |||
| 833990f44d | |||
| 28d87eb0c5 | |||
| ae9e8f915e | |||
| 45fad80c3e | |||
| 0304d30b78 | |||
| 7de0a0814e | |||
| 80356fd9d9 | |||
| c4ff8242a7 | |||
| 82c41dbf14 | |||
| c4168864fd | |||
| dbc9022f6a | |||
| d41bc0b85f | |||
| e7f90166ad | |||
| 156d6e7c9c | |||
| 6e04decf19 | |||
| afb1ea39c2 | |||
| 382e79a748 | |||
| 06dd60fba2 | |||
| 27a7d5031e | |||
| 6281f36662 | |||
| ccfcfa837e | |||
| 87c205fd65 | |||
| f57b5ecee9 | |||
| 486949686c | |||
| 00578a3a81 | |||
| 17f273243d | |||
| 0623bb425c | |||
| 019bbbe5fb | |||
| d04e68bef8 | |||
| 76a4276b5d | |||
| 7d7efe25e7 | |||
| 0186d0905d | |||
| 2f3b5ca59a | |||
| ecae5e28ad | |||
| bcf3b84654 | |||
| 4fb5d7a0e5 | |||
| f12454d4f7 | |||
| 829ae09651 | |||
| 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 | |||
| 6cf07aff4c | |||
| af33129f41 | |||
| 100aadf585 | |||
| 4a9667ffef | |||
| f96a70915e | |||
| 3e64e754a2 | |||
| 2c2da5c7bb | |||
| 14994a3f31 | |||
| 47dfeb9e94 | |||
| f20d1759d3 | |||
| 6b79a1b386 | |||
| 7dd1067cc1 | |||
| 4edb771c5b | |||
| e95cfe66c1 | |||
| 4edb58c0c5 | |||
| f384e2db48 | |||
| 7c96387845 | |||
| 182d4c6ebb | |||
| dc2de4f9ed | |||
| 36a12dd7a2 | |||
| 00992756eb | |||
| 715c33d4b0 |
@@ -0,0 +1,2 @@
|
||||
# These are supported funding model platforms
|
||||
open_collective: tinygo
|
||||
+243
@@ -1,3 +1,246 @@
|
||||
0.33.0
|
||||
---
|
||||
- **new devices**
|
||||
- **ens160**
|
||||
- Add ens160 i2c driver
|
||||
- **lsm303dlhc**
|
||||
- added support for LSM303DLHC e-Compass; (#783)
|
||||
- **seesaw**
|
||||
- add support for Adafruit Seesaw encoders
|
||||
|
||||
- **enhancements**
|
||||
- **ws2812**
|
||||
- add RP2350 support
|
||||
- **ssd1306**
|
||||
- avoid unnecessary heap allocations (#767)
|
||||
- **gps**
|
||||
- allow gps init with address
|
||||
- **lsm6ds3tr**
|
||||
- avoid unnecessary heap allocations (#766)
|
||||
|
||||
- **bugfixes**
|
||||
- **gps**
|
||||
- Fix gps time calculation (#785)
|
||||
|
||||
|
||||
0.32.0
|
||||
---
|
||||
- **enhancements**
|
||||
- **bmp280**
|
||||
- remove alloc on read sensor data
|
||||
- **ws2812**
|
||||
- add 200MHz support for the Cortex-M0/rp2040
|
||||
|
||||
- **bugfixes**
|
||||
- **ssd1306**
|
||||
- remove time.Sleep from SSD1306 SPI transfer code
|
||||
- **tmc2209**
|
||||
- tmc2209 bug fixes (#755)
|
||||
|
||||
- **docs**
|
||||
- **contributing**
|
||||
- add driver design pointer to CONTRIBUTING.md
|
||||
|
||||
|
||||
0.31.0
|
||||
---
|
||||
---
|
||||
- **enhancements**
|
||||
- **spi**
|
||||
- update all SPI usage to use either *machine.SPI or drivers.SPI
|
||||
|
||||
|
||||
0.30.0
|
||||
---
|
||||
- **new devices**
|
||||
- **comboat**
|
||||
- Add wifi driver comboat for Elecrow W5 rp2040 and rp2350 devices (#741)
|
||||
- **max6675**
|
||||
- Add MAX6675 device
|
||||
- **TMC2209**
|
||||
- Added TMC2209 support (#727)
|
||||
- **TMC5160**
|
||||
- Added TMC5160 support (#725)
|
||||
- **sharpmem**
|
||||
- Add sharpmem (#724)
|
||||
|
||||
- **enhancements**
|
||||
- **net**
|
||||
- move to latest golang.org/x/net v0.33.0 (#732)
|
||||
- **microphone**
|
||||
- update microphone driver to use latest i2s interface
|
||||
|
||||
- **bugfixes**
|
||||
- **net**
|
||||
- fix typo in DHCP error message
|
||||
- **aht20**
|
||||
- Fixed bug in aht20 driver
|
||||
- **hub75**
|
||||
- fix data buffering
|
||||
|
||||
|
||||
0.29.0
|
||||
---
|
||||
- **new devices**
|
||||
- **epd1in54**
|
||||
- Waveshare 1.54inch B/W e-Paper display (#704)
|
||||
- **touch**
|
||||
- add capacitive touch sensing on normal GPIO pins
|
||||
- **INA219**
|
||||
- I2C INA219 driver (#705)
|
||||
- **pcf8591**
|
||||
- add ADC only implementation for I2C ADC/DAC (#690)
|
||||
|
||||
- **enhancements**
|
||||
- **pixel**
|
||||
- add NewImageFromBytes() function to allow creating image from existing slice
|
||||
- **servo**
|
||||
- Add function `SetAngleWithMicroseconds` (#695)
|
||||
- **onewire**
|
||||
- onewire improvements
|
||||
- **ssd1306**
|
||||
- Add function `SetFlip` and `GetFlip` (#702)
|
||||
- **uc8151**
|
||||
- add FillRectangle() and SetScroll() functions to satisfy tinyterm.Displayer interface
|
||||
- **ssd1306**
|
||||
- add FillRectangle() and SetScroll() functions to satisfy tinyterm.Displayer interface
|
||||
|
||||
- **bugfixes**
|
||||
- **pixel**
|
||||
- fix Monochrome setPixel
|
||||
|
||||
- **docs**
|
||||
- **readme**
|
||||
- discuss need to change variables in examples
|
||||
- **sponsor**
|
||||
- Add sponsor button to key repositories
|
||||
|
||||
|
||||
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**
|
||||
|
||||
@@ -8,6 +8,9 @@ We would like your help to make this project better, so we appreciate any contri
|
||||
|
||||
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
|
||||
|
||||
### Driver design
|
||||
Before porting or writing a driver from scratch please read **[Driver Design for TinyGo](https://tinygo.org/docs/guides/driver-design)**.
|
||||
|
||||
### One of the TinyGo drivers is not working as you expect
|
||||
|
||||
Please open a Github issue with your problem, and we will be happy to assist.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2025 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!
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
// Package adafruit4650 implements a driver for the Adafruit FeatherWing OLED - 128x64 OLED display.
|
||||
// The display is backed itself by a SH1107 driver chip.
|
||||
//
|
||||
// Store: https://www.adafruit.com/product/4650
|
||||
//
|
||||
// Documentation: https://learn.adafruit.com/adafruit-128x64-oled-featherwing
|
||||
package adafruit4650
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
const DefaultAddress = 0x3c
|
||||
|
||||
const (
|
||||
commandSetLowColumn = 0x00
|
||||
commandSetHighColumn = 0x10
|
||||
commandSetPage = 0xb0
|
||||
)
|
||||
|
||||
const (
|
||||
width = 128
|
||||
height = 64
|
||||
)
|
||||
|
||||
// Device represents an Adafruit 4650 device
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint8
|
||||
buffer []byte
|
||||
width int16
|
||||
height int16
|
||||
}
|
||||
|
||||
// New creates a new device, not configuring anything yet.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
Address: DefaultAddress,
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure initializes the display with default configuration
|
||||
func (d *Device) Configure() error {
|
||||
|
||||
bufferSize := d.width * d.height / 8
|
||||
d.buffer = make([]byte, bufferSize)
|
||||
|
||||
// This sequence is an amalgamation of the datasheet, official Arduino driver, CircuitPython driver and other drivers
|
||||
initSequence := []byte{
|
||||
0xae, // display off, sleep mode
|
||||
//0xd5, 0x41, // set display clock divider (from original datasheet)
|
||||
0xd5, 0x51, // set display clock divider (from Adafruit driver)
|
||||
0xd9, 0x22, // pre-charge/dis-charge period mode: 2 DCLKs/2 DCLKs (POR)
|
||||
0x20, // memory mode
|
||||
0x81, 0x4f, // contrast setting = 0x4f
|
||||
0xad, 0x8a, // set dc/dc pump
|
||||
0xa0, // segment remap, flip-x
|
||||
0xc0, // common output scan direction
|
||||
0xdc, 0x00, // set display start line 0 (POR=0)
|
||||
0xa8, 0x3f, // multiplex ratio, height - 1 = 0x3f
|
||||
0xd3, 0x60, // set display offset mode = 0x60
|
||||
0xdb, 0x35, // VCOM deselect level = 0.770 (POR)
|
||||
0xa4, // entire display off, retain RAM, normal status (POR)
|
||||
0xa6, // normal (not reversed) display
|
||||
0xaf, // display on
|
||||
}
|
||||
|
||||
err := d.writeCommands(initSequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// recommended in the datasheet, same in other drivers
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay clears the image buffer as well as the actual display
|
||||
func (d *Device) ClearDisplay() error {
|
||||
d.ClearBuffer()
|
||||
return d.Display()
|
||||
}
|
||||
|
||||
// ClearBuffer clears the buffer
|
||||
func (d *Device) ClearBuffer() {
|
||||
bzero(d.buffer)
|
||||
}
|
||||
|
||||
// SetPixel modifies the internal buffer. Since this display has a bit-depth of 1 bit any non-zero
|
||||
// color component will be treated as 'on', otherwise 'off'.
|
||||
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
||||
if x < 0 || x >= d.width || y < 0 || y >= d.height {
|
||||
return
|
||||
}
|
||||
|
||||
// RAM layout
|
||||
// *-----> y
|
||||
// |
|
||||
// x| col0 col1 ... col63
|
||||
// v p0 a0 b0 ..
|
||||
// a1 b1 ..
|
||||
// .. .. ..
|
||||
// a7 b7 ..
|
||||
// p1 a0 b0
|
||||
// a1 b1
|
||||
//
|
||||
|
||||
//flip y - so the display orientation matches the silk screen labeling etc.
|
||||
y = d.height - y - 1
|
||||
|
||||
page := x / 8
|
||||
bytesPerPage := d.height
|
||||
byteIndex := y + bytesPerPage*page
|
||||
bit := x % 8
|
||||
if (c.R | c.G | c.B) != 0 {
|
||||
d.buffer[byteIndex] |= 1 << uint8(bit)
|
||||
} else {
|
||||
d.buffer[byteIndex] &^= 1 << uint8(bit)
|
||||
}
|
||||
}
|
||||
|
||||
// Display sends the whole buffer to the screen
|
||||
func (d *Device) Display() error {
|
||||
|
||||
bytesPerPage := d.height
|
||||
|
||||
pages := (d.width + 7) / 8
|
||||
for page := int16(0); page < pages; page++ {
|
||||
|
||||
err := d.setRAMPosition(uint8(page), 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offset := page * bytesPerPage
|
||||
err = d.writeRAM(d.buffer[offset : offset+bytesPerPage])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setRAMPosition updates the device's current page and column position
|
||||
func (d *Device) setRAMPosition(page uint8, column uint8) error {
|
||||
if page > 15 {
|
||||
panic("page out of bounds")
|
||||
}
|
||||
if column > 127 {
|
||||
panic("column out of bounds")
|
||||
}
|
||||
setPage := commandSetPage | (page & 0xF)
|
||||
|
||||
lo := column & 0xF
|
||||
setLowColumn := commandSetLowColumn | lo
|
||||
|
||||
hi := (column >> 4) & 0x7
|
||||
setHighColumn := commandSetHighColumn | hi
|
||||
|
||||
cmds := []byte{
|
||||
setPage,
|
||||
setLowColumn,
|
||||
setHighColumn,
|
||||
}
|
||||
|
||||
return d.writeCommands(cmds)
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
func (d *Device) Size() (w, h int16) {
|
||||
return d.width, d.height
|
||||
}
|
||||
|
||||
func (d *Device) writeCommands(commands []byte) error {
|
||||
onlyCommandsFollowing := byte(0x00)
|
||||
return d.bus.Tx(uint16(d.Address), append([]byte{onlyCommandsFollowing}, commands...), nil)
|
||||
}
|
||||
|
||||
func (d *Device) writeRAM(data []byte) error {
|
||||
onlyRAMFollowing := byte(0x40)
|
||||
return d.bus.Tx(uint16(d.Address), append([]byte{onlyRAMFollowing}, data...), nil)
|
||||
}
|
||||
|
||||
func bzero(buf []byte) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package adafruit4650
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/tinyfont"
|
||||
"tinygo.org/x/tinyfont/freemono"
|
||||
)
|
||||
|
||||
//go:embed expected_hello_world.png
|
||||
var expectedHelloWorld []byte
|
||||
|
||||
// mockBus mocks a fake i2c device adafruit4650 display.
|
||||
// The memory layout assumes that clients set up the device in a particular way and always send complete
|
||||
// pages to the device buffer.
|
||||
type mockBus struct {
|
||||
img draw.Image
|
||||
line int
|
||||
addr uint8
|
||||
currentPage int
|
||||
currentColumn int
|
||||
}
|
||||
|
||||
func (m *mockBus) Tx(addr uint16, w, r []byte) error {
|
||||
if addr != uint16(m.addr) {
|
||||
panic("unexpected address")
|
||||
}
|
||||
if r != nil {
|
||||
panic("mock does not support reads")
|
||||
}
|
||||
|
||||
if w[0] == 0x00 {
|
||||
if w[1]&0xf0 == 0xb0 {
|
||||
m.currentPage = int(w[1] & 0x0f)
|
||||
|
||||
lo := w[2] & 0x0f
|
||||
hi := w[2] & 0x07
|
||||
m.currentColumn = int(hi<<4 | lo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if w[0] != 0x40 {
|
||||
panic("unexpected first byte: " + hex.EncodeToString(w[0:1]))
|
||||
}
|
||||
|
||||
return m.writeRAM(w[1:])
|
||||
}
|
||||
|
||||
func newMock() *mockBus {
|
||||
|
||||
m := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
return &mockBus{img: m, addr: DefaultAddress, currentPage: -1, currentColumn: -1}
|
||||
}
|
||||
|
||||
func (m *mockBus) writeRAM(data []byte) error {
|
||||
|
||||
// RAM layout
|
||||
// *-----> y
|
||||
// |
|
||||
// x| col0 col1 ... col63
|
||||
// v p0 a0 b0 ..
|
||||
// a1 b1 ..
|
||||
// .. .. ..
|
||||
// a7 b7 ..
|
||||
// p1 a0 b0
|
||||
// a1 b1
|
||||
//
|
||||
|
||||
fmt.Printf("writing page %d\n", m.currentPage)
|
||||
// assuming entire pages will be written
|
||||
for x := 0; x < 8; x++ {
|
||||
for y := 0; y < height; y++ {
|
||||
|
||||
col := data[y]
|
||||
|
||||
c := color.Black
|
||||
if col&(1<<x) != 0 {
|
||||
c = color.White
|
||||
}
|
||||
|
||||
m.img.Set(x+m.currentPage*8, height-y-1, c)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockBus) toImage() *image.RGBA {
|
||||
|
||||
container := image.NewRGBA(m.img.Bounds().Inset(-1))
|
||||
draw.Draw(container, container.Bounds(), image.NewUniform(color.RGBA{G: 255, A: 255}), image.Point{}, draw.Over)
|
||||
draw.Draw(container, m.img.Bounds(), m.img, image.Point{}, draw.Over)
|
||||
return container
|
||||
}
|
||||
|
||||
func TestDevice_Display(t *testing.T) {
|
||||
|
||||
bus := newMock()
|
||||
dev := New(bus)
|
||||
|
||||
dev.Configure()
|
||||
|
||||
drawPlus(&dev)
|
||||
drawHellowWorld(&dev)
|
||||
|
||||
//when
|
||||
dev.Display()
|
||||
|
||||
//then
|
||||
actual := bus.toImage()
|
||||
|
||||
expected, err := png.Decode(bytes.NewReader(expectedHelloWorld))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
assertEqualImages(t, actual, expected)
|
||||
}
|
||||
|
||||
func drawPlus(d drivers.Displayer) {
|
||||
for i := int16(0); i < 128; i++ {
|
||||
d.SetPixel(i, 32, color.RGBA{R: 1})
|
||||
}
|
||||
for i := int16(0); i < 64; i++ {
|
||||
d.SetPixel(64, i, color.RGBA{R: 1})
|
||||
}
|
||||
}
|
||||
|
||||
func drawHellowWorld(d drivers.Displayer) {
|
||||
tinyfont.WriteLine(d, &freemono.Regular9pt7b, 0, 32, "Hello World!", color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
|
||||
}
|
||||
|
||||
func assertEqualImages(t testing.TB, actual, expected image.Image) {
|
||||
|
||||
if actual.Bounds().Dx() != expected.Bounds().Dx() || actual.Bounds().Dy() != expected.Bounds().Dy() {
|
||||
f := writeImage(actual)
|
||||
t.Fatalf("differing size: was %v, expected %v, saved actual to %s", actual.Bounds(), expected.Bounds(), f)
|
||||
}
|
||||
|
||||
bb := expected.Bounds()
|
||||
for x := bb.Min.X; x < bb.Max.X; x++ {
|
||||
for y := bb.Min.Y; y < bb.Max.Y; y++ {
|
||||
actualBB := actual.Bounds()
|
||||
if actual.At(x+actualBB.Min.X, y+actualBB.Min.Y) != expected.At(x, y) {
|
||||
f := writeImage(actual)
|
||||
t.Fatalf("different pixel at %d/%d: %v != %v, saved actual at %s", x, y, actual.At(x, y), expected.At(x, y), f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeImage(img image.Image) string {
|
||||
|
||||
fn := fmt.Sprintf("%d.png", time.Now().Unix())
|
||||
f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = png.Encode(f, img)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 449 B |
+7
-7
@@ -95,16 +95,16 @@ func (d *Device) Restart() {
|
||||
func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
|
||||
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
@@ -29,7 +29,7 @@ func New(bus drivers.I2C) Device {
|
||||
func (d *Device) Configure() {
|
||||
// Check initialization state
|
||||
status := d.Status()
|
||||
if status&0x08 == 1 {
|
||||
if status&STATUS_CALIBRATED == 1 {
|
||||
// Device is initialized
|
||||
return
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func (d *Device) Read() error {
|
||||
}
|
||||
|
||||
// If measurement complete, store values
|
||||
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
|
||||
if data[0]&STATUS_CALIBRATED != 0 && data[0]&STATUS_BUSY == 0 {
|
||||
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
|
||||
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||
return nil
|
||||
|
||||
+7
-3
@@ -5,9 +5,10 @@ package apa102 // import "tinygo.org/x/drivers/apa102"
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/internal/legacy"
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,8 +38,11 @@ func New(b drivers.SPI) *Device {
|
||||
|
||||
// NewSoftwareSPI returns a new APA102 driver that will use a software based
|
||||
// implementation of the SPI protocol.
|
||||
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
|
||||
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
|
||||
func NewSoftwareSPI(sckPin, sdoPin pin.Output, delay uint32) *Device {
|
||||
return New(&bbSPI{SCK: sckPin.Set, SDO: sdoPin.Set, Delay: delay, configurePins: func() {
|
||||
legacy.ConfigurePinOut(sckPin)
|
||||
legacy.ConfigurePinOut(sdoPin)
|
||||
}})
|
||||
}
|
||||
|
||||
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
|
||||
|
||||
+12
-6
@@ -1,6 +1,9 @@
|
||||
package apa102
|
||||
|
||||
import "machine"
|
||||
import (
|
||||
"tinygo.org/x/drivers/internal/legacy"
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
|
||||
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
|
||||
@@ -8,15 +11,18 @@ import "machine"
|
||||
// most purposes other than the APA102 package. It might be desirable to make
|
||||
// this more generic and include it in the TinyGo "machine" package instead.
|
||||
type bbSPI struct {
|
||||
SCK machine.Pin
|
||||
SDO machine.Pin
|
||||
Delay uint32
|
||||
SCK pin.OutputFunc
|
||||
SDO pin.OutputFunc
|
||||
Delay uint32
|
||||
configurePins func()
|
||||
}
|
||||
|
||||
// Configure sets up the SCK and SDO pins as outputs and sets them low
|
||||
func (s *bbSPI) Configure() {
|
||||
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
if s.configurePins == nil {
|
||||
panic(legacy.ErrConfigBeforeInstantiated)
|
||||
}
|
||||
s.configurePins()
|
||||
s.SCK.Low()
|
||||
s.SDO.Low()
|
||||
if s.Delay == 0 {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a DS3231 device.
|
||||
// Device wraps an I2C connection to an AT24CX device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
|
||||
+31
-24
@@ -1,31 +1,36 @@
|
||||
package bmi160
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/internal/legacy"
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
// DeviceSPI is the SPI interface to a BMI160 accelerometer/gyroscope. There is
|
||||
// also an I2C interface, but it is not yet supported.
|
||||
type DeviceSPI struct {
|
||||
// Chip select pin
|
||||
CSB machine.Pin
|
||||
csb pin.OutputFunc
|
||||
|
||||
buf [7]byte
|
||||
|
||||
// SPI bus (requires chip select to be usable).
|
||||
Bus drivers.SPI
|
||||
bus drivers.SPI
|
||||
configurePins func()
|
||||
}
|
||||
|
||||
// NewSPI returns a new device driver. The pin and SPI interface are not
|
||||
// touched, provide a fully configured SPI object and call Configure to start
|
||||
// using this device.
|
||||
func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
|
||||
func NewSPI(csb pin.Output, spi drivers.SPI) *DeviceSPI {
|
||||
return &DeviceSPI{
|
||||
CSB: csb, // chip select
|
||||
Bus: spi,
|
||||
csb: csb.Set, // chip select
|
||||
bus: spi,
|
||||
configurePins: func() {
|
||||
legacy.ConfigurePinOut(csb)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +38,11 @@ func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
|
||||
// configures the BMI160, but it does not configure the SPI interface (it is
|
||||
// assumed to be up and running).
|
||||
func (d *DeviceSPI) Configure() error {
|
||||
d.CSB.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
d.CSB.High()
|
||||
|
||||
if d.configurePins == nil {
|
||||
return legacy.ErrConfigBeforeInstantiated
|
||||
}
|
||||
d.configurePins()
|
||||
d.csb.High()
|
||||
// The datasheet recommends doing a register read from address 0x7F to get
|
||||
// SPI communication going:
|
||||
// > If CSB sees a rising edge after power-up, the BMI160 interface switches
|
||||
@@ -86,9 +93,9 @@ func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
|
||||
data[0] = 0x80 | reg_TEMPERATURE_0
|
||||
data[1] = 0
|
||||
data[2] = 0
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
d.csb.Low()
|
||||
err = d.bus.Tx(data, data)
|
||||
d.csb.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -123,9 +130,9 @@ func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
|
||||
for i := 1; i < len(data); i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
d.csb.Low()
|
||||
err = d.bus.Tx(data, data)
|
||||
d.csb.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -153,9 +160,9 @@ func (d *DeviceSPI) ReadRotation() (x int32, y int32, z int32, err error) {
|
||||
for i := 1; i < len(data); i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
d.CSB.Low()
|
||||
err = d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
d.csb.Low()
|
||||
err = d.bus.Tx(data, data)
|
||||
d.csb.High()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -201,9 +208,9 @@ func (d *DeviceSPI) readRegister(address uint8) uint8 {
|
||||
data := d.buf[:2]
|
||||
data[0] = 0x80 | address
|
||||
data[1] = 0
|
||||
d.CSB.Low()
|
||||
d.Bus.Tx(data, data)
|
||||
d.CSB.High()
|
||||
d.csb.Low()
|
||||
d.bus.Tx(data, data)
|
||||
d.csb.High()
|
||||
return data[1]
|
||||
}
|
||||
|
||||
@@ -217,7 +224,7 @@ func (d *DeviceSPI) writeRegister(address, data uint8) {
|
||||
buf[0] = address
|
||||
buf[1] = data
|
||||
|
||||
d.CSB.Low()
|
||||
d.Bus.Tx(buf, buf)
|
||||
d.CSB.High()
|
||||
d.csb.Low()
|
||||
d.bus.Tx(buf, buf)
|
||||
d.csb.High()
|
||||
}
|
||||
|
||||
+7
-8
@@ -23,6 +23,7 @@ type Filter uint
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
buf [6]byte
|
||||
cali calibrationCoefficients
|
||||
Temperature Oversampling
|
||||
Pressure Oversampling
|
||||
@@ -134,8 +135,8 @@ func (d *Device) PrintCali() {
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
data, err := d.readData(REG_TEMP, 3)
|
||||
if err != nil {
|
||||
data := d.buf[:3]
|
||||
if err = d.readData(REG_TEMP, data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -158,8 +159,8 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
// ReadPressure returns the pressure in milli pascals (mPa).
|
||||
func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
// First 3 bytes are Pressure, last 3 bytes are Temperature
|
||||
data, err := d.readData(REG_PRES, 6)
|
||||
if err != nil {
|
||||
data := d.buf[:6]
|
||||
if err = d.readData(REG_PRES, data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -203,7 +204,7 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
}
|
||||
|
||||
// readData reads n number of bytes of the specified register
|
||||
func (d *Device) readData(register int, n int) ([]byte, error) {
|
||||
func (d *Device) readData(register int, data []byte) error {
|
||||
// If not in normal mode, set the mode to FORCED mode, to prevent incorrect measurements
|
||||
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
|
||||
if d.Mode != MODE_NORMAL {
|
||||
@@ -218,9 +219,7 @@ func (d *Device) readData(register int, n int) ([]byte, error) {
|
||||
}
|
||||
|
||||
// Read the requested register
|
||||
data := make([]byte, n)
|
||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
|
||||
return data, err
|
||||
return legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
|
||||
}
|
||||
|
||||
// convert3Bytes converts three bytes to int32
|
||||
|
||||
+7
-7
@@ -2,22 +2,22 @@
|
||||
package buzzer // import "tinygo.org/x/drivers/buzzer"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
// Device wraps a GPIO connection to a buzzer.
|
||||
type Device struct {
|
||||
pin machine.Pin
|
||||
pin pin.OutputFunc
|
||||
High bool
|
||||
BPM float64
|
||||
}
|
||||
|
||||
// New returns a new buzzer driver given which pin to use
|
||||
func New(pin machine.Pin) Device {
|
||||
func New(pin pin.Output) Device {
|
||||
return Device{
|
||||
pin: pin,
|
||||
pin: pin.Set,
|
||||
High: false,
|
||||
BPM: 96.0,
|
||||
}
|
||||
@@ -25,14 +25,14 @@ func New(pin machine.Pin) Device {
|
||||
|
||||
// On sets the buzzer to a high state.
|
||||
func (l *Device) On() (err error) {
|
||||
l.pin.Set(true)
|
||||
l.pin.High()
|
||||
l.High = true
|
||||
return
|
||||
}
|
||||
|
||||
// Off sets the buzzer to a low state.
|
||||
func (l *Device) Off() (err error) {
|
||||
l.pin.Set(false)
|
||||
l.pin.Low()
|
||||
l.High = false
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,711 @@
|
||||
// Package comboat implements WiFi driver for the Aithinker-Combo-AT WiFi
|
||||
// device found on the Elecrow W5 rp2040 and rp2350 devices. Ths WiFi device
|
||||
// is a RTL8720d variant. The driver interface is via AT command set over UART
|
||||
// (see reference docs below).
|
||||
//
|
||||
// NOTE: the driver doesn't support UDP/TCP server connections in STA mode,
|
||||
// currently. UDP/TCP/TLS client connections are supported in STA mode.
|
||||
//
|
||||
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/instruction/index.html
|
||||
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/command-set/index.html
|
||||
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/command-examples/index.html
|
||||
|
||||
package comboat // import "tinygo.org/x/drivers/comboat"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"machine"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/netdev"
|
||||
"tinygo.org/x/drivers/netlink"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
BaudRate uint32
|
||||
Uart *machine.UART
|
||||
Tx machine.Pin
|
||||
Rx machine.Pin
|
||||
}
|
||||
|
||||
type socket struct {
|
||||
protocol int
|
||||
id string
|
||||
rx chan []byte
|
||||
remainder []byte
|
||||
laddr netip.AddrPort // Set in Bind()
|
||||
}
|
||||
|
||||
type device struct {
|
||||
cfg *Config
|
||||
uart *machine.UART
|
||||
uartMu sync.Mutex
|
||||
mac net.HardwareAddr
|
||||
ip netip.Addr
|
||||
gateway netip.Addr
|
||||
buf [1500]byte
|
||||
pos int
|
||||
last []byte
|
||||
ok chan bool
|
||||
txReady chan bool
|
||||
accept chan string
|
||||
err chan error
|
||||
sockets [8]*socket
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func NewDevice(cfg *Config) *device {
|
||||
return &device{
|
||||
cfg: cfg,
|
||||
ok: make(chan bool),
|
||||
txReady: make(chan bool),
|
||||
accept: make(chan string),
|
||||
err: make(chan error),
|
||||
}
|
||||
}
|
||||
|
||||
func logDebug(msg string) {
|
||||
//println("[DEBUG] " + msg)
|
||||
}
|
||||
|
||||
func logError(msg string) {
|
||||
println("[ERROR] " + msg)
|
||||
}
|
||||
|
||||
func split(resp []byte, part int, del, on string) string {
|
||||
parts := bytes.Split(resp, []byte(del))
|
||||
if part >= len(parts) {
|
||||
return "Split parts error getting " + on
|
||||
}
|
||||
return string(parts[part])
|
||||
}
|
||||
|
||||
func (d *device) getFWVersion() string {
|
||||
return split(d.last, 1, ":", "FW version")
|
||||
}
|
||||
|
||||
func (d *device) saveMAC() {
|
||||
raw := split(d.last, 1, ":", "MAC")
|
||||
if len(raw) > 11 {
|
||||
macStr := fmt.Sprintf("%s:%s:%s:%s:%s:%s",
|
||||
raw[0:2], raw[2:4], raw[4:6],
|
||||
raw[6:8], raw[8:10], raw[10:12])
|
||||
d.mac, _ = net.ParseMAC(macStr)
|
||||
}
|
||||
}
|
||||
|
||||
var countryCodes = map[int]string{
|
||||
1: "JP Japan",
|
||||
2: "American Samoa",
|
||||
3: "CA Canada",
|
||||
4: "US",
|
||||
5: "CN China",
|
||||
6: "Hong Kong, China",
|
||||
7: "Taiwan, China",
|
||||
8: "MO Macau, China",
|
||||
9: "IL Israel",
|
||||
10: "Singapore",
|
||||
11: "KR South Korea",
|
||||
12: "TR Türkiye",
|
||||
13: "AU Australia",
|
||||
14: "ZA South Africa",
|
||||
15: "BR Brazil",
|
||||
}
|
||||
|
||||
func (d *device) getCountry() (code string) {
|
||||
code = split(d.last, 1, ":", "county code")
|
||||
codeNum, err := strconv.Atoi(code)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if val, ok := countryCodes[codeNum]; ok {
|
||||
code = val
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *device) saveIP() {
|
||||
ipStr := split(d.last, 7, ",", "IP address")
|
||||
gwStr := split(d.last, 8, ",", "gateway address")
|
||||
d.ip, _ = netip.ParseAddr(ipStr)
|
||||
d.gateway, _ = netip.ParseAddr(gwStr)
|
||||
}
|
||||
|
||||
func (d *device) execute(cmd string, timeout int) (err error) {
|
||||
logDebug("EXECUTE " + cmd)
|
||||
|
||||
d.uartMu.Lock()
|
||||
_, err = d.uart.Write([]byte(cmd + "\r\n"))
|
||||
d.uartMu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t := time.NewTicker(time.Duration(timeout) * time.Millisecond)
|
||||
defer t.Stop()
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
return errors.New("Timed out")
|
||||
case <-d.ok:
|
||||
return
|
||||
case err = <-d.err:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) send(cmd string, timeout int) (err error) {
|
||||
logDebug("EXECUTE " + cmd)
|
||||
|
||||
d.uartMu.Lock()
|
||||
_, err = d.uart.Write([]byte(cmd + "\r\n"))
|
||||
d.uartMu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t := time.NewTicker(time.Duration(timeout) * time.Millisecond)
|
||||
defer t.Stop()
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
return errors.New("Timed out")
|
||||
case <-d.txReady:
|
||||
return
|
||||
case err = <-d.err:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) findSocket(id string) (*socket, error) {
|
||||
for _, s := range d.sockets {
|
||||
if s.id == id {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("Socket not found with id: " + id)
|
||||
}
|
||||
|
||||
func (d *device) getSocket(sockfd int) (*socket, error) {
|
||||
if sockfd < 0 || sockfd+1 > len(d.sockets) {
|
||||
return nil, netdev.ErrInvalidSocketFd
|
||||
}
|
||||
if d.sockets[sockfd] == nil {
|
||||
return nil, netdev.ErrInvalidSocketFd
|
||||
}
|
||||
return d.sockets[sockfd], nil
|
||||
}
|
||||
|
||||
func (d *device) handle(event []byte) {
|
||||
logDebug("GOT EVENT " + string(event))
|
||||
switch {
|
||||
|
||||
// SocketDisconnect,<id>
|
||||
case bytes.HasPrefix(event, []byte("SocketDisconnect")):
|
||||
id := split(event, 1, ",", "SocketDisconnect")
|
||||
s, err := d.findSocket(id)
|
||||
if err == nil {
|
||||
close(s.rx) // Sends io.EOF
|
||||
}
|
||||
|
||||
// SocketSeed,<id>,<server id>
|
||||
case bytes.HasPrefix(event, []byte("SocketSeed,2,1")):
|
||||
//d.uart.Write([]byte("AT+SOCKET?" + "\r\n"))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) processUART() {
|
||||
|
||||
if d.pos == 1 && d.buf[0] == '>' {
|
||||
d.pos = 0
|
||||
logDebug("GOT >")
|
||||
d.txReady <- true
|
||||
}
|
||||
|
||||
sofar := d.buf[:d.pos]
|
||||
|
||||
if !bytes.HasSuffix(sofar, []byte("\r\n")) {
|
||||
return
|
||||
}
|
||||
|
||||
// Strip CR/LF off end
|
||||
sofar = sofar[:len(sofar)-2]
|
||||
|
||||
switch {
|
||||
|
||||
case bytes.HasPrefix(sofar, []byte("+EVENT:SocketDown")):
|
||||
// +EVENT:SocketDown,<id>,<length>,<data>
|
||||
parts := bytes.SplitN(sofar, []byte(","), 4)
|
||||
if len(parts) != 4 {
|
||||
logError("Error parsing +EVENT:SocketDown: " + string(sofar))
|
||||
d.pos = 0
|
||||
return
|
||||
}
|
||||
id := string(parts[1])
|
||||
length, err := strconv.Atoi(string(parts[2]))
|
||||
if err != nil {
|
||||
logError("Error parsing length from: " + string(parts[2]))
|
||||
d.pos = 0
|
||||
return
|
||||
}
|
||||
if length != len(parts[3]) {
|
||||
// This can happen if <data> actually contains a CR/LF.
|
||||
// Return without resetting d.pos to continue reading
|
||||
// in the full <data>.
|
||||
return
|
||||
}
|
||||
s, err := d.findSocket(id)
|
||||
if err != nil {
|
||||
logError(err.Error())
|
||||
d.pos = 0
|
||||
return
|
||||
}
|
||||
logDebug("GOT +EVENT:SocketDown," + id + "," + string(parts[2]))
|
||||
d.pos = 0
|
||||
data := make([]byte, len(parts[3]))
|
||||
copy(data, parts[3])
|
||||
s.rx <- data
|
||||
|
||||
case bytes.HasPrefix(sofar, []byte("OK")):
|
||||
d.pos = 0
|
||||
logDebug("GOT OK")
|
||||
d.ok <- true
|
||||
|
||||
case bytes.HasPrefix(sofar, []byte("ERROR")):
|
||||
d.pos = 0
|
||||
logDebug("GOT ERROR")
|
||||
errStr := getErrStr(d.last)
|
||||
d.err <- errors.New(errStr)
|
||||
|
||||
case bytes.HasPrefix(sofar, []byte("+EVENT:")):
|
||||
d.pos = 0
|
||||
event := sofar[len("+EVENT:"):]
|
||||
d.handle(event)
|
||||
|
||||
default:
|
||||
// Catch everything else and store in d.last
|
||||
d.pos = 0
|
||||
size := len(sofar)
|
||||
if size > 0 {
|
||||
d.last = make([]byte, size)
|
||||
copy(d.last, sofar[:size])
|
||||
logDebug("GOT LINE " + string(d.last))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) serviceUART() {
|
||||
for {
|
||||
d.uartMu.Lock()
|
||||
for d.uart.Buffered() > 0 {
|
||||
if d.pos >= len(d.buf) {
|
||||
println("Trying to write past buffer")
|
||||
d.pos = 0
|
||||
break
|
||||
}
|
||||
var err error
|
||||
d.buf[d.pos], err = d.uart.ReadByte()
|
||||
if err == nil {
|
||||
d.pos++
|
||||
d.processUART()
|
||||
}
|
||||
}
|
||||
d.uartMu.Unlock()
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) NetConnect(params *netlink.ConnectParams) error {
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
d.uart = d.cfg.Uart
|
||||
d.uart.Configure(machine.UARTConfig{
|
||||
BaudRate: d.cfg.BaudRate,
|
||||
TX: d.cfg.Tx,
|
||||
RX: d.cfg.Rx,
|
||||
})
|
||||
|
||||
go d.serviceUART()
|
||||
|
||||
fmt.Printf("\r\n")
|
||||
fmt.Printf("TinyGo Combo-AT WiFi network device driver\r\n")
|
||||
|
||||
fmt.Printf("\r\n")
|
||||
fmt.Printf("Driver version : %s\r\n", drivers.Version)
|
||||
|
||||
if len(params.Ssid) == 0 {
|
||||
return netlink.ErrMissingSSID
|
||||
}
|
||||
|
||||
// AT Test to see if device is alive
|
||||
if err := d.execute("AT", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Disable echo
|
||||
if err := d.execute("ATE0", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get FW version
|
||||
if err := d.execute("AT+GMR", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Combo-AT firmware version : %s\r\n", d.getFWVersion())
|
||||
|
||||
// Get/save MAC addresses
|
||||
if err := d.execute("AT+CIPSTAMAC_DEF?", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
d.saveMAC()
|
||||
fmt.Printf("MAC address : %s\r\n", d.mac.String())
|
||||
|
||||
// Set country code US
|
||||
if err := d.execute("AT+WCOUNTRY=4", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get country code
|
||||
if err := d.execute("AT+WCOUNTRY?", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("WiFi country code : %s\r\n", d.getCountry())
|
||||
|
||||
// Set Wi-Fi working mode to STA and save to flash
|
||||
if err := d.execute("AT+WMODE=1,1", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect to Wifi AP (keep trying until connected)
|
||||
fmt.Printf("\r\n")
|
||||
cmd := "AT+WJAP=" + params.Ssid + "," + params.Passphrase
|
||||
|
||||
for {
|
||||
fmt.Printf("Connecting to WiFi SSID '%s'...", params.Ssid)
|
||||
if err := d.execute(cmd, 20000); err != nil {
|
||||
fmt.Printf("FAILED (%s)\r\n", err.Error())
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Printf("CONNECTED\r\n")
|
||||
|
||||
// Automatically reconnect to Wi-Fi after power on
|
||||
if err := d.execute("AT+WAUTOCONN=1", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get/save IP/gateway addresses
|
||||
if err := d.execute("AT+WJAP?", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
d.saveIP()
|
||||
|
||||
fmt.Printf("\r\n")
|
||||
fmt.Printf("DHCP-assigned IP : %s\r\n", d.ip)
|
||||
fmt.Printf("DHCP-assigned gateway : %s\r\n", d.gateway)
|
||||
fmt.Printf("\r\n")
|
||||
|
||||
// Set socket receiving mode to active
|
||||
if err := d.execute("AT+SOCKETRECVCFG=1", 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *device) NetDisconnect() {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
// Disconnect from WiFi AP
|
||||
d.execute("AT+WDISCONNECT", 1000)
|
||||
}
|
||||
|
||||
func (d *device) NetNotify(cb func(netlink.Event)) {
|
||||
fmt.Printf("\r\n%s\r\n", netlink.ErrNotSupported)
|
||||
}
|
||||
|
||||
func (d *device) GetHardwareAddr() (net.HardwareAddr, error) {
|
||||
return d.mac, nil
|
||||
}
|
||||
|
||||
func (d *device) _getHostByName(name string) (ip netip.Addr, err error) {
|
||||
if err = d.execute("AT+WDOMAIN="+name, 1000); err != nil {
|
||||
return
|
||||
}
|
||||
ipStr := split(d.last, 1, ":", "host by name")
|
||||
return netip.ParseAddr(ipStr)
|
||||
}
|
||||
|
||||
func (d *device) GetHostByName(name string) (ip netip.Addr, err error) {
|
||||
|
||||
// If it's already a dotted-network address, and not a host name,
|
||||
// return it
|
||||
ip, err = netip.ParseAddr(name)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
return d._getHostByName(name)
|
||||
}
|
||||
|
||||
func (d *device) Addr() (netip.Addr, error) {
|
||||
return d.ip, nil
|
||||
}
|
||||
|
||||
func (d *device) Socket(domain, stype, 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
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
// Search for empty slot in sockets array
|
||||
for fd, s := range d.sockets {
|
||||
if s == nil {
|
||||
// Found one
|
||||
d.sockets[fd] = &socket{
|
||||
protocol: protocol,
|
||||
rx: make(chan []byte, 10),
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
}
|
||||
|
||||
return -1, netdev.ErrNoMoreSockets
|
||||
}
|
||||
|
||||
func (d *device) Bind(sockfd int, ip netip.AddrPort) error {
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.laddr = ip
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *device) Connect(sockfd int, host string, ip netip.AddrPort) error {
|
||||
|
||||
var addr string
|
||||
var cmd string
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if host == "" {
|
||||
addr = ip.Addr().String()
|
||||
} else {
|
||||
ip, err := d._getHostByName(host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr = ip.String()
|
||||
}
|
||||
port := strconv.Itoa(int(ip.Port()))
|
||||
|
||||
switch s.protocol {
|
||||
case netdev.IPPROTO_UDP:
|
||||
cmd = "AT+SOCKET=2," + addr + "," + port
|
||||
case netdev.IPPROTO_TCP:
|
||||
cmd = "AT+SOCKET=4," + addr + "," + port
|
||||
case netdev.IPPROTO_TLS:
|
||||
cmd = "AT+SOCKET=7," + addr + "," + port
|
||||
}
|
||||
|
||||
if cmd == "" {
|
||||
return netdev.ErrProtocolNotSupported
|
||||
}
|
||||
|
||||
if err := d.execute(cmd, 20000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.id = split(d.last, 1, "=", "connection ID")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *device) Listen(sockfd, backlog int) error {
|
||||
|
||||
// TODO Creating a TCP server socket isn't working when in STA mode,
|
||||
// TODO returning error "Socket bind error".
|
||||
// TODO The reference example shows a TCP server example in AP mode.
|
||||
|
||||
/*
|
||||
var cmd string
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
port := strconv.Itoa(int(s.laddr.Port()))
|
||||
|
||||
switch s.protocol {
|
||||
case netdev.IPPROTO_UDP:
|
||||
cmd = "AT+SOCKET=1," + port
|
||||
case netdev.IPPROTO_TCP:
|
||||
cmd = "AT+SOCKET=3," + port
|
||||
}
|
||||
|
||||
if cmd == "" {
|
||||
return netdev.ErrProtocolNotSupported
|
||||
}
|
||||
|
||||
if err := d.execute(cmd, 20000); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.id = split(d.last, 1, "=", "connection ID")
|
||||
*/
|
||||
|
||||
return netdev.ErrNotSupported
|
||||
}
|
||||
|
||||
func (d *device) Accept(sockfd int) (int, netip.AddrPort, error) {
|
||||
return 0, netip.AddrPort{}, netdev.ErrNotSupported
|
||||
}
|
||||
|
||||
func (d *device) Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("AT+SOCKETSEND=%s,%d", s.id, len(buf))
|
||||
|
||||
if err := d.send(cmd, 1000); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// AT+SOCKETSEND will sub-packet send data into 1024-byte chunks,
|
||||
// automatically, so send the full buffer in one shot, even if it's
|
||||
// bigger than 1024 bytes.
|
||||
|
||||
d.uartMu.Lock()
|
||||
n, err := d.uart.Write(buf)
|
||||
d.uartMu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Expecting "OK" after good send, or "ERROR"
|
||||
|
||||
t := time.NewTicker(time.Duration(1000) * time.Millisecond)
|
||||
defer t.Stop()
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
return 0, errors.New("Timed out")
|
||||
case <-d.ok:
|
||||
return n, nil
|
||||
case err = <-d.err:
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
func (d *device) Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 1. Use leftover data first
|
||||
if len(s.remainder) > 0 {
|
||||
n := copy(buf, s.remainder)
|
||||
s.remainder = s.remainder[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// 2. Get new data from the channel
|
||||
data, ok := <-s.rx
|
||||
if !ok {
|
||||
// Socket closed, return EOF
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
// 3. Copy data, handle leftovers
|
||||
n := copy(buf, data)
|
||||
if n < len(data) {
|
||||
s.remainder = data[n:]
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (d *device) Close(sockfd int) error {
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
s, err := d.getSocket(sockfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete socket only if connection was successful (s.id is set)
|
||||
if s.id != "" {
|
||||
cmd := fmt.Sprintf("AT+SOCKETDEL=%s", s.id)
|
||||
if err = d.execute(cmd, 1000); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d.sockets[sockfd] = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *device) SetSockOpt(sockfd, level, opt int, value interface{}) error {
|
||||
return netdev.ErrNotSupported
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package comboat
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var errStrings = map[int]string{
|
||||
|
||||
// System framework related error codes
|
||||
|
||||
0: "success",
|
||||
1: "The command is not supported (the combo framework contains the command but the current platform has not transplanted or adapted to support it)",
|
||||
2: "The command parameters contain unsupported operations (the current platform only supports some operations for this command)",
|
||||
3: "The instruction format is incorrect (this refers to the wrong number of parameters, for example, two parameters are required, but only one parameter is entered)",
|
||||
4: "Parameter error (the content of the parameter is wrong, for example, a number between 0 and 9 is required, but 10 or xyz is passed in, which is a parameter error)",
|
||||
5: "Parameter length error (command length exceeds the maximum supported length)",
|
||||
31: "The current command has not ended and needs to report the status asynchronously. This value is used by the state machine to determine the use of the command and no message is returned.",
|
||||
32: "Unknown error (or unhandled error type)",
|
||||
|
||||
// Common error codes
|
||||
|
||||
33: "malloc error",
|
||||
34: "Failed to read buf",
|
||||
35: "Failed to write buf",
|
||||
36: "Configuration error (configuration error loaded from memory, for example, we set port -1 for OTA upgrade, and check port error when executing AT+OTA, then configuration error will be reported)",
|
||||
37: "Failed to create task",
|
||||
38: "Flash read and write failure",
|
||||
39: "Serial port configuration error, unsupported baud rate",
|
||||
40: "Serial port configuration error, unsupported data bits",
|
||||
41: "Serial port configuration error, unsupported stop bit",
|
||||
42: "Serial port configuration error, unsupported parity bit",
|
||||
43: "Serial port configuration error, unsupported flow control",
|
||||
44: "Serial port configuration failed",
|
||||
45: "Wrong username/password",
|
||||
46: "Low power mode error or unsupported low power mode",
|
||||
47: "Uninitialized configuration data error (including io mapping data)",
|
||||
63: "General error code (without other information)",
|
||||
|
||||
// Wi-Fi related error codes
|
||||
|
||||
64: "Wi-Fi not initialized or initialization failed",
|
||||
65: "Wi-Fi mode error (unable to connect to Wi-Fi in single AP mode)",
|
||||
66: "Wi-Fi connection failed",
|
||||
67: "Wi-Fi connection successful, error in obtaining IP (DHCP)",
|
||||
68: "Failed to obtain encryption method",
|
||||
69: "The specified AP was not found.",
|
||||
70: "Wi-Fi scan start failed",
|
||||
71: "Wi-Fi scan timeout",
|
||||
72: "Failed to enable AP hotspot",
|
||||
73: "Failed to obtain the Wi-Fi information of the router or the AP information that you enabled yourself",
|
||||
74: "The network card (STA/AP) is not running",
|
||||
75: "Wi-Fi country code error (unsupported Wi-Fi country code)",
|
||||
76: "The current network configuration mode is wrong.",
|
||||
95: "Wi-Fi connection unknown error",
|
||||
|
||||
// Socket related error codes
|
||||
|
||||
96: "Failed to create socket",
|
||||
97: "Socket connection failed",
|
||||
98: "DNS Failure",
|
||||
99: "The socket status is wrong (for example, TCP is not connected yet)",
|
||||
100: "Socket type error",
|
||||
101: "Socket send failed",
|
||||
102: "Socket receive failed",
|
||||
103: "Socket monitoring thread creation failed",
|
||||
104: "Socket bind error",
|
||||
105: "The current connection cannot be transparently linked (wrong socket type or number)",
|
||||
106: "PING test failed (all packets lost)",
|
||||
107: "Wi-Fi country code error (unsupported Wi-Fi country code)",
|
||||
108: "SSL Config Error",
|
||||
109: "SSL verification error (usually caused by unsupported SSL encryption type or certificate error)",
|
||||
127: "Unknown socket error",
|
||||
}
|
||||
|
||||
func getErrStr(errLine []byte) (errStr string) {
|
||||
errStr = "Can't parse ERROR response"
|
||||
tokens := bytes.Split(errLine, []byte(":"))
|
||||
if len(tokens) > 1 {
|
||||
errCode, err := strconv.Atoi(string(tokens[1]))
|
||||
if err == nil {
|
||||
errStr = errStrings[errCode]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
+1
-1
@@ -49,7 +49,7 @@ func Sleep(duration time.Duration) {
|
||||
// * The CPU frequency is lower than 256MHz. If it is higher, long sleep
|
||||
// times (1-16ms) may not work correctly.
|
||||
cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000
|
||||
slept := C.tinygo_drivers_sleep(cycles)
|
||||
slept := C.tinygo_drivers_sleep(C.uint32_t(cycles))
|
||||
if !slept {
|
||||
// Fallback for platforms without inline assembly support.
|
||||
time.Sleep(duration)
|
||||
|
||||
+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
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package easystepper // import "tinygo.org/x/drivers/easystepper"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
// StepMode determines the coil sequence used to perform a single step
|
||||
@@ -30,28 +30,10 @@ func (sm StepMode) stepCount() uint {
|
||||
}
|
||||
}
|
||||
|
||||
// DeviceConfig contains the configuration data for a single easystepper driver
|
||||
type DeviceConfig struct {
|
||||
// Pin1 ... Pin4 determines the pins to configure and use for the device
|
||||
Pin1, Pin2, Pin3, Pin4 machine.Pin
|
||||
// StepCount is the number of steps required to perform a full revolution of the stepper motor
|
||||
StepCount uint
|
||||
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
|
||||
RPM uint
|
||||
// Mode determines the coil sequence used to perform a single step
|
||||
Mode StepMode
|
||||
}
|
||||
|
||||
// DualDeviceConfig contains the configuration data for a dual easystepper driver
|
||||
type DualDeviceConfig struct {
|
||||
DeviceConfig
|
||||
// Pin5 ... Pin8 determines the pins to configure and use for the second device
|
||||
Pin5, Pin6, Pin7, Pin8 machine.Pin
|
||||
}
|
||||
|
||||
// Device holds the pins and the delay between steps
|
||||
type Device struct {
|
||||
pins [4]machine.Pin
|
||||
pins [4]pin.OutputFunc
|
||||
config func()
|
||||
stepDelay time.Duration
|
||||
stepNumber uint8
|
||||
stepMode StepMode
|
||||
@@ -62,51 +44,6 @@ type DualDevice struct {
|
||||
devices [2]*Device
|
||||
}
|
||||
|
||||
// New returns a new single easystepper driver given a DeviceConfig
|
||||
func New(config DeviceConfig) (*Device, error) {
|
||||
if config.StepCount == 0 || config.RPM == 0 {
|
||||
return nil, errors.New("config.StepCount and config.RPM must be > 0")
|
||||
}
|
||||
return &Device{
|
||||
pins: [4]machine.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
|
||||
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
|
||||
stepMode: config.Mode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Configure configures the pins of the Device
|
||||
func (d *Device) Configure() {
|
||||
for _, pin := range d.pins {
|
||||
pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
}
|
||||
|
||||
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
|
||||
func NewDual(config DualDeviceConfig) (*DualDevice, error) {
|
||||
// Create the first device
|
||||
dev1, err := New(config.DeviceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create the second device
|
||||
config.DeviceConfig.Pin1 = config.Pin5
|
||||
config.DeviceConfig.Pin2 = config.Pin6
|
||||
config.DeviceConfig.Pin3 = config.Pin7
|
||||
config.DeviceConfig.Pin4 = config.Pin8
|
||||
dev2, err := New(config.DeviceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Return composite dual device
|
||||
return &DualDevice{devices: [2]*Device{dev1, dev2}}, nil
|
||||
}
|
||||
|
||||
// Configure configures the pins of the DualDevice
|
||||
func (d *DualDevice) Configure() {
|
||||
d.devices[0].Configure()
|
||||
d.devices[1].Configure()
|
||||
}
|
||||
|
||||
// Move rotates the motor the number of given steps
|
||||
// (negative steps will rotate it the opposite direction)
|
||||
func (d *Device) Move(steps int32) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package easystepper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
func NewCrossPlatform(stepcount, rpm uint, mode StepMode, pins [4]pin.OutputFunc) (*Device, error) {
|
||||
if stepcount == 0 || rpm == 0 {
|
||||
return nil, errors.New("zero rpm and/or stepcount")
|
||||
}
|
||||
for i := range pins {
|
||||
if pins[i] == nil {
|
||||
return nil, errors.New("nil pin")
|
||||
}
|
||||
}
|
||||
d := &Device{
|
||||
pins: pins,
|
||||
stepDelay: time.Second * 60 / time.Duration((stepcount * rpm)),
|
||||
stepMode: mode,
|
||||
config: func() {},
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//go:build baremetal
|
||||
|
||||
package easystepper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/internal/legacy"
|
||||
"tinygo.org/x/drivers/internal/pin"
|
||||
)
|
||||
|
||||
// New returns a new single easystepper driver given a DeviceConfig
|
||||
func New(config DeviceConfig) (*Device, error) {
|
||||
if config.StepCount == 0 || config.RPM == 0 {
|
||||
return nil, errors.New("config.StepCount and config.RPM must be > 0")
|
||||
}
|
||||
return &Device{
|
||||
pins: [4]pin.OutputFunc{config.Pin1.Set, config.Pin2.Set, config.Pin3.Set, config.Pin4.Set},
|
||||
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
|
||||
stepMode: config.Mode,
|
||||
config: func() {
|
||||
legacy.ConfigurePinOut(config.Pin1)
|
||||
legacy.ConfigurePinOut(config.Pin2)
|
||||
legacy.ConfigurePinOut(config.Pin3)
|
||||
legacy.ConfigurePinOut(config.Pin4)
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Configure configures the pins of the Device
|
||||
func (d *Device) Configure() {
|
||||
if d.config == nil {
|
||||
panic(legacy.ErrConfigBeforeInstantiated)
|
||||
}
|
||||
d.config()
|
||||
}
|
||||
|
||||
// Configure configures the pins of the DualDevice
|
||||
func (d *DualDevice) Configure() {
|
||||
d.devices[0].Configure()
|
||||
d.devices[1].Configure()
|
||||
}
|
||||
|
||||
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
|
||||
func NewDual(config DualDeviceConfig) (*DualDevice, error) {
|
||||
// Create the first device
|
||||
dev1, err := New(config.DeviceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create the second device
|
||||
config.DeviceConfig.Pin1 = config.Pin5
|
||||
config.DeviceConfig.Pin2 = config.Pin6
|
||||
config.DeviceConfig.Pin3 = config.Pin7
|
||||
config.DeviceConfig.Pin4 = config.Pin8
|
||||
dev2, err := New(config.DeviceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Return composite dual device
|
||||
return &DualDevice{devices: [2]*Device{dev1, dev2}}, nil
|
||||
}
|
||||
|
||||
// DeviceConfig contains the configuration data for a single easystepper driver
|
||||
type DeviceConfig struct {
|
||||
// Pin1 ... Pin4 determines the pins to configure and use for the device
|
||||
Pin1, Pin2, Pin3, Pin4 machine.Pin
|
||||
// StepCount is the number of steps required to perform a full revolution of the stepper motor
|
||||
StepCount uint
|
||||
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
|
||||
RPM uint
|
||||
// Mode determines the coil sequence used to perform a single step
|
||||
Mode StepMode
|
||||
}
|
||||
|
||||
// DualDeviceConfig contains the configuration data for a dual easystepper driver
|
||||
type DualDeviceConfig struct {
|
||||
DeviceConfig
|
||||
// Pin5 ... Pin8 determines the pins to configure and use for the second device
|
||||
Pin5, Pin6, Pin7, Pin8 machine.Pin
|
||||
}
|
||||
@@ -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 || rp2350 || 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))
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
// Package ens160 provides a driver for the ScioSense ENS160 digital gas sensor.
|
||||
//
|
||||
// Datasheet: https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
|
||||
package ens160
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeout = 30 * time.Millisecond
|
||||
shortTimeout = 1 * time.Millisecond
|
||||
)
|
||||
|
||||
// Conversion constants for environment data compensation.
|
||||
const (
|
||||
kelvinOffsetMilli = 273150 // 273.15 K in milli-units
|
||||
tempRawFactor = 64 // As per datasheet for TEMP_IN
|
||||
humRawFactor = 512 // As per datasheet for RH_IN
|
||||
milliFactor = 1000 // For converting from milli-units
|
||||
roundingTerm = milliFactor / 2 // For rounding before integer division
|
||||
)
|
||||
|
||||
// validityStrings provides human-readable descriptions for validity flags.
|
||||
var validityStrings = [...]string{
|
||||
ValidityNormalOperation: "normal operation",
|
||||
ValidityWarmUpPhase: "warm-up phase, wait ~3 minutes for valid data",
|
||||
ValidityInitialStartUpPhase: "initial start-up phase, wait ~1 hour for valid data",
|
||||
ValidityInvalidOutput: "invalid output",
|
||||
}
|
||||
|
||||
// Device wraps an I2C connection to an ENS160 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C // I²C implementation
|
||||
addr uint16 // 7‑bit bus address, promoted to uint16 per drivers.I2C
|
||||
|
||||
// shadow registers / last measurements
|
||||
lastTvocPPB uint16
|
||||
lastEco2PPM uint16
|
||||
lastAqiUBA uint8
|
||||
lastValidity uint8 // Store the latest validity status
|
||||
|
||||
// pre‑allocated buffers
|
||||
wbuf [5]byte // longest write: reg + 4 bytes (TEMP+RH)
|
||||
rbuf [5]byte // longest read: DATA burst (5 bytes)
|
||||
}
|
||||
|
||||
// New returns a new ENS160 driver.
|
||||
func New(bus drivers.I2C, addr uint16) *Device {
|
||||
if addr == 0 {
|
||||
addr = DefaultAddress
|
||||
}
|
||||
return &Device{
|
||||
bus: bus,
|
||||
addr: addr,
|
||||
lastValidity: ValidityInvalidOutput,
|
||||
}
|
||||
}
|
||||
|
||||
// Connected returns whether a ENS160 has been found.
|
||||
func (d *Device) Connected() bool {
|
||||
d.wbuf[0] = regPartID
|
||||
err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:2])
|
||||
return err == nil && d.rbuf[0] == LowPartID && d.rbuf[1] == HighPartID
|
||||
}
|
||||
|
||||
// Configure sets up the device for reading.
|
||||
func (d *Device) Configure() error {
|
||||
// 1. Soft-reset. The device will automatically enter IDLE mode.
|
||||
if err := d.write1(regOpMode, ModeReset); err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(defaultTimeout)
|
||||
|
||||
// 2. Clear GPR registers, then go to STANDARD mode.
|
||||
if err := d.write1(regCommand, cmdClrGPR); err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(defaultTimeout)
|
||||
|
||||
if err := d.write1(regOpMode, ModeStandard); err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(defaultTimeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// calculateTempRaw converts temperature from milli-degrees Celsius to the sensor's raw format.
|
||||
func calculateTempRaw(tempMilliC int32) uint16 {
|
||||
// Clip temperature
|
||||
const (
|
||||
minC = -40 * 1000
|
||||
maxC = 85 * 1000
|
||||
)
|
||||
if tempMilliC < minC {
|
||||
tempMilliC = minC
|
||||
} else if tempMilliC > maxC {
|
||||
tempMilliC = maxC
|
||||
}
|
||||
|
||||
// Integer fixed-point conversion to format required by the sensor.
|
||||
// Formula from datasheet: T_IN = (T_ambient_C + 273.15) * 64
|
||||
return uint16((((tempMilliC + kelvinOffsetMilli) * tempRawFactor) + roundingTerm) / milliFactor)
|
||||
}
|
||||
|
||||
// calculateHumRaw converts relative humidity from milli-percent to the sensor's raw format.
|
||||
func calculateHumRaw(rhMilliPct int32) uint16 {
|
||||
// Clip humidity
|
||||
if rhMilliPct < 0 {
|
||||
rhMilliPct = 0
|
||||
} else if rhMilliPct > 100*1000 {
|
||||
rhMilliPct = 100 * 1000
|
||||
}
|
||||
|
||||
// Integer fixed-point conversion to format required by the sensor.
|
||||
// Formula from datasheet: RH_IN = (RH_ambient_% * 512)
|
||||
return uint16(((rhMilliPct * humRawFactor) + roundingTerm) / milliFactor)
|
||||
}
|
||||
|
||||
// SetEnvDataMilli sets the ambient temperature and humidity for compensation.
|
||||
//
|
||||
// tempMilliC is the temperature in milli-degrees Celsius.
|
||||
// rhMilliPct is the relative humidity in milli-percent.
|
||||
func (d *Device) SetEnvDataMilli(tempMilliC, rhMilliPct int32) error {
|
||||
tempRaw := calculateTempRaw(tempMilliC)
|
||||
humRaw := calculateHumRaw(rhMilliPct)
|
||||
|
||||
d.wbuf[0] = regTempIn // start address (auto‑increment)
|
||||
binary.LittleEndian.PutUint16(d.wbuf[1:3], tempRaw)
|
||||
binary.LittleEndian.PutUint16(d.wbuf[3:5], humRaw)
|
||||
|
||||
return d.bus.Tx(d.addr, d.wbuf[:5], nil)
|
||||
}
|
||||
|
||||
// Update refreshes the concentration measurements.
|
||||
func (d *Device) Update(which drivers.Measurement) error {
|
||||
if which&drivers.Concentration == 0 {
|
||||
return nil // nothing requested
|
||||
}
|
||||
|
||||
const maxTries = 1000
|
||||
var (
|
||||
status uint8
|
||||
validity uint8
|
||||
)
|
||||
var gotData bool
|
||||
|
||||
// Poll DEVICE_STATUS until NEWDAT or timeout
|
||||
for range maxTries {
|
||||
var err error
|
||||
status, err = d.read1(regStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status&statusSTATER != 0 {
|
||||
return errors.New("ENS160: error (STATER set)")
|
||||
}
|
||||
validity = (status & statusValidityMask) >> statusValidityShift
|
||||
|
||||
if status&statusNEWDAT != 0 {
|
||||
gotData = true
|
||||
break // Always break when data available
|
||||
}
|
||||
time.Sleep(shortTimeout)
|
||||
}
|
||||
if !gotData {
|
||||
return errors.New("ENS160: timeout waiting for NEWDAT")
|
||||
}
|
||||
|
||||
// Burst-read data regardless of validity state
|
||||
d.wbuf[0] = regAQI
|
||||
if err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:5]); err != nil {
|
||||
return errors.New("ENS160: burst read failed")
|
||||
}
|
||||
|
||||
d.lastAqiUBA = d.rbuf[0]
|
||||
d.lastTvocPPB = binary.LittleEndian.Uint16(d.rbuf[1:3])
|
||||
d.lastEco2PPM = binary.LittleEndian.Uint16(d.rbuf[3:5])
|
||||
d.lastValidity = validity // Store the validity status
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TVOC returns the last total‑VOC concentration in parts‑per‑billion.
|
||||
func (d *Device) TVOC() uint16 { return d.lastTvocPPB }
|
||||
|
||||
// ECO2 returns the last equivalent CO₂ concentration in parts‑per‑million.
|
||||
func (d *Device) ECO2() uint16 { return d.lastEco2PPM }
|
||||
|
||||
// AQI returns the last Air‑Quality Index according to UBA (1–5).
|
||||
func (d *Device) AQI() uint8 { return d.lastAqiUBA }
|
||||
|
||||
// Validity returns the current operating state of the sensor.
|
||||
func (d *Device) Validity() uint8 {
|
||||
return d.lastValidity
|
||||
}
|
||||
|
||||
// ValidityString returns a human-readable string describing the current validity status.
|
||||
func (d *Device) ValidityString() string {
|
||||
if int(d.lastValidity) < len(validityStrings) {
|
||||
return validityStrings[d.lastValidity]
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// write1 writes a single byte to a register.
|
||||
func (d *Device) write1(reg, val uint8) error {
|
||||
d.wbuf[0] = reg
|
||||
d.wbuf[1] = val
|
||||
return d.bus.Tx(d.addr, d.wbuf[:2], nil)
|
||||
}
|
||||
|
||||
// read1 reads a single byte from a register.
|
||||
func (d *Device) read1(reg uint8) (uint8, error) {
|
||||
d.wbuf[0] = reg
|
||||
if err := d.bus.Tx(d.addr, d.wbuf[:1], d.rbuf[:1]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.rbuf[0], nil
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package ens160
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCalculateTempRaw(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
tempMilliC int32
|
||||
expectedRaw uint16
|
||||
}{
|
||||
{"25°C", 25000, 19082},
|
||||
{"-10.5°C", -10500, 16810},
|
||||
{"Min temp", -40000, 14922},
|
||||
{"Below min", -50000, 14922},
|
||||
{"Max temp", 85000, 22922},
|
||||
{"Above max", 90000, 22922},
|
||||
{"Zero", 0, 17482},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
raw := calculateTempRaw(tc.tempMilliC)
|
||||
if raw != tc.expectedRaw {
|
||||
t.Errorf("expected %d, got %d", tc.expectedRaw, raw)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateHumRaw(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
rhMilliPct int32
|
||||
expectedRaw uint16
|
||||
}{
|
||||
{"50%", 50000, 25600},
|
||||
{"0%", 0, 0},
|
||||
{"100%", 100000, 51200},
|
||||
{"Below 0%", -10000, 0},
|
||||
{"Above 100%", 110000, 51200},
|
||||
{"33.3%", 33300, 17050},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
raw := calculateHumRaw(tc.rhMilliPct)
|
||||
if raw != tc.expectedRaw {
|
||||
t.Errorf("expected %d, got %d", tc.expectedRaw, raw)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package ens160
|
||||
|
||||
// DefaultAddress is the default I2C address for the ENS160 when the ADDR pin is
|
||||
// connected to high (3.3V). When connected to low (GND), the address is 0x52.
|
||||
const DefaultAddress = 0x53
|
||||
|
||||
// Registers
|
||||
const (
|
||||
regPartID = 0x00
|
||||
regOpMode = 0x10
|
||||
regConfig = 0x11
|
||||
regCommand = 0x12
|
||||
regTempIn = 0x13
|
||||
regRhIn = 0x15
|
||||
regStatus = 0x20
|
||||
regAQI = 0x21
|
||||
regTVOC = 0x22
|
||||
regECO2 = 0x24
|
||||
regDataT = 0x30
|
||||
regDataRH = 0x32
|
||||
regMISR = 0x38
|
||||
regGPRWrite = 0x40
|
||||
regGPRRead = 0x48
|
||||
)
|
||||
|
||||
// Operating modes
|
||||
const (
|
||||
ModeDeepSleep = 0x00
|
||||
ModeIdle = 0x01
|
||||
ModeStandard = 0x02
|
||||
ModeReset = 0xF0
|
||||
)
|
||||
|
||||
// Status register bits
|
||||
const (
|
||||
statusSTATAS = 1 << 7
|
||||
statusSTATER = 1 << 6
|
||||
|
||||
statusValidityMask = 0x0C
|
||||
statusValidityShift = 2
|
||||
|
||||
statusNEWDAT = 1 << 1
|
||||
statusNEWGPR = 1 << 0
|
||||
)
|
||||
|
||||
// Validity flags
|
||||
const (
|
||||
ValidityNormalOperation = 0x00
|
||||
ValidityWarmUpPhase = 0x01 // need ~3 minutes until valid data
|
||||
ValidityInitialStartUpPhase = 0x02 // need ~1 hour until valid data
|
||||
ValidityInvalidOutput = 0x03
|
||||
)
|
||||
|
||||
// Commands
|
||||
const (
|
||||
cmdNOP = 0x00
|
||||
cmdGetAppVer = 0x0E
|
||||
cmdClrGPR = 0xCC
|
||||
)
|
||||
|
||||
// Part IDs
|
||||
const (
|
||||
LowPartID = 0x60
|
||||
HighPartID = 0x01
|
||||
)
|
||||
@@ -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,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/adafruit4650"
|
||||
"tinygo.org/x/tinyfont"
|
||||
"tinygo.org/x/tinyfont/freemono"
|
||||
)
|
||||
|
||||
func main() {
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
dev := adafruit4650.New(machine.I2C0)
|
||||
|
||||
err := dev.Configure()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
drawPlus(&dev)
|
||||
drawHelloWorld(&dev)
|
||||
|
||||
err = dev.Display()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func drawPlus(d drivers.Displayer) {
|
||||
for i := int16(0); i < 128; i++ {
|
||||
d.SetPixel(i, 32, color.RGBA{R: 1})
|
||||
}
|
||||
for i := int16(0); i < 64; i++ {
|
||||
d.SetPixel(64, i, color.RGBA{R: 1})
|
||||
}
|
||||
}
|
||||
|
||||
func drawHelloWorld(d drivers.Displayer) {
|
||||
tinyfont.WriteLine(d, &freemono.Regular9pt7b, 0, 32, "Hello World!", color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Connects to an MAG3110 I2C magnetometer.
|
||||
// Connects to an DS3231 I2C Real Time Clock (RTC).
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build macropad_rp2040
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/encoders"
|
||||
)
|
||||
|
||||
var (
|
||||
enc = encoders.NewQuadratureViaInterrupt(machine.ROT_A, machine.ROT_B)
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
enc.Configure(encoders.QuadratureConfig{
|
||||
Precision: 4,
|
||||
})
|
||||
|
||||
for oldValue := 0; ; {
|
||||
if newValue := enc.Position(); newValue != oldValue {
|
||||
println("value: ", newValue)
|
||||
oldValue = newValue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// This example demonstrates ENS160 usage.
|
||||
//
|
||||
// Wiring:
|
||||
// - VCC to 3.3V, GND to ground
|
||||
// - SDA to board SDA, SCL to board SCL
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/ens160"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := machine.I2C0.Configure(machine.I2CConfig{
|
||||
Frequency: 400 * machine.KHz,
|
||||
})
|
||||
if err != nil {
|
||||
println("Failed to configure I2C:", err)
|
||||
}
|
||||
|
||||
dev := ens160.New(machine.I2C0, ens160.DefaultAddress)
|
||||
|
||||
connected := dev.Connected()
|
||||
if !connected {
|
||||
println("ENS160 not detected")
|
||||
return
|
||||
}
|
||||
println("ENS160 detected")
|
||||
|
||||
if err := dev.Configure(); err != nil {
|
||||
println("Failed to configure ENS160:", err)
|
||||
}
|
||||
|
||||
for {
|
||||
err := dev.Update(drivers.Concentration)
|
||||
if err != nil {
|
||||
println("Error reading ENS160: %v\n", err)
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
println(
|
||||
"AQI:", dev.AQI(),
|
||||
"TVOC:", dev.TVOC(),
|
||||
"eCO2:", dev.ECO2(),
|
||||
"Validity:", dev.ValidityString(),
|
||||
)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func main() {
|
||||
console_example.RunFor(
|
||||
flash.NewSPI(
|
||||
&machine.SPI1,
|
||||
machine.SPI1,
|
||||
machine.SPI1_SDO_PIN,
|
||||
machine.SPI1_SDI_PIN,
|
||||
machine.SPI1_SCK_PIN,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func main() {
|
||||
println("GPS I2C Example")
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
ublox := gps.NewI2C(machine.I2C0)
|
||||
ublox := gps.NewI2CWithAddress(machine.I2C0, gps.UBLOX_I2C_ADDRESS)
|
||||
parser := gps.NewParser()
|
||||
var fix gps.Fix
|
||||
for {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/honeyhsc"
|
||||
)
|
||||
|
||||
// Data taken from https://github.com/rodan/honeywell_hsc_ssc_i2c/blob/master/hsc_ssc_i2c.cpp
|
||||
// these defaults are valid for the HSCMRNN030PA2A3 chip
|
||||
const (
|
||||
i2cAddress = 0x28
|
||||
// 10%
|
||||
outputMinimum = 0x666
|
||||
// 90% of 2^14 - 1
|
||||
outputMax = 0x399A
|
||||
// min is 0 for sensors that give absolute values
|
||||
pressureMin = 0
|
||||
// 30psi (and we want results in millipascals)
|
||||
// pressureMax = 206842.7
|
||||
pressureMax = 206843 * 1000
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := machine.I2C0
|
||||
err := bus.Configure(machine.I2CConfig{
|
||||
Frequency: 400_000, // 100kHz minimum and 400kHz I2C maximum clock. 50 to 800 for SPI.
|
||||
SDA: machine.I2C0_SDA_PIN,
|
||||
SCL: machine.I2C0_SCL_PIN,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
sensor := honeyhsc.NewDevI2C(bus, i2cAddress, outputMinimum, outputMax, pressureMin, pressureMax)
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
const measuremask = drivers.Pressure | drivers.Temperature
|
||||
err := sensor.Update(measuremask)
|
||||
if err != nil {
|
||||
println("error updating measurements:", err.Error())
|
||||
continue
|
||||
}
|
||||
P := sensor.Pressure()
|
||||
T := sensor.Temperature()
|
||||
println("pressure:", P, "temperature:", T)
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,16 @@ import (
|
||||
"tinygo.org/x/drivers/examples/ili9341/initdisplay"
|
||||
"tinygo.org/x/drivers/examples/ili9341/pyportal_boing/graphics"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
"tinygo.org/x/drivers/pixel"
|
||||
)
|
||||
|
||||
const (
|
||||
BGCOLOR = 0xAD75
|
||||
GRIDCOLOR = 0xA815
|
||||
BGSHADOW = 0x5285
|
||||
GRIDSHADOW = 0x600C
|
||||
RED = 0xF800
|
||||
WHITE = 0xFFFF
|
||||
BGCOLOR = pixel.RGB565BE(0x75AD)
|
||||
GRIDCOLOR = pixel.RGB565BE(0x15A8)
|
||||
BGSHADOW = pixel.RGB565BE(0x8552)
|
||||
GRIDSHADOW = pixel.RGB565BE(0x0C60)
|
||||
RED = pixel.RGB565BE(0x00F8)
|
||||
WHITE = pixel.RGB565BE(0xFFFF)
|
||||
|
||||
YBOTTOM = 123 // Ball Y coord at bottom
|
||||
YBOUNCE = -3.5 // Upward velocity on ball bounce
|
||||
@@ -25,7 +26,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8) * 2]uint8{}
|
||||
frameBuffer = pixel.NewImage[pixel.RGB565BE](graphics.BALLWIDTH+8, graphics.BALLHEIGHT+8)
|
||||
|
||||
startTime int64
|
||||
frame int64
|
||||
@@ -41,7 +42,7 @@ var (
|
||||
balloldy float32
|
||||
|
||||
// Color table for ball rotation effect
|
||||
palette [16]uint16
|
||||
palette [16]pixel.RGB565BE
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -108,6 +109,7 @@ func main() {
|
||||
|
||||
width = maxx - minx + 1
|
||||
height = maxy - miny + 1
|
||||
buffer := frameBuffer.Rescale(int(width), int(height))
|
||||
|
||||
// Ball animation frame # is incremented opposite the ball's X velocity
|
||||
ballframe -= ballvx * 0.5
|
||||
@@ -128,7 +130,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Only the changed rectangle is drawn into the 'renderbuf' array...
|
||||
var c uint16 //, *destPtr;
|
||||
var c pixel.RGB565BE //, *destPtr;
|
||||
bx := minx - int16(ballx) // X relative to ball bitmap (can be negative)
|
||||
by := miny - int16(bally) // Y relative to ball bitmap (can be negative)
|
||||
bgx := minx // X relative to background bitmap (>= 0)
|
||||
@@ -149,19 +151,20 @@ func main() {
|
||||
(by >= 0) && (by < graphics.BALLHEIGHT) { // inside the ball bitmap area?
|
||||
// Yes, do ball compositing math...
|
||||
p = graphics.Ball[int(by*(graphics.BALLWIDTH/2))+int(bx1/2)] // Get packed value (2 pixels)
|
||||
var nibble uint8
|
||||
if (bx1 & 1) != 0 {
|
||||
c = uint16(p & 0xF)
|
||||
nibble = p & 0xF
|
||||
} else {
|
||||
c = uint16(p >> 4)
|
||||
nibble = p >> 4
|
||||
} // Unpack high or low nybble
|
||||
if c == 0 { // Outside ball - just draw grid
|
||||
if nibble == 0 { // Outside ball - just draw grid
|
||||
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
||||
c = GRIDCOLOR
|
||||
} else {
|
||||
c = BGCOLOR
|
||||
}
|
||||
} else if c > 1 { // In ball area...
|
||||
c = palette[c]
|
||||
} else if nibble > 1 { // In ball area...
|
||||
c = palette[nibble]
|
||||
} else { // In shadow area...
|
||||
if graphics.Background[bgidx]&(0x80>>(bgx1&7)) != 0 {
|
||||
c = GRIDSHADOW
|
||||
@@ -176,8 +179,7 @@ func main() {
|
||||
c = BGCOLOR
|
||||
}
|
||||
}
|
||||
frameBuffer[(y*int(width)+x)*2] = byte(c >> 8)
|
||||
frameBuffer[(y*int(width)+x)*2+1] = byte(c)
|
||||
buffer.Set(x, y, c)
|
||||
bx1++ // Increment bitmap position counters (X axis)
|
||||
bgx1++
|
||||
}
|
||||
@@ -188,7 +190,7 @@ func main() {
|
||||
bgy++
|
||||
}
|
||||
|
||||
display.DrawRGBBitmap8(minx, miny, frameBuffer[:width*height*2], width, height)
|
||||
display.DrawBitmap(minx, miny, buffer)
|
||||
|
||||
// Show approximate frame rate
|
||||
frame++
|
||||
@@ -205,6 +207,7 @@ func DrawBackground() {
|
||||
w, h := display.Size()
|
||||
byteWidth := (w + 7) / 8 // Bitmap scanline pad = whole byte
|
||||
var b uint8
|
||||
buffer := frameBuffer.Rescale(int(w), 1)
|
||||
for j := int16(0); j < h; j++ {
|
||||
for k := int16(0); k < w; k++ {
|
||||
if k&7 > 0 {
|
||||
@@ -213,13 +216,11 @@ func DrawBackground() {
|
||||
b = graphics.Background[j*byteWidth+k/8]
|
||||
}
|
||||
if b&0x80 == 0 {
|
||||
frameBuffer[2*k] = byte(BGCOLOR >> 8)
|
||||
frameBuffer[2*k+1] = byte(BGCOLOR & 0xFF)
|
||||
buffer.Set(int(k), 0, BGCOLOR)
|
||||
} else {
|
||||
frameBuffer[2*k] = byte(GRIDCOLOR >> 8)
|
||||
frameBuffer[2*k+1] = byte(GRIDCOLOR & 0xFF)
|
||||
buffer.Set(int(k), 0, GRIDCOLOR)
|
||||
}
|
||||
}
|
||||
display.DrawRGBBitmap8(0, j, frameBuffer[0:w*2], w, 1)
|
||||
display.DrawBitmap(0, j, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -14,9 +14,18 @@ func main() {
|
||||
i2c.Configure(machine.I2CConfig{SCL: machine.SCL1_PIN, SDA: machine.SDA1_PIN})
|
||||
|
||||
accel := lis3dh.New(i2c)
|
||||
accel.Address = lis3dh.Address1 // address on the Circuit Playground Express
|
||||
accel.Configure()
|
||||
accel.SetRange(lis3dh.RANGE_2_G)
|
||||
err := accel.Configure(lis3dh.Config{
|
||||
Address: lis3dh.Address1, // address on the Circuit Playground Express
|
||||
})
|
||||
for err != nil {
|
||||
println("could not configure LIS3DH:", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
err = accel.SetRange(lis3dh.RANGE_2_G)
|
||||
for err != nil {
|
||||
println("could not set acceleration range:", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
println(accel.Connected())
|
||||
|
||||
|
||||
@@ -23,20 +23,20 @@ Builds/flashes atcmd console application with simulator instead of actual LoRa r
|
||||
tinygo flash -target pico ./examples/lora/lorawan/atcmd/
|
||||
```
|
||||
|
||||
## PyBadge with LoRa Featherwing
|
||||
## PyBadge with LoRa Featherwing for EU868 region
|
||||
|
||||
Builds/flashes atcmd console application on PyBadge using LoRa Featherwing (RFM95/SX1276).
|
||||
|
||||
```
|
||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/atcmd/
|
||||
tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/atcmd/
|
||||
```
|
||||
|
||||
## LoRa-E5
|
||||
## LoRa-E5 for US915 region
|
||||
|
||||
Builds/flashes atcmd console application on Lora-E5 using onboard SX126x.
|
||||
|
||||
```
|
||||
tinygo flash -target lorae5 ./examples/lora/lorawan/atcmd/
|
||||
tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/atcmd/
|
||||
```
|
||||
|
||||
## Joining a Public Lorawan Network
|
||||
|
||||
@@ -32,6 +32,8 @@ var (
|
||||
defaultTimeout uint32 = 1000
|
||||
)
|
||||
|
||||
var reg string
|
||||
|
||||
func main() {
|
||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||
|
||||
@@ -45,7 +47,16 @@ func main() {
|
||||
otaa = &lorawan.Otaa{}
|
||||
lorawan.UseRadio(radio)
|
||||
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
switch reg {
|
||||
case "AU915":
|
||||
lorawan.UseRegionSettings(region.AU915())
|
||||
case "EU868":
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
case "US915":
|
||||
lorawan.UseRegionSettings(region.US915())
|
||||
default:
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
}
|
||||
|
||||
for {
|
||||
if uart.Buffered() > 0 {
|
||||
|
||||
@@ -21,16 +21,16 @@ loraConnect: Connected !
|
||||
tinygo flash -target pico ./examples/lora/lorawan/basic-demo
|
||||
```
|
||||
|
||||
## PyBadge with LoRa Featherwing
|
||||
## PyBadge with LoRa Featherwing for EU868 region
|
||||
|
||||
```
|
||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/basic-demo
|
||||
tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/basic-demo
|
||||
```
|
||||
|
||||
## LoRa-E5
|
||||
## LoRa-E5 for US915 region
|
||||
|
||||
```
|
||||
tinygo flash -target lorae5 ./examples/lora/lorawan/basic-demo
|
||||
tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/basic-demo
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ import (
|
||||
"tinygo.org/x/drivers/lora/lorawan/region"
|
||||
)
|
||||
|
||||
var debug string
|
||||
var (
|
||||
reg string
|
||||
debug string
|
||||
)
|
||||
|
||||
const (
|
||||
LORAWAN_JOIN_TIMEOUT_SEC = 180
|
||||
@@ -67,8 +70,16 @@ func main() {
|
||||
|
||||
// Connect the lorawan with the Lora Radio device.
|
||||
lorawan.UseRadio(radio)
|
||||
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
switch reg {
|
||||
case "AU915":
|
||||
lorawan.UseRegionSettings(region.AU915())
|
||||
case "EU868":
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
case "US915":
|
||||
lorawan.UseRegionSettings(region.US915())
|
||||
default:
|
||||
lorawan.UseRegionSettings(region.EU868())
|
||||
}
|
||||
|
||||
// Configure AppEUI, DevEUI, APPKey, and public/private Lorawan Network
|
||||
setLorawanKeys()
|
||||
|
||||
@@ -23,13 +23,18 @@ func (sr *SimLoraRadio) Rx(timeoutMs uint32) ([]uint8, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
|
||||
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
|
||||
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
||||
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
||||
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
||||
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
||||
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
||||
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
|
||||
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
|
||||
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
||||
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
||||
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
||||
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
||||
func (sr *SimLoraRadio) SetHeaderType(headerType uint8) {}
|
||||
func (sr *SimLoraRadio) SetPreambleLength(pLen uint16) {}
|
||||
func (sr *SimLoraRadio) SetPublicNetwork(enabled bool) {}
|
||||
func (sr *SimLoraRadio) SetSyncWord(syncWord uint16) {}
|
||||
func (sr *SimLoraRadio) SetTxPower(txPower int8) {}
|
||||
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
||||
|
||||
func FirmwareVersion() string {
|
||||
return "simulator " + CurrentVersion()
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm303dlhc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// LSM303DLHC is connected to the I2C0 bus on Adafruit Feather M4 via pins: 20(SDA) and 21(SCL).
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
sensor := lsm303dlhc.New(machine.I2C0)
|
||||
//default settings
|
||||
err := sensor.Configure(lsm303dlhc.Configuration{
|
||||
AccelPowerMode: lsm303dlhc.ACCEL_POWER_NORMAL,
|
||||
AccelRange: lsm303dlhc.ACCEL_RANGE_2G,
|
||||
AccelDataRate: lsm303dlhc.ACCEL_DATARATE_100HZ,
|
||||
MagPowerMode: lsm303dlhc.MAG_POWER_NORMAL,
|
||||
MagSystemMode: lsm303dlhc.MAG_SYSTEM_CONTINUOUS,
|
||||
MagDataRate: lsm303dlhc.MAG_DATARATE_10HZ,
|
||||
})
|
||||
if err != nil {
|
||||
for {
|
||||
println("Failed to configure", err.Error())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
accel_x, accel_y, accel_z, err := sensor.ReadAcceleration()
|
||||
if err != nil {
|
||||
println("Failed to read accel", err.Error())
|
||||
}
|
||||
println("ACCEL_X:", accel_x, " ACCEL_Y:", accel_y, " ACCEL_Z:", accel_z)
|
||||
|
||||
mag_x, mag_y, mag_z, err := sensor.ReadMagneticField()
|
||||
if err != nil {
|
||||
println("Failed to read mag", err.Error())
|
||||
}
|
||||
println("MAG_X:", mag_x, " MAG_Y:", mag_y, " MAG_Z:", mag_z)
|
||||
|
||||
pitch, roll, _ := sensor.ReadPitchRoll()
|
||||
println("Pitch:", float32(pitch), " Roll:", float32(roll))
|
||||
|
||||
heading, _ := sensor.ReadCompass()
|
||||
println("Heading:", float32(heading), "degrees")
|
||||
|
||||
temp, _ := sensor.ReadTemperature()
|
||||
println("Temperature:", float32(temp)/1000, "*C")
|
||||
|
||||
println("\n")
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/max6675"
|
||||
)
|
||||
|
||||
// example for reading temperature from a thermocouple
|
||||
func main() {
|
||||
// Pins are for an Adafruit Feather nRF52840 Express
|
||||
machine.D5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.D5.High()
|
||||
|
||||
machine.SPI0.Configure(machine.SPIConfig{
|
||||
Frequency: 1_000_000,
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
})
|
||||
|
||||
thermocouple := max6675.NewDevice(machine.SPI0, machine.D5)
|
||||
|
||||
for {
|
||||
temp, err := thermocouple.Read()
|
||||
if err != nil {
|
||||
println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%0.02f C : %0.02f F\n", temp, (temp*9/5)+32)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@@ -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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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 || comboat_fw
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI0
|
||||
spi = machine.SPI0
|
||||
sckPin = machine.SPI0_SCK_PIN
|
||||
sdoPin = machine.SPI0_SDO_PIN
|
||||
sdiPin = machine.SPI0_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI1
|
||||
spi = machine.SPI1
|
||||
sckPin = machine.SDCARD_SCK_PIN
|
||||
sdoPin = machine.SDCARD_SDO_PIN
|
||||
sdiPin = machine.SDCARD_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI0
|
||||
spi = machine.SPI0
|
||||
sckPin = machine.SPI0_SCK_PIN
|
||||
sdoPin = machine.SPI0_SDO_PIN
|
||||
sdiPin = machine.SPI0_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SDCARD_SPI
|
||||
spi = machine.SDCARD_SPI
|
||||
sckPin = machine.SDCARD_SCK_PIN
|
||||
sdoPin = machine.SDCARD_SDO_PIN
|
||||
sdiPin = machine.SDCARD_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI0
|
||||
spi = machine.SPI0
|
||||
sckPin = machine.SPI0_SCK_PIN
|
||||
sdoPin = machine.SPI0_SDO_PIN
|
||||
sdiPin = machine.SPI0_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI0
|
||||
spi = machine.SPI0
|
||||
sckPin = machine.SPI0_SCK_PIN
|
||||
sdoPin = machine.SPI0_SDO_PIN
|
||||
sdiPin = machine.SPI0_SDI_PIN
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
spi = &machine.SPI2
|
||||
spi = machine.SPI2
|
||||
sckPin = machine.SCK2
|
||||
sdoPin = machine.SDO2
|
||||
sdiPin = machine.SDI2
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/seesaw"
|
||||
)
|
||||
|
||||
// example reading the position of a rotary encoder (4991) powered by a seesaw
|
||||
// https://learn.adafruit.com/adafruit-i2c-qt-rotary-encoder/arduino
|
||||
func main() {
|
||||
// This assumes you are using an Adafruit QT Py RP2040 for its Stemma QT connector
|
||||
// https://www.adafruit.com/product/4900
|
||||
i2c := machine.I2C1
|
||||
i2c.Configure(machine.I2CConfig{
|
||||
SCL: machine.I2C1_QT_SCL_PIN,
|
||||
SDA: machine.I2C1_QT_SDA_PIN,
|
||||
})
|
||||
|
||||
dev := seesaw.New(i2c)
|
||||
dev.Address = 0x36
|
||||
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
pos, err := dev.GetEncoderPosition(0, false)
|
||||
if err != nil {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
println(pos)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user