mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-02 14:07:48 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a15f2167cc | |||
| 5d5378a47c | |||
| 3ceb688663 | |||
| 941c1c9057 | |||
| d8c813d515 | |||
| 905fc6fce3 | |||
| 80913d5fe7 | |||
| b6c750ccd1 | |||
| 43899e1330 | |||
| 45c68ef0fc | |||
| 025a66655f | |||
| 121e8147f7 | |||
| b48bc5ac5d | |||
| 0d40c99d1f | |||
| bee7422c3a | |||
| 43099c5d5f | |||
| 0f9b9d873b | |||
| 114e24870e | |||
| b33c84ff78 | |||
| 966210f1b0 |
@@ -1,3 +1,29 @@
|
||||
0.19.0
|
||||
---
|
||||
- **new devices**
|
||||
- ft6336: add support for ft6336
|
||||
- pca9685: PCA9685 driver
|
||||
- shtc3: Sensirion SHTC3 Relative Humidity / Temperature i2c sensor
|
||||
- sx126x: Driver for Semtech sx126x radio modules
|
||||
- xpt2046: XPT2046 Touch driver (#350)
|
||||
- **enhancements**
|
||||
- **hd44780i2c**
|
||||
- clean up for go fmt
|
||||
- Needed fixes and update hd44780i2c.go
|
||||
- **ili9341, ili9342**
|
||||
- add support for m5stack
|
||||
- add support for m5stack-core2
|
||||
- **wifi**
|
||||
- modify to use shared net.Adapter interface for all supported wifi devices
|
||||
- wifinina: remove busy wait
|
||||
- **bugfixes**
|
||||
- **hd44780**
|
||||
- fix 4-bit data length flag
|
||||
- Reset data pins to output mode after reading
|
||||
- Nano 33 BLE drivers (#351)
|
||||
- **docs**
|
||||
- examples/wifi: add unified example for tcpclient that compiles for all supported wifi adaptors
|
||||
|
||||
0.18.0
|
||||
---
|
||||
- **new devices**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2021 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2022 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
|
||||
|
||||
@@ -117,6 +117,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
||||
@@ -187,8 +189,8 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||
@md5sum ./build/test.hex
|
||||
# tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||
# @md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
|
||||
@@ -215,12 +217,21 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
|
||||
@md5sum ./build/test.uf2
|
||||
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/basic/
|
||||
@md5sum ./build/test.elf
|
||||
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/touchpaint/
|
||||
@md5sum ./build/test.elf
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/sx126x/lora_rxtx/
|
||||
@md5sum ./build/test.hex
|
||||
|
||||
DRIVERS = $(wildcard */)
|
||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192
|
||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 \
|
||||
ft6336 sx126x
|
||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||
|
||||
unit-test:
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 74 devices are supported.
|
||||
The following 78 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|----------|-------------|
|
||||
@@ -78,6 +78,7 @@ The following 74 devices are supported.
|
||||
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
||||
| [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI |
|
||||
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
|
||||
| [FT6336 touch controller](https://focuslcds.com/content/FT6236.pdf) | I2C |
|
||||
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
|
||||
| [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO |
|
||||
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
|
||||
@@ -114,6 +115,7 @@ The following 74 devices are supported.
|
||||
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
|
||||
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||
| [SHTC3 Digital Humidity Sensor (RH/T)](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf) | I2C |
|
||||
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
||||
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
|
||||
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||
@@ -131,6 +133,8 @@ The following 74 devices are supported.
|
||||
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) | SPI |
|
||||
| [Waveshare 4.2" e-paper B/W display](https://www.waveshare.com/w/upload/6/6a/4.2inch-e-paper-specification.pdf) | SPI |
|
||||
| [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO |
|
||||
| [XPT2046 touch controller](http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) | GPIO |
|
||||
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-transceiv-ers/sx1261) | SPI |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+53
-46
@@ -57,6 +57,14 @@ type enableConfig struct {
|
||||
PON bool
|
||||
}
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
}
|
||||
|
||||
// Connected returns whether APDS-9960 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
@@ -65,52 +73,6 @@ func (d *Device) Connected() bool {
|
||||
return data[0] == 0xAB
|
||||
}
|
||||
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
d.DisableAll() // turn off everything
|
||||
|
||||
// "default" settings
|
||||
if cfg.ProximityPulseLength == 0 {
|
||||
cfg.ProximityPulseLength = 16
|
||||
}
|
||||
if cfg.ProximityPulseCount == 0 {
|
||||
cfg.ProximityPulseCount = 64
|
||||
}
|
||||
if cfg.GesturePulseLength == 0 {
|
||||
cfg.GesturePulseLength = 16
|
||||
}
|
||||
if cfg.GesturePulseCount == 0 {
|
||||
cfg.GesturePulseCount = 64
|
||||
}
|
||||
if cfg.ProximityGain == 0 {
|
||||
cfg.ProximityGain = 1
|
||||
}
|
||||
if cfg.GestureGain == 0 {
|
||||
cfg.GestureGain = 1
|
||||
}
|
||||
if cfg.ColorGain == 0 {
|
||||
cfg.ColorGain = 4
|
||||
}
|
||||
if cfg.ADCIntegrationCycles == 0 {
|
||||
cfg.ADCIntegrationCycles = 4
|
||||
}
|
||||
if cfg.threshold == 0 {
|
||||
d.gesture.threshold = 30
|
||||
}
|
||||
if cfg.sensitivity == 0 {
|
||||
d.gesture.sensitivity = 20
|
||||
}
|
||||
|
||||
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
|
||||
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
|
||||
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
|
||||
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
|
||||
|
||||
if cfg.LEDBoost > 0 {
|
||||
d.LEDBoost(cfg.LEDBoost)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMode returns current engine mode
|
||||
func (d *Device) GetMode() uint8 {
|
||||
return d.mode
|
||||
@@ -353,6 +315,51 @@ func (d *Device) ReadGesture() (gesture int32) {
|
||||
|
||||
// private functions
|
||||
|
||||
func (d *Device) configureDevice(cfg Configuration) {
|
||||
d.DisableAll() // turn off everything
|
||||
|
||||
// "default" settings
|
||||
if cfg.ProximityPulseLength == 0 {
|
||||
cfg.ProximityPulseLength = 16
|
||||
}
|
||||
if cfg.ProximityPulseCount == 0 {
|
||||
cfg.ProximityPulseCount = 64
|
||||
}
|
||||
if cfg.GesturePulseLength == 0 {
|
||||
cfg.GesturePulseLength = 16
|
||||
}
|
||||
if cfg.GesturePulseCount == 0 {
|
||||
cfg.GesturePulseCount = 64
|
||||
}
|
||||
if cfg.ProximityGain == 0 {
|
||||
cfg.ProximityGain = 1
|
||||
}
|
||||
if cfg.GestureGain == 0 {
|
||||
cfg.GestureGain = 1
|
||||
}
|
||||
if cfg.ColorGain == 0 {
|
||||
cfg.ColorGain = 4
|
||||
}
|
||||
if cfg.ADCIntegrationCycles == 0 {
|
||||
cfg.ADCIntegrationCycles = 4
|
||||
}
|
||||
if cfg.threshold == 0 {
|
||||
d.gesture.threshold = 30
|
||||
}
|
||||
if cfg.sensitivity == 0 {
|
||||
d.gesture.sensitivity = 20
|
||||
}
|
||||
|
||||
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
|
||||
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
|
||||
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
|
||||
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
|
||||
|
||||
if cfg.LEDBoost > 0 {
|
||||
d.LEDBoost(cfg.LEDBoost)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) enable(cfg enableConfig) {
|
||||
var gen, pien, aien, wen, pen, aen, pon uint8
|
||||
|
||||
|
||||
@@ -5,10 +5,8 @@ package apds9960
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
// configure device
|
||||
d.configureDevice(cfg)
|
||||
}
|
||||
|
||||
@@ -6,24 +6,19 @@ package apds9960
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
|
||||
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
|
||||
machine.LSM_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.LSM_PWR.High()
|
||||
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.I2C_PULLUP.High()
|
||||
// Wait a moment
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// configure device
|
||||
d.configureDevice(cfg)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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, 10)
|
||||
}
|
||||
|
||||
func (d *Device) Disconnect() error {
|
||||
return d.DisconnectFromAP()
|
||||
}
|
||||
@@ -9,21 +9,22 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableColor() // enable color engine
|
||||
|
||||
for {
|
||||
|
||||
@@ -9,21 +9,22 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableGesture() // enable gesture engine
|
||||
|
||||
for {
|
||||
@@ -34,7 +35,7 @@ func main() {
|
||||
gesture := sensor.ReadGesture()
|
||||
print("Detected gesture: ")
|
||||
switch gesture {
|
||||
case apds9960.GESTURE_UP:
|
||||
case apds9960.GESTURE_UP: // the nRF52 chip is "up"
|
||||
println("Up")
|
||||
case apds9960.GESTURE_DOWN:
|
||||
println("Down")
|
||||
|
||||
@@ -9,21 +9,23 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := apds9960.New(machine.I2C1)
|
||||
|
||||
// use default settings
|
||||
sensor.Configure(apds9960.Configuration{})
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("APDS-9960 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||
|
||||
sensor.EnableProximity() // enable proximity engine
|
||||
|
||||
for {
|
||||
|
||||
@@ -113,8 +113,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -99,8 +99,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -88,8 +88,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -108,8 +108,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -129,8 +129,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -91,8 +91,9 @@ func connectToESP() bool {
|
||||
func connectToAP() {
|
||||
println("Connecting to wifi network '" + ssid + "'")
|
||||
|
||||
adaptor.SetWifiMode(espat.WifiModeClient)
|
||||
adaptor.ConnectToAP(ssid, pass, 10)
|
||||
if err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second); err != nil {
|
||||
failMessage(err.Error())
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
ip, err := adaptor.GetClientIP()
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ft6336"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func initDevices() (touch.Pointer, error) {
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
|
||||
resistiveTouch.Configure(ft6336.Config{})
|
||||
resistiveTouch.SetPeriodActive(0x00)
|
||||
|
||||
return resistiveTouch, nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
touchScreen, _ := initDevices()
|
||||
|
||||
for {
|
||||
touch := touchScreen.ReadTouchPoint()
|
||||
if touch.Z > 0 {
|
||||
//X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size
|
||||
//Z is 24 bit and is typically > 2000 for a touch
|
||||
println("touch:", touch.X, touch.Y, touch.Z)
|
||||
//Example of scaling for m5stack-core2's 320x240 display with 320x270 touch area
|
||||
println("screen:", (touch.X*320)>>16, (touch.Y*270)>>16)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/ft6336"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func initDevices() (touchPaintDisplay, touch.Pointer, error) {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
led.Low()
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.NoPin,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
display.FillScreen(color.RGBA{255, 255, 255, 255})
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
resistiveTouch := ft6336.New(i2c, machine.Pin(39))
|
||||
resistiveTouch.Configure(ft6336.Config{})
|
||||
resistiveTouch.SetPeriodActive(0x00)
|
||||
|
||||
return display, resistiveTouch, nil
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
type touchPaintDisplay interface {
|
||||
drivers.Displayer
|
||||
FillRectangle(x, y, width, height int16, c color.RGBA) error
|
||||
DrawRectangle(x, y, w, h int16, c color.RGBA) error
|
||||
}
|
||||
|
||||
var (
|
||||
white = color.RGBA{255, 255, 255, 255}
|
||||
black = color.RGBA{0, 0, 0, 255}
|
||||
red = color.RGBA{255, 0, 0, 255}
|
||||
green = color.RGBA{0, 255, 0, 255}
|
||||
blue = color.RGBA{0, 0, 255, 255}
|
||||
magenta = color.RGBA{255, 0, 255, 255}
|
||||
yellow = color.RGBA{255, 255, 0, 255}
|
||||
cyan = color.RGBA{0, 255, 255, 255}
|
||||
|
||||
oldColor color.RGBA
|
||||
currentColor color.RGBA
|
||||
)
|
||||
|
||||
const (
|
||||
penRadius = 3
|
||||
boxSize = 30
|
||||
|
||||
Xmin = 0
|
||||
Xmax = 0xFFFF
|
||||
Ymin = 0
|
||||
Ymax = 0xFFFF
|
||||
)
|
||||
|
||||
func main() {
|
||||
display, resistiveTouch, _ := initDevices()
|
||||
|
||||
// fill the background and activate the backlight
|
||||
width, height := display.Size()
|
||||
display.FillRectangle(0, 0, width, height, black)
|
||||
|
||||
// make color selection boxes
|
||||
display.FillRectangle(0, 0, boxSize, boxSize, red)
|
||||
display.FillRectangle(boxSize, 0, boxSize, boxSize, yellow)
|
||||
display.FillRectangle(boxSize*2, 0, boxSize, boxSize, green)
|
||||
display.FillRectangle(boxSize*3, 0, boxSize, boxSize, cyan)
|
||||
display.FillRectangle(boxSize*4, 0, boxSize, boxSize, blue)
|
||||
display.FillRectangle(boxSize*5, 0, boxSize, boxSize, magenta)
|
||||
display.FillRectangle(boxSize*6, 0, boxSize, boxSize, black)
|
||||
display.FillRectangle(boxSize*7, 0, boxSize, boxSize, white)
|
||||
|
||||
// set the initial color to red and draw a box to highlight it
|
||||
oldColor = red
|
||||
currentColor = red
|
||||
display.DrawRectangle(0, 0, boxSize, boxSize, white)
|
||||
|
||||
last := touch.Point{}
|
||||
|
||||
// loop and poll for touches, including performing debouncing
|
||||
debounce := 0
|
||||
for {
|
||||
|
||||
point := resistiveTouch.ReadTouchPoint()
|
||||
touch := touch.Point{}
|
||||
if point.Z>>6 > 100 {
|
||||
rawX := mapval(point.X, Xmin, Xmax, 0, int(width))
|
||||
rawY := mapval(point.Y, Ymin, Ymax, 0, int(height))
|
||||
touch.X = rawX
|
||||
touch.Y = rawY
|
||||
touch.Z = 1
|
||||
} else {
|
||||
touch.X = 0
|
||||
touch.Y = 0
|
||||
touch.Z = 0
|
||||
}
|
||||
|
||||
if last.Z != touch.Z {
|
||||
debounce = 0
|
||||
last = touch
|
||||
} else if math.Abs(float64(touch.X-last.X)) > 4 ||
|
||||
math.Abs(float64(touch.Y-last.Y)) > 4 {
|
||||
debounce = 0
|
||||
last = touch
|
||||
} else if debounce > 1 {
|
||||
debounce = 0
|
||||
HandleTouch(display, last)
|
||||
} else if touch.Z > 0 {
|
||||
debounce++
|
||||
} else {
|
||||
last = touch
|
||||
debounce = 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// based on Arduino's "map" function
|
||||
func mapval(x int, inMin int, inMax int, outMin int, outMax int) int {
|
||||
return (x-inMin)*(outMax-outMin)/(inMax-inMin) + outMin
|
||||
}
|
||||
|
||||
func HandleTouch(display touchPaintDisplay, touch touch.Point) {
|
||||
|
||||
if int16(touch.Y) < boxSize {
|
||||
oldColor = currentColor
|
||||
x := int16(touch.X)
|
||||
switch {
|
||||
case x < boxSize:
|
||||
currentColor = red
|
||||
case x < boxSize*2:
|
||||
currentColor = yellow
|
||||
case x < boxSize*3:
|
||||
currentColor = green
|
||||
case x < boxSize*4:
|
||||
currentColor = cyan
|
||||
case x < boxSize*5:
|
||||
currentColor = blue
|
||||
case x < boxSize*6:
|
||||
currentColor = magenta
|
||||
case x < boxSize*7:
|
||||
currentColor = black
|
||||
case x < boxSize*8:
|
||||
currentColor = white
|
||||
}
|
||||
|
||||
if oldColor == currentColor {
|
||||
return
|
||||
}
|
||||
|
||||
display.DrawRectangle((x/boxSize)*boxSize, 0, boxSize, boxSize, white)
|
||||
switch oldColor {
|
||||
case red:
|
||||
x = 0
|
||||
case yellow:
|
||||
x = boxSize
|
||||
case green:
|
||||
x = boxSize * 2
|
||||
case cyan:
|
||||
x = boxSize * 3
|
||||
case blue:
|
||||
x = boxSize * 4
|
||||
case magenta:
|
||||
x = boxSize * 5
|
||||
case black:
|
||||
x = boxSize * 6
|
||||
case white:
|
||||
x = boxSize * 7
|
||||
}
|
||||
display.FillRectangle(int16(x), 0, boxSize, boxSize, oldColor)
|
||||
|
||||
}
|
||||
|
||||
if (int16(touch.Y) - penRadius) > boxSize {
|
||||
display.FillRectangle(
|
||||
int16(touch.X), int16(touch.Y), penRadius*2, penRadius*2, currentColor)
|
||||
}
|
||||
}
|
||||
@@ -9,28 +9,27 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := hts221.New(machine.I2C1)
|
||||
|
||||
sensor.Configure() // power on and calibrate
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("HTS221 not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure() // power on and calibrate
|
||||
|
||||
for {
|
||||
|
||||
h, _ := sensor.ReadHumidity()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("h =", float32(h)/100.0, "% / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//go:build m5stack
|
||||
// +build m5stack
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.SPI0_SCK_PIN,
|
||||
SDO: machine.SPI0_SDO_PIN,
|
||||
SDI: machine.SPI0_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
// configure backlight
|
||||
backlight := machine.LCD_BL_PIN
|
||||
backlight.Configure(machine.PinConfig{machine.PinOutput})
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.LCD_RST_PIN,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
|
||||
backlight.High()
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package initdisplay
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"machine"
|
||||
|
||||
axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192"
|
||||
"tinygo.org/x/drivers/i2csoft"
|
||||
"tinygo.org/x/drivers/ili9341"
|
||||
)
|
||||
|
||||
// InitDisplay initializes the display of each board.
|
||||
func InitDisplay() *ili9341.Device {
|
||||
machine.SPI2.Configure(machine.SPIConfig{
|
||||
SCK: machine.LCD_SCK_PIN,
|
||||
SDO: machine.LCD_SDO_PIN,
|
||||
SDI: machine.LCD_SDI_PIN,
|
||||
Frequency: 40e6,
|
||||
})
|
||||
|
||||
i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN)
|
||||
i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3})
|
||||
|
||||
axp := axp192.New(i2c)
|
||||
led := axp.LED
|
||||
led.Low()
|
||||
|
||||
display := ili9341.NewSPI(
|
||||
machine.SPI2,
|
||||
machine.LCD_DC_PIN,
|
||||
machine.LCD_SS_PIN,
|
||||
machine.NoPin,
|
||||
)
|
||||
|
||||
// configure display
|
||||
display.Configure(ili9341.Config{
|
||||
Width: 320,
|
||||
Height: 240,
|
||||
DisplayInversion: true,
|
||||
})
|
||||
display.FillScreen(color.RGBA{255, 255, 255, 255})
|
||||
|
||||
display.SetRotation(ili9341.Rotation0Mirror)
|
||||
|
||||
return display
|
||||
}
|
||||
@@ -9,29 +9,27 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
// use Nano 33 BLE Sense's internal I2C bus
|
||||
machine.I2C1.Configure(machine.I2CConfig{
|
||||
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||
SCL: machine.SCL1_PIN,
|
||||
SDA: machine.SDA1_PIN,
|
||||
Frequency: machine.TWI_FREQ_400KHZ,
|
||||
})
|
||||
|
||||
sensor := lps22hb.New(machine.I2C1)
|
||||
sensor.Configure()
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("LPS22HB not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
sensor.Configure()
|
||||
|
||||
for {
|
||||
|
||||
p, _ := sensor.ReadPressure()
|
||||
t, _ := sensor.ReadTemperature()
|
||||
println("p =", float32(p)/1000.0, "hPa / t =", float32(t)/1000.0, "*C")
|
||||
time.Sleep(time.Second)
|
||||
// note: the device would power down itself after each query
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
-16
@@ -3,37 +3,54 @@ package main
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lsm303agr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// LSM303AGR/MAG is connected to the I2C0 bus on micro:bit v1 (the same as P19/P20) and v2 (internal)
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
accel_mag := lsm303agr.New(machine.I2C0)
|
||||
|
||||
if !accel_mag.Connected() {
|
||||
sensor := lsm303agr.New(machine.I2C0)
|
||||
sensor.Configure(lsm303agr.Configuration{}) //default settings
|
||||
|
||||
// you can specify the following options to adjust accuracy, sensor range or save power.
|
||||
// see https://github.com/tinygo-org/drivers/blob/release/lsm303agr/registers.go for details:
|
||||
/*
|
||||
sensor.Configure(lsm303agr.Configuration{
|
||||
AccelPowerMode: lsm303agr.ACCEL_POWER_NORMAL,
|
||||
AccelRange: lsm303agr.ACCEL_RANGE_2G,
|
||||
AccelDataRate: lsm303agr.ACCEL_DATARATE_100HZ,
|
||||
MagPowerMode: lsm303agr.MAG_POWER_NORMAL,
|
||||
MagSystemMode: lsm303agr.MAG_SYSTEM_CONTINUOUS,
|
||||
MagDataRate: lsm303agr.MAG_DATARATE_10HZ,
|
||||
})
|
||||
*/
|
||||
|
||||
if !sensor.Connected() {
|
||||
println("LSM303AGR/MAG not connected!")
|
||||
return
|
||||
}
|
||||
|
||||
accel_mag.Configure(lsm303agr.Configuration{}) //default settings
|
||||
|
||||
for {
|
||||
// accel_x, accel_y, accel_z := sensor.ReadAcceleration()
|
||||
// println("ACCEL_X:", accel_x/100000, " ACCEL_Y:", accel_y/100000, " ACCEL_Z:", accel_z/100000)
|
||||
|
||||
accel_x, accel_y, accel_z := accel_mag.ReadAcceleration()
|
||||
pitch, roll := accel_mag.ReadPitchRoll()
|
||||
mag_x, mag_y, mag_z := accel_mag.ReadMagneticField()
|
||||
heading := accel_mag.ReadCompass()
|
||||
temp, _ := accel_mag.ReadTemperature()
|
||||
// mag_x, mag_y, mag_z := sensor.ReadMagneticField()
|
||||
// println("MAG_X:", mag_x/100000, " MAG_Y:", mag_y/100000, " MAG_Z:", mag_z/100000)
|
||||
|
||||
pitch, roll := sensor.ReadPitchRoll()
|
||||
println("Pitch:", float32(pitch)/100000, " Roll:", float32(roll)/100000)
|
||||
|
||||
heading := sensor.ReadCompass()
|
||||
println("Heading:", float32(heading)/100000, "degrees")
|
||||
|
||||
temp, _ := sensor.ReadTemperature()
|
||||
println("Temperature:", float32(temp)/1000, "*C")
|
||||
|
||||
println("ACCEL_X:", accel_x, " ACCEL_Y:", accel_y, " ACCEL_Z:", accel_z)
|
||||
println("MAG_X:", mag_x, " MAG_Y:", mag_y, " MAG_Z:", mag_z)
|
||||
println("Pitch:", pitch, " Roll:", roll)
|
||||
println("Heading:", heading)
|
||||
println("Temperature:", temp/1000)
|
||||
println("\n")
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pca9685"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
// Default address on most breakout boards.
|
||||
pcaAddr = 0x40
|
||||
)
|
||||
err := machine.I2C0.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
d := pca9685.New(machine.I2C0, 0x40)
|
||||
err = d.IsConnected()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
err = d.Configure(pca9685.PWMConfig{Period: 1e9 / 200}) // 200Hz PWM
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
var value uint32
|
||||
step := d.Top() / 5
|
||||
for {
|
||||
for value = 0; value <= d.Top(); value += step {
|
||||
d.SetAll(value)
|
||||
dc := 100 * value / d.Top()
|
||||
println("set dc @", dc, "%")
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ScanI2CDev finds I2C devices on the bus and rreturns them inside
|
||||
// a slice. If slice is nil then no devices were found.
|
||||
func ScanI2CDev(bus machine.I2C) (addrs []uint8) {
|
||||
var addr, count uint8
|
||||
var err error
|
||||
w := []byte{1}
|
||||
// Count devices in first scan
|
||||
for addr = 1; addr < 127; addr++ {
|
||||
err = bus.Tx(uint16(addr), w, nil)
|
||||
if err == nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
// Allocate slice and populate slice with addresses
|
||||
addrs = make([]uint8, count)
|
||||
count = 0
|
||||
for addr = 1; addr < 127; addr++ {
|
||||
err = bus.Tx(uint16(addr), w, nil)
|
||||
if err == nil && count < uint8(len(addrs)) {
|
||||
addrs[count] = addr
|
||||
count++
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func run() error {
|
||||
}
|
||||
net.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func run() error {
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
fmt.Fprintf(terminal, "ConnectToAP()\r\n")
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
net.UseDriver(rtl)
|
||||
http.SetBuf(buf[:])
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func run() error {
|
||||
}
|
||||
http.UseDriver(rtl)
|
||||
|
||||
err = rtl.ConnectToAP(ssid, password)
|
||||
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/shtc3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
sensor := shtc3.New(machine.I2C0)
|
||||
|
||||
for {
|
||||
|
||||
sensor.WakeUp()
|
||||
|
||||
temp, humidity, _ := sensor.ReadTemperatureHumidity()
|
||||
t := fmt.Sprintf("%.2f", float32(temp)/1000)
|
||||
h := fmt.Sprintf("%.2f", float32(humidity)/100)
|
||||
println("Temperature:", t, "°C")
|
||||
println("Humidity", h, "%")
|
||||
|
||||
sensor.Sleep()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
// This example will periodically enable Continuous "Preamble" and "Wave" modes on 868.1 Mhz
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
const FREQ = 868100000
|
||||
|
||||
var (
|
||||
loraRadio *sx126x.Device
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("\n# TinyGo Lora continuous Wave/Preamble test")
|
||||
println("# -----------------------------------------")
|
||||
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
// Create the driver
|
||||
loraRadio = sx126x.New(machine.SPI3)
|
||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
||||
|
||||
// Create RF Switch
|
||||
var radioSwitch rfswitch.CustomSwitch
|
||||
loraRadio.SetRfSwitch(radioSwitch)
|
||||
|
||||
state := loraRadio.DetectDevice()
|
||||
if !state {
|
||||
panic("sx126x not detected. ")
|
||||
}
|
||||
|
||||
// Prepare for Lora operation
|
||||
loraConf := sx126x.LoraConfig{
|
||||
Freq: FREQ,
|
||||
Bw: sx126x.SX126X_LORA_BW_500_0,
|
||||
Sf: sx126x.SX126X_LORA_SF9,
|
||||
Cr: sx126x.SX126X_LORA_CR_4_7,
|
||||
HeaderType: sx126x.SX126X_LORA_HEADER_EXPLICIT,
|
||||
Preamble: 12,
|
||||
Ldr: sx126x.SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF,
|
||||
Iq: sx126x.SX126X_LORA_IQ_STANDARD,
|
||||
Crc: sx126x.SX126X_LORA_CRC_ON,
|
||||
SyncWord: sx126x.SX126X_LORA_MAC_PRIVATE_SYNCWORD,
|
||||
LoraTxPowerDBm: 14,
|
||||
}
|
||||
loraRadio.LoraConfig(loraConf)
|
||||
|
||||
// Although LoraConfig has already configured most of Lora settings,
|
||||
// the following lines are still required to enable Continuous Preamble/Wave
|
||||
loraRadio.SetPacketType(sx126x.SX126X_PACKET_TYPE_LORA)
|
||||
loraRadio.SetRfFrequency(loraConf.Freq)
|
||||
loraRadio.SetModulationParams(loraConf.Sf, loraConf.Bw, loraConf.Cr, loraConf.Ldr)
|
||||
loraRadio.SetTxParams(loraConf.LoraTxPowerDBm, sx126x.SX126X_PA_RAMP_200U)
|
||||
|
||||
for {
|
||||
println("2 seconds in Continuous Preamble")
|
||||
loraRadio.SetStandby()
|
||||
loraRadio.SetTxContinuousPreamble()
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Continuous Preamble Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
println("2 seconds in Continuous Wave")
|
||||
loraRadio.SetTxContinuousWave()
|
||||
time.Sleep(2 * time.Second)
|
||||
println(" Continuous Wave Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(60 * time.Second)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
// In this example, a Lora packet will be sent every 10s
|
||||
// module will be in RX mode between two transmissions
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
|
||||
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
const FREQ = 868100000
|
||||
|
||||
const (
|
||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
||||
)
|
||||
|
||||
var (
|
||||
loraRadio *sx126x.Device
|
||||
txmsg = []byte("Hello TinyGO")
|
||||
)
|
||||
|
||||
// radioIntHandler will take care of radio interrupts
|
||||
func radioIntHandler(intr interrupt.Interrupt) {
|
||||
loraRadio.HandleInterrupt()
|
||||
}
|
||||
|
||||
func main() {
|
||||
println("\n# TinyGo Lora RX/TX test")
|
||||
println("# ----------------------")
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
// Create the driver
|
||||
loraRadio = sx126x.New(machine.SPI3)
|
||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
||||
|
||||
// Create RF Switch
|
||||
var radioSwitch rfswitch.CustomSwitch
|
||||
loraRadio.SetRfSwitch(radioSwitch)
|
||||
|
||||
// Detect the device
|
||||
state := loraRadio.DetectDevice()
|
||||
if !state {
|
||||
panic("sx126x not detected.")
|
||||
}
|
||||
|
||||
// Add interrupt handler for Radio IRQs
|
||||
intr := interrupt.New(stm32.IRQ_Radio_IRQ_Busy, radioIntHandler)
|
||||
intr.Enable()
|
||||
|
||||
loraConf := sx126x.LoraConfig{
|
||||
Freq: FREQ,
|
||||
Bw: sx126x.SX126X_LORA_BW_500_0,
|
||||
Sf: sx126x.SX126X_LORA_SF9,
|
||||
Cr: sx126x.SX126X_LORA_CR_4_7,
|
||||
HeaderType: sx126x.SX126X_LORA_HEADER_EXPLICIT,
|
||||
Preamble: 12,
|
||||
Ldr: sx126x.SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF,
|
||||
Iq: sx126x.SX126X_LORA_IQ_STANDARD,
|
||||
Crc: sx126x.SX126X_LORA_CRC_ON,
|
||||
SyncWord: sx126x.SX126X_LORA_MAC_PRIVATE_SYNCWORD,
|
||||
LoraTxPowerDBm: 20,
|
||||
}
|
||||
|
||||
loraRadio.LoraConfig(loraConf)
|
||||
|
||||
var count uint
|
||||
for {
|
||||
tStart := time.Now()
|
||||
|
||||
// Blocking RX for LORA_DEFAULT_RXTIMEOUT_MS
|
||||
println("Start Lora RX for 10 sec")
|
||||
for int(time.Now().Sub(tStart).Seconds()) < 10 {
|
||||
buf, err := loraRadio.LoraRx(LORA_DEFAULT_RXTIMEOUT_MS)
|
||||
|
||||
if err != nil {
|
||||
println("RX Error: ", err)
|
||||
} else if buf != nil {
|
||||
println("Packet Received: len=", len(buf), string(buf))
|
||||
}
|
||||
}
|
||||
println("END Lora RX")
|
||||
|
||||
println("LORA TX size=", len(txmsg))
|
||||
err := loraRadio.LoraTx(txmsg, LORA_DEFAULT_TXTIMEOUT_MS)
|
||||
if err != nil {
|
||||
println("TX Error:", err)
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//go:build gnse
|
||||
// +build gnse
|
||||
|
||||
/*
|
||||
Generic Node Sensor Edition
|
||||
RFSwitch
|
||||
|
||||
Disable Switch : PB8=OFF PA0=OFF PA1=OFF
|
||||
Enable RX : PB8=ON PA0=ON PA1=OFF
|
||||
Enable TX RFO LP : PB8=ON PA0=ON PA1=ON
|
||||
Enable TX RFO HP : PB8=ON PA0=OFF PA1=ON
|
||||
*/
|
||||
package rfswitch
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
var (
|
||||
rfstate int
|
||||
)
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.RF_FE_CTRL1.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RF_FE_CTRL2.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RF_FE_CTRL3.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
rfstate = -1 //Unknown
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
if mode == rfstate {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.RF_FE_CTRL1.Set(false)
|
||||
machine.RF_FE_CTRL2.Set(true)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
machine.RF_FE_CTRL1.Set(true)
|
||||
machine.RF_FE_CTRL2.Set(true)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.RF_FE_CTRL1.Set(true)
|
||||
machine.RF_FE_CTRL2.Set(false)
|
||||
machine.RF_FE_CTRL3.Set(true)
|
||||
}
|
||||
|
||||
rfstate = mode
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//go:build lorae5
|
||||
// +build lorae5
|
||||
|
||||
package radio
|
||||
|
||||
/*
|
||||
/!\ LoRa-E5 module ONLY transmits through RFO_HP:
|
||||
|
||||
Receive: PA4=1, PA5=0
|
||||
Transmit(high output power, SMPS mode): PA4=0, PA5=1
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.PA4.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PB5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.PA4.Set(true)
|
||||
machine.PB5.Set(false)
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
errors.New("RFSWITCH_TX_LP not supported ")
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.PA4.Set(false)
|
||||
machine.PB5.Set(true)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build nucleowl55jc
|
||||
// +build nucleowl55jc
|
||||
|
||||
/*
|
||||
Nucleo WL55JC1
|
||||
RFSwitch
|
||||
|
||||
+-----------+---------+------------+------------+
|
||||
| | FE_CTRL1 | FE_CTRL2 | FE_CTRL3 |
|
||||
| | (PC4) | (PC5) | (PC3) |
|
||||
+-----------+----------+-----------+------------+
|
||||
| TX_HP | LOW | HIGH | HIGH |
|
||||
| TX_LP | HIGH | HIGH | HIGH |
|
||||
| RX | HIGH | LOW | HIGH |
|
||||
+-----------+----------+-----------+------------+
|
||||
*/
|
||||
package rfswitch
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
type CustomSwitch struct {
|
||||
}
|
||||
|
||||
func (s CustomSwitch) InitRFSwitch() {
|
||||
machine.PC4.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PC5.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.PC3.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
|
||||
func (s CustomSwitch) SetRfSwitchMode(mode int) error {
|
||||
switch mode {
|
||||
|
||||
case sx126x.RFSWITCH_TX_HP:
|
||||
machine.PC4.Set(false)
|
||||
machine.PC5.Set(true)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_TX_LP:
|
||||
machine.PC4.Set(true)
|
||||
machine.PC5.Set(true)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
case sx126x.RFSWITCH_RX:
|
||||
machine.PC4.Set(true)
|
||||
machine.PC5.Set(false)
|
||||
machine.PC3.Set(true)
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build espat
|
||||
// +build espat
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"tinygo.org/x/drivers/espat"
|
||||
)
|
||||
|
||||
// these are the default pins for the Arduino Nano33 IoT.
|
||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||
var (
|
||||
uart = machine.UART1
|
||||
tx = machine.PA22
|
||||
rx = machine.PA23
|
||||
|
||||
adaptor *espat.Device
|
||||
)
|
||||
|
||||
func initAdaptor() *espat.Device {
|
||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||
|
||||
adaptor = espat.New(uart)
|
||||
adaptor.Configure()
|
||||
|
||||
return adaptor
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// 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
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
// access point info
|
||||
const ssid = ""
|
||||
const pass = ""
|
||||
|
||||
// IP address of the server aka "hub". Replace with your own info.
|
||||
const serverIP = ""
|
||||
|
||||
var buf = &bytes.Buffer{}
|
||||
|
||||
func main() {
|
||||
initAdaptor()
|
||||
|
||||
connectToAP()
|
||||
|
||||
for {
|
||||
sendBatch()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
println("Done.")
|
||||
}
|
||||
|
||||
func sendBatch() {
|
||||
|
||||
// make TCP connection
|
||||
ip := net.ParseIP(serverIP)
|
||||
raddr := &net.TCPAddr{IP: ip, Port: 8080}
|
||||
laddr := &net.TCPAddr{Port: 8080}
|
||||
|
||||
message("---------------\r\nDialing TCP connection")
|
||||
conn, err := net.DialTCP("tcp", laddr, raddr)
|
||||
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
|
||||
message(err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
n := 0
|
||||
w := 0
|
||||
start := time.Now()
|
||||
|
||||
// send data
|
||||
message("Sending data")
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
buf.Reset()
|
||||
fmt.Fprint(buf,
|
||||
"\r---------------------------- i == ", i, " ----------------------------"+
|
||||
"\r---------------------------- i == ", i, " ----------------------------")
|
||||
if w, err = conn.Write(buf.Bytes()); err != nil {
|
||||
println("error:", err.Error(), "\r")
|
||||
continue
|
||||
}
|
||||
n += w
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
ms := time.Now().Sub(start).Milliseconds()
|
||||
fmt.Fprint(buf, "\nWrote ", n, " bytes in ", ms, " ms\r\n")
|
||||
message(buf.String())
|
||||
|
||||
if _, err := conn.Write(buf.Bytes()); err != nil {
|
||||
println("error:", err.Error(), "\r")
|
||||
}
|
||||
|
||||
// Right now this code is never reached. Need a way to trigger it...
|
||||
println("Disconnecting TCP...")
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
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")
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//go:build rtl8720dn
|
||||
// +build rtl8720dn
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"device/sam"
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
"tinygo.org/x/drivers/rtl8720dn"
|
||||
)
|
||||
|
||||
var (
|
||||
adaptor *rtl8720dn.RTL8720DN
|
||||
|
||||
uart UARTx
|
||||
)
|
||||
|
||||
func initAdaptor() *rtl8720dn.RTL8720DN {
|
||||
adaptor, err := setupRTL8720DN()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
net.UseDriver(adaptor)
|
||||
|
||||
return adaptor
|
||||
}
|
||||
|
||||
func handleInterrupt(interrupt.Interrupt) {
|
||||
// should reset IRQ
|
||||
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||
}
|
||||
|
||||
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.RTL8720D_CHIP_PU.Low()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
machine.RTL8720D_CHIP_PU.High()
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
|
||||
uart = UARTx{
|
||||
UART: &machine.UART{
|
||||
Buffer: machine.NewRingBuffer(),
|
||||
Bus: sam.SERCOM0_USART_INT,
|
||||
SERCOM: 0,
|
||||
},
|
||||
}
|
||||
|
||||
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||
|
||||
rtl := rtl8720dn.New(uart)
|
||||
//rtl.Debug(debug)
|
||||
|
||||
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rtl, nil
|
||||
}
|
||||
|
||||
type UARTx struct {
|
||||
*machine.UART
|
||||
}
|
||||
|
||||
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||
if u.Buffered() == 0 {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
return 0, nil
|
||||
}
|
||||
return u.UART.Read(p)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//go:build wifinina
|
||||
// +build wifinina
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"tinygo.org/x/drivers/wifinina"
|
||||
)
|
||||
|
||||
var (
|
||||
// default interface for the Arduino Nano33 IoT.
|
||||
spi = machine.NINA_SPI
|
||||
|
||||
// ESP32/ESP8266 chip that has the WIFININA firmware flashed on it
|
||||
adaptor *wifinina.Device
|
||||
)
|
||||
|
||||
func initAdaptor() *wifinina.Device {
|
||||
// Configure SPI for 8Mhz, Mode 0, MSB First
|
||||
spi.Configure(machine.SPIConfig{
|
||||
Frequency: 8 * 1e6,
|
||||
SDO: machine.NINA_SDO,
|
||||
SDI: machine.NINA_SDI,
|
||||
SCK: machine.NINA_SCK,
|
||||
})
|
||||
|
||||
adaptor = wifinina.New(spi,
|
||||
machine.NINA_CS,
|
||||
machine.NINA_ACK,
|
||||
machine.NINA_GPIO0,
|
||||
machine.NINA_RESETN)
|
||||
adaptor.Configure()
|
||||
|
||||
return adaptor
|
||||
}
|
||||
@@ -128,19 +128,15 @@ func waitSerial() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
for {
|
||||
println("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
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.")
|
||||
}
|
||||
|
||||
@@ -132,22 +132,18 @@ func waitSerial() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
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("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -104,14 +104,16 @@ func main() {
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
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.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
println(err.Error())
|
||||
|
||||
@@ -116,13 +116,16 @@ func publishing() {
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
println("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
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.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -151,21 +151,18 @@ func clearBuffer() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
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("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -113,14 +113,17 @@ func sendBatch() {
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
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)
|
||||
}
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -122,21 +122,18 @@ func makeHTTPSRequest() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
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("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
|
||||
@@ -76,15 +76,17 @@ func main() {
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
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)
|
||||
}
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -124,22 +124,18 @@ func makeHTTPRequest() {
|
||||
|
||||
// connect to access point
|
||||
func connectToAP() {
|
||||
if len(ssid) == 0 || len(pass) == 0 {
|
||||
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("Connection failed: Either ssid or password not set")
|
||||
time.Sleep(10 * time.Second)
|
||||
println(err)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
message("Connecting to " + ssid)
|
||||
adaptor.SetPassphrase(ssid, pass)
|
||||
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
|
||||
message("Connection status: " + st.String())
|
||||
time.Sleep(1 * time.Second)
|
||||
st, _ = adaptor.GetConnectionStatus()
|
||||
}
|
||||
message("Connected.")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
println("Connected.")
|
||||
|
||||
ip, _, _, err := adaptor.GetIP()
|
||||
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
|
||||
message(err.Error())
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/xpt2046"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
clk := machine.GPIO0
|
||||
cs := machine.GPIO1
|
||||
din := machine.GPIO2
|
||||
dout := machine.GPIO3
|
||||
irq := machine.GPIO4
|
||||
|
||||
touchScreen := xpt2046.New(clk, cs, din, dout, irq)
|
||||
|
||||
touchScreen.Configure(&xpt2046.Config{
|
||||
Precision: 10, //Maximum number of samples for a single ReadTouchPoint to improve accuracy.
|
||||
})
|
||||
|
||||
for {
|
||||
|
||||
//Wait for a touch
|
||||
for !touchScreen.Touched() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
touch := touchScreen.ReadTouchPoint()
|
||||
//X and Y are 16 bit with 12 bit resolution and need to be scaled for the display size
|
||||
//Z is 24 bit and is typically > 2000 for a touch
|
||||
println("touch:", touch.X, touch.Y, touch.Z)
|
||||
//Example of scaling for a 240x320 display
|
||||
println("screen:", (touch.X*240)>>16, (touch.Y*320)>>16)
|
||||
|
||||
//Wait for touch to end
|
||||
for touchScreen.Touched() {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Package ft6336 provides a driver for the FT6336 I2C Self-Capacitive touch
|
||||
// panel controller.
|
||||
//
|
||||
// Datasheet: https://focuslcds.com/content/FT6236.pdf
|
||||
//
|
||||
package ft6336
|
||||
|
||||
import (
|
||||
"machine"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
// Device wraps FT6336 I2C Self-Capacitive touch
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
buf []byte
|
||||
Address uint8
|
||||
intPin machine.Pin
|
||||
}
|
||||
|
||||
// New returns FT6336 device for the provided I2C bus using default address.
|
||||
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
|
||||
return &Device{
|
||||
bus: i2c,
|
||||
buf: make([]byte, 11),
|
||||
Address: Address,
|
||||
intPin: intPin,
|
||||
}
|
||||
}
|
||||
|
||||
// Config contains settings for FT6636.
|
||||
type Config struct {
|
||||
}
|
||||
|
||||
// Configure the FT6336 device.
|
||||
func (d *Device) Configure(config Config) error {
|
||||
d.write1Byte(0xA4, 0x00)
|
||||
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGMode sets interrupt mode.
|
||||
// 0x00 : Interrupt Polling mode
|
||||
// 0x01 : Interrupt Trigger mode (default)
|
||||
func (d *Device) SetGMode(v uint8) {
|
||||
d.write1Byte(RegGMode, v)
|
||||
}
|
||||
|
||||
// GetGMode gets interrupt mode.
|
||||
func (d *Device) GetGMode() uint8 {
|
||||
return d.read8bit(RegGMode)
|
||||
}
|
||||
|
||||
// SetPeriodActive sets report rate in Active mode.
|
||||
func (d *Device) SetPeriodActive(v uint8) {
|
||||
d.write1Byte(RegPeriodActive, v)
|
||||
}
|
||||
|
||||
// GetPeriodActive gets report rate in Active mode.
|
||||
func (d *Device) GetPeriodActive() uint8 {
|
||||
return d.read8bit(RegPeriodActive)
|
||||
}
|
||||
|
||||
// GetFirmwareID gets firmware version.
|
||||
func (d *Device) GetFirmwareID() uint8 {
|
||||
return d.read8bit(RegFirmid)
|
||||
}
|
||||
|
||||
// Read reads the registers.
|
||||
func (d *Device) Read() []byte {
|
||||
d.bus.Tx(uint16(d.Address), []byte{0x02}, d.buf[:])
|
||||
return d.buf[:]
|
||||
}
|
||||
|
||||
// ReadTouchPoint reads a single touch.Point from the device. The maximum value
|
||||
// for each touch.Point is 0xFFFF.
|
||||
func (d *Device) ReadTouchPoint() touch.Point {
|
||||
d.Read()
|
||||
z := 0xFFFFF
|
||||
if d.buf[0] == 0 {
|
||||
z = 0
|
||||
}
|
||||
|
||||
//Scale X&Y to 16 bit for consistency across touch drivers
|
||||
return touch.Point{
|
||||
X: (int(d.buf[1]&0x0F)<<8 + int(d.buf[2])) * ((1 << 16) / 320),
|
||||
Y: (int(d.buf[3]&0x0F)<<8 + int(d.buf[4])) * ((1 << 16) / 270),
|
||||
Z: z,
|
||||
}
|
||||
}
|
||||
|
||||
// Touched returns if touched or not.
|
||||
func (d *Device) Touched() bool {
|
||||
p := d.ReadTouchPoint()
|
||||
return p.Z > 0
|
||||
}
|
||||
|
||||
func (d *Device) write1Byte(reg, data uint8) {
|
||||
d.bus.WriteRegister(d.Address, reg, []byte{data})
|
||||
}
|
||||
|
||||
func (d *Device) read8bit(reg uint8) uint8 {
|
||||
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
|
||||
return d.buf[0]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package ft6336
|
||||
|
||||
// 0x00 DEV_MODE
|
||||
// 0x01 GEST_ID
|
||||
// 0x02 TD_STATUS
|
||||
// 0x03 P1_XH
|
||||
// 0x04 P1_XL
|
||||
// 0x05 P1_YH
|
||||
// 0x06 P1_YL
|
||||
// 0x07 P1_WEIGHT
|
||||
// 0x08 P1_MISC
|
||||
// 0x09 P2_XH
|
||||
// 0x0A P2_XL
|
||||
// 0x0B P2_YH
|
||||
// 0x0C P2_YL
|
||||
// 0x0D P2_WEIGHT
|
||||
// 0x0E P2_MISC
|
||||
// 0x80 TH_GROUP
|
||||
// 0x85 TH_DIFF
|
||||
// 0x86 CTRL
|
||||
// 0x87 TIMEENTERMONITOR
|
||||
// 0x88 PERIODACTIVE
|
||||
// 0x89 PERIODMONITOR
|
||||
// 0x91 RADIAN_VALUE
|
||||
// 0x92 OFFSET_LEFT_RIGHT
|
||||
// 0x93 OFFSET_UP_D
|
||||
// 0x94 DISTANCE_LE
|
||||
// 0x95 DISTANCE_UP
|
||||
// 0x96 DISTANCE_ZO
|
||||
// ...
|
||||
// 0xA1 LIB_VER_H
|
||||
// 0xA2 LIB_VER_L
|
||||
// 0xA3 CIPHER
|
||||
// 0xA4 G_MODE
|
||||
// 0xA5 PWR_MODE
|
||||
// 0xA6 FIRMID
|
||||
// 0xA8 FOCALTECH_ID
|
||||
// ...
|
||||
// 0xAF RELEASE_CODE_ID
|
||||
// ...
|
||||
// 0xBC STATE
|
||||
|
||||
const (
|
||||
Address = 0x38
|
||||
|
||||
RegPeriodActive = 0x88
|
||||
RegGMode = 0xA4
|
||||
RegFirmid = 0xA6
|
||||
)
|
||||
+3
-1
@@ -105,7 +105,8 @@ func (g *GPIO) Read(data []byte) (n int, err error) {
|
||||
data[i] = g.read()
|
||||
n++
|
||||
}
|
||||
g.reconfigureGPIOMode(machine.PinInput)
|
||||
g.rw.Low()
|
||||
g.reconfigureGPIOMode(machine.PinOutput)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ func (g *GPIO) read4BitMode() byte {
|
||||
g.en.High()
|
||||
data := (g.pins() << 4 & 0xF0)
|
||||
g.en.Low()
|
||||
|
||||
g.en.High()
|
||||
data |= (g.pins() & 0x0F)
|
||||
g.en.Low()
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ func (d *Device) Configure(cfg Config) error {
|
||||
}
|
||||
|
||||
if d.datalength == DATA_LENGTH_4BIT {
|
||||
d.bus.Write([]byte{DATA_LENGTH_4BIT >> 4})
|
||||
d.bus.Write([]byte{DATA_LENGTH_4BIT})
|
||||
}
|
||||
|
||||
// Busy flag is now accessible
|
||||
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
|
||||
FUNCTION_MODE = 0x20
|
||||
DATA_LENGTH_8BIT = FUNCTION_MODE | 0x10
|
||||
DATA_LENGTH_4BIT = FUNCTION_MODE | 0x0
|
||||
DATA_LENGTH_4BIT = FUNCTION_MODE | 0x2
|
||||
TWO_LINE = FUNCTION_MODE | 0x8
|
||||
ONE_LINE = FUNCTION_MODE | 0x0
|
||||
FONT_5X10 = FUNCTION_MODE | 0x4
|
||||
|
||||
@@ -101,7 +101,7 @@ func (d *Device) Configure(cfg Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay clears all texts on the display.
|
||||
// ClearDisplay clears all texts on the display and sets the cursor back to position (0, 0).
|
||||
func (d *Device) ClearDisplay() {
|
||||
d.sendCommand(DISPLAY_CLEAR)
|
||||
d.cursor.x = 0
|
||||
@@ -119,7 +119,8 @@ func (d *Device) Home() {
|
||||
|
||||
// SetCursor sets the cursor to a specific position (x, y).
|
||||
//
|
||||
// if y (row) is set larger than actual rows, it would be set to 0.
|
||||
// For example, on 16x2 LCDs the range of x (column) is 0~15 and y (row) is 0~1.
|
||||
// if y is larger than actual rows, it would be set to 0 (restart from first row).
|
||||
func (d *Device) SetCursor(x, y uint8) {
|
||||
rowOffset := []uint8{0x0, 0x40, 0x14, 0x54}
|
||||
if y > (d.height - 1) {
|
||||
@@ -139,11 +140,11 @@ func (d *Device) Print(data []byte) {
|
||||
if chr == '\n' {
|
||||
d.newLine()
|
||||
} else {
|
||||
d.cursor.x++
|
||||
if d.cursor.x >= d.width {
|
||||
d.newLine()
|
||||
}
|
||||
d.sendData(uint8(rune(chr)))
|
||||
d.cursor.x++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -21,6 +21,14 @@ type Device struct {
|
||||
temperatureZero float32
|
||||
}
|
||||
|
||||
// New creates a new HTS221 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
}
|
||||
|
||||
// Connected returns whether HTS221 has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
@@ -29,14 +37,6 @@ func (d *Device) Connected() bool {
|
||||
return data[0] == 0xBC
|
||||
}
|
||||
|
||||
// Configure sets up the HTS221 device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// read calibration data
|
||||
d.calibration()
|
||||
// activate device and use block data update mode
|
||||
d.Power(true)
|
||||
}
|
||||
|
||||
// Power is for turn on/off the HTS221 device
|
||||
func (d *Device) Power(status bool) {
|
||||
data := []byte{0}
|
||||
|
||||
@@ -5,10 +5,10 @@ package hts221
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new HTS221 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
// Configure sets up the HTS221 device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// read calibration data
|
||||
d.calibration()
|
||||
// activate device and use block data update mode
|
||||
d.Power(true)
|
||||
}
|
||||
|
||||
@@ -6,24 +6,20 @@ package hts221
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new HTS221 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
// Configure sets up the HTS221 device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
|
||||
machine.HTS_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.HTS_PWR.High()
|
||||
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.I2C_PULLUP.High()
|
||||
// Wait a moment
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
return Device{bus: bus, Address: HTS221_ADDRESS}
|
||||
// read calibration data
|
||||
d.calibration()
|
||||
// activate device and use block data update mode
|
||||
d.Power(true)
|
||||
}
|
||||
|
||||
+27
-9
@@ -8,9 +8,10 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Width int16
|
||||
Height int16
|
||||
Rotation Rotation
|
||||
Width int16
|
||||
Height int16
|
||||
Rotation Rotation
|
||||
DisplayInversion bool
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
@@ -103,10 +104,19 @@ func (d *Device) Configure(config Config) {
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
||||
GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
|
||||
}
|
||||
|
||||
if config.DisplayInversion {
|
||||
initCmd = append(initCmd, []byte{
|
||||
INVON, 0x80,
|
||||
}...)
|
||||
}
|
||||
|
||||
initCmd = append(initCmd, []byte{
|
||||
SLPOUT, 0x80, // Exit Sleep
|
||||
DISPON, 0x80, // Display on
|
||||
0x00, // End of list
|
||||
}
|
||||
}...)
|
||||
for i, c := 0, len(initCmd); i < c; {
|
||||
cmd := initCmd[i]
|
||||
if cmd == 0x00 {
|
||||
@@ -239,14 +249,22 @@ func (d *Device) GetRotation() Rotation {
|
||||
// SetRotation changes the rotation of the device (clock-wise)
|
||||
func (d *Device) SetRotation(rotation Rotation) {
|
||||
madctl := uint8(0)
|
||||
switch rotation % 4 {
|
||||
case 0:
|
||||
switch rotation % 8 {
|
||||
case Rotation0:
|
||||
madctl = MADCTL_MX | MADCTL_BGR
|
||||
case 1:
|
||||
case Rotation90:
|
||||
madctl = MADCTL_MV | MADCTL_BGR
|
||||
case 2:
|
||||
case Rotation180:
|
||||
madctl = MADCTL_MY | MADCTL_BGR
|
||||
case 3:
|
||||
case Rotation270:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
case Rotation0Mirror:
|
||||
madctl = MADCTL_BGR
|
||||
case Rotation90Mirror:
|
||||
madctl = MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
case Rotation180Mirror:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_BGR
|
||||
case Rotation270Mirror:
|
||||
madctl = MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR
|
||||
}
|
||||
d.sendCommand(MADCTL, []uint8{madctl})
|
||||
|
||||
@@ -81,4 +81,9 @@ const (
|
||||
Rotation90 Rotation = 1 // 90 degrees clock-wise rotation
|
||||
Rotation180 Rotation = 2
|
||||
Rotation270 Rotation = 3
|
||||
|
||||
Rotation0Mirror Rotation = 4
|
||||
Rotation90Mirror Rotation = 5
|
||||
Rotation180Mirror Rotation = 6
|
||||
Rotation270Mirror Rotation = 7
|
||||
)
|
||||
|
||||
+14
-12
@@ -14,18 +14,12 @@ type Device struct {
|
||||
Address uint8
|
||||
}
|
||||
|
||||
// Connected returns whether LPS22HB has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_WHO_AM_I_REG, data)
|
||||
return data[0] == 0xB1
|
||||
}
|
||||
|
||||
// Configure sets up the LPS22HB device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// set to block update mode
|
||||
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
|
||||
// New creates a new LPS22HB connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: LPS22HB_ADDRESS}
|
||||
}
|
||||
|
||||
// ReadPressure returns the pressure in milli pascals (mPa).
|
||||
@@ -42,6 +36,14 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
|
||||
return int32(pValue * 1000), nil
|
||||
}
|
||||
|
||||
// Connected returns whether LPS22HB has been found.
|
||||
// It does a "who am I" request and checks the response.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.bus.ReadRegister(d.Address, LPS22HB_WHO_AM_I_REG, data)
|
||||
return data[0] == 0xB1
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (temperature int32, err error) {
|
||||
d.waitForOneShot()
|
||||
|
||||
@@ -5,10 +5,8 @@ package lps22hb
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// New creates a new LPS22HB connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{bus: bus, Address: LPS22HB_ADDRESS}
|
||||
// Configure sets up the LPS22HB device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// set to block update mode
|
||||
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
|
||||
}
|
||||
|
||||
@@ -6,24 +6,18 @@ package lps22hb
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new LPS22HB connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not touch the device.
|
||||
func New(bus drivers.I2C) Device {
|
||||
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||
// and wait a moment.
|
||||
ENV := machine.P0_22
|
||||
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
ENV.High()
|
||||
R := machine.P1_00
|
||||
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
R.High()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
// Configure sets up the LPS22HB device for communication.
|
||||
func (d *Device) Configure() {
|
||||
// Following lines are Nano 33 BLE specific, they have nothing to do with sensor per se
|
||||
machine.LSP_PWR.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.LSP_PWR.High()
|
||||
machine.I2C_PULLUP.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.I2C_PULLUP.High()
|
||||
// Wait a moment
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
return Device{bus: bus, Address: LPS22HB_ADDRESS}
|
||||
// set to block update mode
|
||||
d.bus.WriteRegister(d.Address, LPS22HB_CTRL1_REG, []byte{0x02})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
package net
|
||||
|
||||
type DeviceDriver interface {
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWiFiMissingSSID = errors.New("missing SSID")
|
||||
ErrWiFiConnectTimeout = errors.New("WiFi connect timeout")
|
||||
)
|
||||
|
||||
// Adapter interface is used to communicate with the network adapter.
|
||||
type Adapter interface {
|
||||
// functions used to connect/disconnect to/from an access point
|
||||
ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error
|
||||
Disconnect() error
|
||||
GetClientIP() (string, error)
|
||||
|
||||
// these functions are used once the adapter is connected to the network
|
||||
GetDNS(domain string) (string, error)
|
||||
ConnectTCPSocket(addr, port string) error
|
||||
ConnectSSLSocket(addr, port string) error
|
||||
@@ -16,12 +33,12 @@ type DeviceDriver interface {
|
||||
Response(timeout int) ([]byte, error)
|
||||
}
|
||||
|
||||
var ActiveDevice DeviceDriver
|
||||
var ActiveDevice Adapter
|
||||
|
||||
func UseDriver(driver DeviceDriver) {
|
||||
func UseDriver(a Adapter) {
|
||||
// TODO: rethink and refactor this
|
||||
if ActiveDevice != nil {
|
||||
panic("net.ActiveDevice is already set")
|
||||
}
|
||||
ActiveDevice = driver
|
||||
ActiveDevice = a
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ func NewClient(o *ClientOptions) Client {
|
||||
}
|
||||
|
||||
type mqttclient struct {
|
||||
adaptor net.DeviceDriver
|
||||
adaptor net.Adapter
|
||||
conn net.Conn
|
||||
connected bool
|
||||
opts *ClientOptions
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ type ClientOptionsReader struct {
|
||||
|
||||
// ClientOptions contains configurable options for an MQTT Client.
|
||||
type ClientOptions struct {
|
||||
Adaptor net.DeviceDriver
|
||||
Adaptor net.Adapter
|
||||
|
||||
//Servers []*url.URL
|
||||
Servers string
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ func Dial(network, address string) (Conn, error) {
|
||||
|
||||
// SerialConn is a loosely net.Conn compatible implementation
|
||||
type SerialConn struct {
|
||||
Adaptor DeviceDriver
|
||||
Adaptor Adapter
|
||||
}
|
||||
|
||||
// UDPSerialConn is a loosely net.Conn compatible intended to support
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package pca9685
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrInvalidMode1 = errors.New("pca9685: data read from MODE1 not valid")
|
||||
ErrBadPeriod = errors.New("pca9685: period must be in range 1..25ms")
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package pca9685
|
||||
|
||||
func (d *Dev) readReg(reg uint8, data []byte) error {
|
||||
return d.bus.ReadRegister(d.addr, reg, data)
|
||||
}
|
||||
|
||||
func (d *Dev) writeReg(reg uint8, data []byte) error {
|
||||
return d.bus.WriteRegister(d.addr, reg, data)
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package pca9685
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
const (
|
||||
// Internal oscillator frequency.
|
||||
oscclock = 25000000
|
||||
// Max value PWM value (on or off) can take.
|
||||
maxtop = 1<<12 - 1
|
||||
milliseconds = 1_000_000 // units in nanoseconds
|
||||
)
|
||||
|
||||
// Dev is a handle to the PCA9685 device given an address
|
||||
// (usually 0x47) and an i2c bus.
|
||||
type Dev struct {
|
||||
addr uint8
|
||||
bus drivers.I2C
|
||||
buf [4]byte
|
||||
}
|
||||
|
||||
type PWMConfig struct {
|
||||
Period uint64
|
||||
}
|
||||
|
||||
// New creates a new instance of a PCA9685 device. It performs
|
||||
// no IO on the i2c bus.
|
||||
func New(bus drivers.I2C, addr uint8) Dev {
|
||||
return Dev{
|
||||
bus: bus,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure enables autoincrement, sets all PWM signals to logic low (Ground)
|
||||
// and finally sets the Period.
|
||||
func (d Dev) Configure(cfg PWMConfig) error {
|
||||
err := d.SetAI(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.SetAll(0)
|
||||
d.SetDrive(true)
|
||||
return d.SetPeriod(cfg.Period)
|
||||
}
|
||||
|
||||
// SetPeriod updates the period of this PWM integrated circuit in nanoseconds.
|
||||
// To set a particular frequency, use the following formula:
|
||||
//
|
||||
// period = 1e9 / frequency
|
||||
//
|
||||
// In the equation above frequency is in Hertz.
|
||||
//
|
||||
// If you use a period of 0, a period that works well for LEDs will be picked.
|
||||
//
|
||||
// PCA9685 accepts frequencies inbetween [40..1000 Hz],
|
||||
// or expressed as a period [1..25ms].
|
||||
func (d Dev) SetPeriod(period uint64) error {
|
||||
const div = maxtop + 1
|
||||
if period == 0 {
|
||||
period = 1 * milliseconds
|
||||
}
|
||||
if period > 25*milliseconds || period < 1*milliseconds {
|
||||
return ErrBadPeriod
|
||||
}
|
||||
// Correct for overshoot in provided frequency: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/issues/11
|
||||
// Note: 0.96 was empirically determined to be closer. Should follow up to understand what is happening here.
|
||||
freq := 96 * 1e9 / (100 * period)
|
||||
prescale := byte(oscclock/(div*freq) - 1)
|
||||
err := d.Sleep(true) // Enable sleep to write to PRESCALE register
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.buf[0] = prescale
|
||||
err = d.writeReg(PRESCALE, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.Sleep(false)
|
||||
}
|
||||
|
||||
// Top returns max value PWM can take.
|
||||
func (d Dev) Top() uint32 {
|
||||
return maxtop
|
||||
}
|
||||
|
||||
// Set sets the `on` value of a PWM channel in the range [0..15].
|
||||
// Example:
|
||||
// d.Set(1, d.Top()/4)
|
||||
// sets the dutycycle of second (LED1) channel to 25%.
|
||||
func (d Dev) Set(channel uint8, on uint32) {
|
||||
switch {
|
||||
case on > maxtop:
|
||||
panic("pca9685: value must be in range 0..4096")
|
||||
case on == 0:
|
||||
d.SetPhased(channel, 0, maxtop)
|
||||
return
|
||||
}
|
||||
|
||||
d.SetPhased(channel, on, 0)
|
||||
}
|
||||
|
||||
// SetAll sets all PWM signals to a ON value. Equivalent of calling
|
||||
// Dev.Set(pca9685.ALLLED, value)
|
||||
func (d Dev) SetAll(on uint32) {
|
||||
d.Set(ALLLED, on)
|
||||
}
|
||||
|
||||
// IsConnected returns error if read fails or if
|
||||
// driver suspects device is not connected.
|
||||
func (d Dev) IsConnected() error {
|
||||
// Set data to the NOT of default MODE1 contents.
|
||||
// If read is succesful then data will be modified
|
||||
const notdefaultMODE1 = ^defaultMODE1Value
|
||||
d.buf[0] = notdefaultMODE1
|
||||
|
||||
err := d.readReg(MODE1, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
} else if d.buf[0] == notdefaultMODE1 {
|
||||
return ErrInvalidMode1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAI enables or disables autoincrement feature on device. Useful for
|
||||
// writing to many consecutive registers in one shot.
|
||||
func (d Dev) SetAI(ai bool) error {
|
||||
err := d.readReg(MODE1, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ai {
|
||||
d.buf[0] |= AI
|
||||
} else {
|
||||
d.buf[0] &^= AI
|
||||
}
|
||||
err = d.writeReg(MODE1, d.buf[:1])
|
||||
return err
|
||||
}
|
||||
|
||||
// SetDrive configures PWM output connection in MODE2 register.
|
||||
// false: The 16 LEDn outputs are configured with an open-drain structure.
|
||||
// true: The 16 LEDn outputs are configured with a totem pole structure.
|
||||
func (d Dev) SetDrive(outdrv bool) error {
|
||||
err := d.readReg(MODE2, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if outdrv {
|
||||
d.buf[0] |= OUTDRV
|
||||
} else {
|
||||
d.buf[0] &^= OUTDRV
|
||||
}
|
||||
return d.writeReg(MODE2, d.buf[:1])
|
||||
}
|
||||
|
||||
// Sleep sets/unsets SLEEP bit in MODE1.
|
||||
// if sleepEnabled
|
||||
// Stops PWM. Allows writing to PRE_SCALE register.
|
||||
// else
|
||||
// wakes PCA9685. Resumes PWM.
|
||||
func (d Dev) Sleep(sleepEnabled bool) error {
|
||||
err := d.readReg(MODE1, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sleepEnabled {
|
||||
d.buf[0] |= SLEEP
|
||||
return d.writeReg(MODE1, d.buf[:1])
|
||||
}
|
||||
d.buf[0] &^= SLEEP
|
||||
err = d.writeReg(MODE1, d.buf[:1])
|
||||
// It takes 500μs max for the oscillator to be up and running once SLEEP bit
|
||||
// has been set to logic 0. Timings on LEDn outputs are not guaranteed if PWM
|
||||
// control registers are accessed within the 500μs window.
|
||||
// There is no start-up delay required when using the EXTCLK pin as the PWM clock.
|
||||
time.Sleep(1000 * time.Microsecond) // Requested by datasheet.
|
||||
return err
|
||||
}
|
||||
|
||||
// SetInverting inverts ALL PCA9685 PWMs. The channel argument merely implements PWM interface.
|
||||
//
|
||||
// Without inverting, a 25% duty cycle would mean the output is high for 25% of
|
||||
// the time and low for the rest. Inverting flips the output as if a NOT gate
|
||||
// was placed at the output, meaning that the output would be 25% low and 75%
|
||||
// high with a duty cycle of 25%.
|
||||
func (d Dev) SetInverting(_ uint8, inverting bool) error {
|
||||
err := d.readReg(MODE2, d.buf[:1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if inverting {
|
||||
d.buf[0] |= INVRT
|
||||
} else {
|
||||
d.buf[0] &^= INVRT
|
||||
}
|
||||
return d.writeReg(MODE2, d.buf[:1])
|
||||
}
|
||||
|
||||
// SetPhased sets PWM on and off mark.
|
||||
// The ON time, which is programmable, will be the time the LED output
|
||||
// will be asserted and the OFF time, which is also programmable, will be
|
||||
// the time when the LED output will be negated.
|
||||
// In this way, the phase shift becomes completely programmable.
|
||||
// The resolution for the phase shift is 1⁄4096 of the target frequency.
|
||||
func (d Dev) SetPhased(channel uint8, on, off uint32) {
|
||||
binary.LittleEndian.PutUint16(d.buf[:2], uint16(on)&maxtop)
|
||||
binary.LittleEndian.PutUint16(d.buf[2:4], uint16(off)&maxtop)
|
||||
onLReg, _, _, _ := LED(channel)
|
||||
d.writeReg(onLReg, d.buf[:4])
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package pca9685
|
||||
|
||||
// Software reset addresses for generic i2c implementation
|
||||
// and PCA specific SWRST. See section 7.6
|
||||
const (
|
||||
I2CSWRSTADR = 0x0
|
||||
PCA9685SWRSTBYTE = 0b0000_0110 // 0x06
|
||||
)
|
||||
|
||||
// Registries with nomenclature as seen in manual
|
||||
const (
|
||||
SUBADR1 uint8 = 0x2
|
||||
SUBADR2 uint8 = 0x3
|
||||
SUBADR3 uint8 = 0x4
|
||||
|
||||
MODE1 uint8 = 0x0
|
||||
MODE2 uint8 = 0x1
|
||||
ALLCALLADR uint8 = 0x05
|
||||
|
||||
SWRESET uint8 = 0b0000_0011
|
||||
|
||||
// Start of LED registries. corresponds to LED0_ON_L register.
|
||||
// Use LED function to get registries of a specific PWM channel register.
|
||||
LEDSTART = 0x06
|
||||
)
|
||||
|
||||
// MODE1
|
||||
const (
|
||||
RESET byte = 0b1000_0000
|
||||
EXTCLK byte = 0b0100_0000
|
||||
AI byte = 0b0010_0000
|
||||
SLEEP byte = 0b0001_0000
|
||||
defaultMODE1Value byte = 0b0001_0001
|
||||
)
|
||||
|
||||
// MODE2
|
||||
const (
|
||||
OUTDRV = 1 << 2
|
||||
INVRT = 1 << 4
|
||||
)
|
||||
|
||||
// LED channels from 0-15. Returns 4 registries associated with
|
||||
// the channel PWM signal. Channel 250 (0xFA) gives ALL_LED registers.
|
||||
// The L suffix represents the 8 LSB of 12 bit timing, the H suffix represents
|
||||
// the 4 MSB of the timing. This way you have 0-4095 timing options. ON or OFF
|
||||
// will be a number between these two or will be simply ON or OFF (fifth bit of H registry).
|
||||
//
|
||||
// The SetPWM implementation in this library does not do phase-shifting so OFF will always
|
||||
// happen at time stamp 0. ON will solely decide duty cycle.
|
||||
func LED(ch uint8) (ONL, ONH, OFFL, OFFH uint8) {
|
||||
switch {
|
||||
case ch == ALLLED:
|
||||
return ALLLED, ALLLED + 1, ALLLED + 2, ALLLED + 3
|
||||
|
||||
case ch > 15:
|
||||
panic("PWM channel out of range [0-15]")
|
||||
default:
|
||||
}
|
||||
// 4 registries per channel. Starts at 6
|
||||
onLReg := LEDSTART + 4*ch
|
||||
return onLReg, onLReg + 1, onLReg + 2, onLReg + 3
|
||||
}
|
||||
|
||||
const (
|
||||
// ALLLED is channel that selects registries to control all leds. Use with function LED
|
||||
ALLLED = 0xfa
|
||||
// PRESCALE Prescaling byte
|
||||
PRESCALE byte = 0xFE
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
package rtl8720dn
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
func (r *RTL8720DN) ConnectToAccessPoint(ssid, pass string, timeout time.Duration) error {
|
||||
if len(ssid) == 0 {
|
||||
return net.ErrWiFiMissingSSID
|
||||
}
|
||||
|
||||
return r.ConnectToAP(ssid, pass)
|
||||
}
|
||||
|
||||
func (r *RTL8720DN) Disconnect() error {
|
||||
_, err := r.Rpc_wifi_disconnect()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *RTL8720DN) GetClientIP() (string, error) {
|
||||
ip, _, _, err := r.GetIP()
|
||||
return ip.String(), err
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package shtc3
|
||||
|
||||
// Constants used for I2C.
|
||||
|
||||
const (
|
||||
SHTC3_ADDRESS = 0x70
|
||||
SHTC3_CMD_WAKEUP = "\x35\x17" // Wake up
|
||||
SHTC3_CMD_MEASURE_HP = "\x7C\xA2" // Read sensor in high power mode with clock stretching
|
||||
SHTC3_CMD_SLEEP = "\xB0\x98" // Sleep
|
||||
SHTC3_CMD_SOFT_RESET = "\x80\x5D" // Soft Reset
|
||||
)
|
||||
@@ -0,0 +1,79 @@
|
||||
// Package shtc3 provides a driver for the SHTC3 digital humidity sensor
|
||||
// series by Sensirion.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf
|
||||
//
|
||||
package shtc3 // import "tinygo.org/x/drivers/shtc3"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a SHT31 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
}
|
||||
|
||||
// New creates a new SHTC3 connection. The I2C bus must already be
|
||||
// configured.
|
||||
//
|
||||
// This function only creates the Device object, it does not initialize the device.
|
||||
// You must call Configure() first in order to use the device itself.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: bus,
|
||||
}
|
||||
}
|
||||
|
||||
// Read returns the temperature in celsius milli degrees (°C/1000).
|
||||
func (d *Device) ReadTemperature() (tempMilliCelsius int32, err error) {
|
||||
tempMilliCelsius, _, err = d.ReadTemperatureHumidity()
|
||||
return tempMilliCelsius, err
|
||||
}
|
||||
|
||||
// Read returns the relative humidity in hundredths of a percent.
|
||||
func (d *Device) ReadHumidity() (relativeHumidity int16, err error) {
|
||||
_, relativeHumidity, err = d.ReadTemperatureHumidity()
|
||||
return relativeHumidity, err
|
||||
}
|
||||
|
||||
// Read returns both the temperature and relative humidity.
|
||||
func (d *Device) ReadTemperatureHumidity() (tempMilliCelsius int32, relativeHumidity int16, err error) {
|
||||
var rawTemp, rawHum, errx = d.rawReadings()
|
||||
if errx != nil {
|
||||
err = errx
|
||||
return
|
||||
}
|
||||
tempMilliCelsius = ((21875 * int32(rawTemp)) >> 13) - 45000
|
||||
relativeHumidity = int16((1250 * int32(rawHum)) >> 13)
|
||||
return tempMilliCelsius, relativeHumidity, err
|
||||
}
|
||||
|
||||
// rawReadings returns the sensor's raw values of the temperature and humidity
|
||||
func (d *Device) rawReadings() (uint16, uint16, error) {
|
||||
var data [6]byte
|
||||
d.bus.Tx(SHTC3_ADDRESS, []byte(SHTC3_CMD_MEASURE_HP), data[:])
|
||||
// ignore crc for now
|
||||
return readUint(data[0], data[1]), readUint(data[3], data[4]), nil
|
||||
}
|
||||
|
||||
// WakeUp makes device leave sleep mode
|
||||
func (d *Device) WakeUp() error {
|
||||
d.bus.Tx(SHTC3_ADDRESS, []byte(SHTC3_CMD_WAKEUP), nil)
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sleep makes device go to sleep
|
||||
func (d *Device) Sleep() error {
|
||||
d.bus.Tx(SHTC3_ADDRESS, []byte(SHTC3_CMD_SLEEP), nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// readUint converts two bytes to uint16
|
||||
func readUint(msb byte, lsb byte) uint16 {
|
||||
return (uint16(msb) << 8) | uint16(lsb)
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package sx126x
|
||||
|
||||
const (
|
||||
// SX126X physical layer properties
|
||||
SX126X_FREQUENCY_STEP_SIZE = 0.9536743164
|
||||
SX126X_MAX_PACKET_LENGTH = 255
|
||||
SX126X_CRYSTAL_FREQ = 32.0
|
||||
SX126X_DIV_EXPONENT = 25
|
||||
|
||||
// SX126X SPI commands
|
||||
// operational modes commands
|
||||
SX126X_CMD_NOP = 0x00
|
||||
SX126X_CMD_SET_SLEEP = 0x84
|
||||
SX126X_CMD_SET_STANDBY = 0x80
|
||||
SX126X_CMD_SET_FS = 0xC1
|
||||
SX126X_CMD_SET_TX = 0x83
|
||||
SX126X_CMD_SET_RX = 0x82
|
||||
SX126X_CMD_STOP_TIMER_ON_PREAMBLE = 0x9F
|
||||
SX126X_CMD_SET_RX_DUTY_CYCLE = 0x94
|
||||
SX126X_CMD_SET_CAD = 0xC5
|
||||
SX126X_CMD_SET_TX_CONTINUOUS_WAVE = 0xD1
|
||||
SX126X_CMD_SET_TX_INFINITE_PREAMBLE = 0xD2
|
||||
SX126X_CMD_SET_REGULATOR_MODE = 0x96
|
||||
SX126X_CMD_CALIBRATE = 0x89
|
||||
SX126X_CMD_CALIBRATE_IMAGE = 0x98
|
||||
SX126X_CMD_SET_PA_CONFIG = 0x95
|
||||
SX126X_CMD_SET_RX_TX_FALLBACK_MODE = 0x93
|
||||
|
||||
// register and buffer access commands
|
||||
SX126X_CMD_WRITE_REGISTER = 0x0D
|
||||
SX126X_CMD_READ_REGISTER = 0x1D
|
||||
SX126X_CMD_WRITE_BUFFER = 0x0E
|
||||
SX126X_CMD_READ_BUFFER = 0x1E
|
||||
|
||||
// DIO and IRQ control
|
||||
SX126X_CMD_SET_DIO_IRQ_PARAMS = 0x08
|
||||
SX126X_CMD_GET_IRQ_STATUS = 0x12
|
||||
SX126X_CMD_CLEAR_IRQ_STATUS = 0x02
|
||||
SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL = 0x9D
|
||||
SX126X_CMD_SET_DIO3_AS_TCXO_CTRL = 0x97
|
||||
|
||||
// RF, modulation and packet commands
|
||||
SX126X_CMD_SET_RF_FREQUENCY = 0x86
|
||||
SX126X_CMD_SET_PACKET_TYPE = 0x8A
|
||||
SX126X_CMD_GET_PACKET_TYPE = 0x11
|
||||
SX126X_CMD_SET_TX_PARAMS = 0x8E
|
||||
SX126X_CMD_SET_MODULATION_PARAMS = 0x8B
|
||||
SX126X_CMD_SET_PACKET_PARAMS = 0x8C
|
||||
SX126X_CMD_SET_CAD_PARAMS = 0x88
|
||||
SX126X_CMD_SET_BUFFER_BASE_ADDRESS = 0x8F
|
||||
SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT = 0x0A
|
||||
|
||||
// status commands
|
||||
SX126X_CMD_GET_STATUS = 0xC0
|
||||
SX126X_CMD_GET_RSSI_INST = 0x15
|
||||
SX126X_CMD_GET_RX_BUFFER_STATUS = 0x13
|
||||
SX126X_CMD_GET_PACKET_STATUS = 0x14
|
||||
SX126X_CMD_GET_DEVICE_ERRORS = 0x17
|
||||
SX126X_CMD_CLEAR_DEVICE_ERRORS = 0x07
|
||||
SX126X_CMD_GET_STATS = 0x10
|
||||
SX126X_CMD_RESET_STATS = 0x00
|
||||
|
||||
// SX126X register map
|
||||
SX126X_REG_WHITENING_INITIAL_MSB = 0x06B8
|
||||
SX126X_REG_WHITENING_INITIAL_LSB = 0x06B9
|
||||
SX126X_REG_CRC_INITIAL_MSB = 0x06BC
|
||||
SX126X_REG_CRC_INITIAL_LSB = 0x06BD
|
||||
SX126X_REG_CRC_POLYNOMIAL_MSB = 0x06BE
|
||||
SX126X_REG_CRC_POLYNOMIAL_LSB = 0x06BF
|
||||
SX126X_REG_SYNC_WORD_0 = 0x06C0
|
||||
SX126X_REG_SYNC_WORD_1 = 0x06C1
|
||||
SX126X_REG_SYNC_WORD_2 = 0x06C2
|
||||
SX126X_REG_SYNC_WORD_3 = 0x06C3
|
||||
SX126X_REG_SYNC_WORD_4 = 0x06C4
|
||||
SX126X_REG_SYNC_WORD_5 = 0x06C5
|
||||
SX126X_REG_SYNC_WORD_6 = 0x06C6
|
||||
SX126X_REG_SYNC_WORD_7 = 0x06C7
|
||||
SX126X_REG_NODE_ADDRESS = 0x06CD
|
||||
SX126X_REG_BROADCAST_ADDRESS = 0x06CE
|
||||
SX126X_REG_LORA_SYNC_WORD_MSB = 0x0740
|
||||
SX126X_REG_LORA_SYNC_WORD_LSB = 0x0741
|
||||
SX126X_REG_RANDOM_NUMBER_0 = 0x0819
|
||||
SX126X_REG_RANDOM_NUMBER_1 = 0x081A
|
||||
SX126X_REG_RANDOM_NUMBER_2 = 0x081B
|
||||
SX126X_REG_RANDOM_NUMBER_3 = 0x081C
|
||||
SX126X_REG_RX_GAIN = 0x08AC
|
||||
SX126X_REG_OCP_CONFIGURATION = 0x08E7
|
||||
SX126X_REG_XTA_TRIM = 0x0911
|
||||
SX126X_REG_XTB_TRIM = 0x0912
|
||||
|
||||
// undocumented registers
|
||||
SX126X_REG_SENSITIVITY_CONFIG = 0x0889 // SX1268 datasheet v1.1, section 15.1
|
||||
SX126X_REG_TX_CLAMP_CONFIG = 0x08D8 // SX1268 datasheet v1.1, section 15.2
|
||||
SX126X_REG_RTC_STOP = 0x0920 // SX1268 datasheet v1.1, section 15.3
|
||||
SX126X_REG_RTC_EVENT = 0x0944 // SX1268 datasheet v1.1, section 15.3
|
||||
SX126X_REG_IQ_CONFIG = 0x0736 // SX1268 datasheet v1.1, section 15.4
|
||||
SX126X_REG_RX_GAIN_RETENTION_0 = 0x029F // SX1268 datasheet v1.1, section 9.6
|
||||
SX126X_REG_RX_GAIN_RETENTION_1 = 0x02A0 // SX1268 datasheet v1.1, section 9.6
|
||||
SX126X_REG_RX_GAIN_RETENTION_2 = 0x02A1 // SX1268 datasheet v1.1, section 9.6
|
||||
|
||||
// SX126X SPI command variables
|
||||
//SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION
|
||||
SX126X_SLEEP_START_COLD = 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default)
|
||||
SX126X_SLEEP_START_WARM = 0b00000100 // 2 2 warm start, configuration is retained
|
||||
SX126X_SLEEP_RTC_OFF = 0b00000000 // 0 0 wake on RTC timeout: disabled
|
||||
SX126X_SLEEP_RTC_ON = 0b00000001 // 0 0 enabled
|
||||
|
||||
//SX126X_CMD_SET_STANDBY
|
||||
SX126X_STANDBY_RC = 0x00 // 7 0 standby mode: 13 MHz RC oscillator
|
||||
SX126X_STANDBY_XOSC = 0x01 // 7 0 32 MHz crystal oscillator
|
||||
|
||||
//SX126X_CMD_SET_RX
|
||||
SX126X_RX_TIMEOUT_NONE = 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode)
|
||||
SX126X_RX_TIMEOUT_INF = 0xFFFFFF // 23 0 infinite (Rx continuous mode)
|
||||
|
||||
//SX126X_CMD_SET_TX
|
||||
SX126X_TX_TIMEOUT_NONE = 0x000000 // 23 0 Tx timeout duration: no timeout (Tx single mode)
|
||||
|
||||
//SX126X_CMD_STOP_TIMER_ON_PREAMBLE
|
||||
SX126X_STOP_ON_PREAMBLE_OFF = 0x00 // 7 0 stop timer on: sync word or header (default)
|
||||
SX126X_STOP_ON_PREAMBLE_ON = 0x01 // 7 0 preamble detection
|
||||
|
||||
//SX126X_CMD_SET_REGULATOR_MODE
|
||||
SX126X_REGULATOR_LDO = 0x00 // 7 0 set regulator mode: LDO (default)
|
||||
SX126X_REGULATOR_DC_DC = 0x01 // 7 0 DC-DC
|
||||
|
||||
//SX126X_CMD_CALIBRATE
|
||||
SX126X_CALIBRATE_IMAGE_OFF = 0b00000000 // 6 6 image calibration: disabled
|
||||
SX126X_CALIBRATE_IMAGE_ON = 0b01000000 // 6 6 enabled
|
||||
SX126X_CALIBRATE_ADC_BULK_P_OFF = 0b00000000 // 5 5 ADC bulk P calibration: disabled
|
||||
SX126X_CALIBRATE_ADC_BULK_P_ON = 0b00100000 // 5 5 enabled
|
||||
SX126X_CALIBRATE_ADC_BULK_N_OFF = 0b00000000 // 4 4 ADC bulk N calibration: disabled
|
||||
SX126X_CALIBRATE_ADC_BULK_N_ON = 0b00010000 // 4 4 enabled
|
||||
SX126X_CALIBRATE_ADC_PULSE_OFF = 0b00000000 // 3 3 ADC pulse calibration: disabled
|
||||
SX126X_CALIBRATE_ADC_PULSE_ON = 0b00001000 // 3 3 enabled
|
||||
SX126X_CALIBRATE_PLL_OFF = 0b00000000 // 2 2 PLL calibration: disabled
|
||||
SX126X_CALIBRATE_PLL_ON = 0b00000100 // 2 2 enabled
|
||||
SX126X_CALIBRATE_RC13M_OFF = 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled
|
||||
SX126X_CALIBRATE_RC13M_ON = 0b00000010 // 1 1 enabled
|
||||
SX126X_CALIBRATE_RC64K_OFF = 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled
|
||||
SX126X_CALIBRATE_RC64K_ON = 0b00000001 // 0 0 enabled
|
||||
SX126X_CALIBRATE_ALL = 0b01111111 // 6 0 calibrate all blocks
|
||||
|
||||
//SX126X_CMD_CALIBRATE_IMAGE
|
||||
SX126X_CAL_IMG_430_MHZ_1 = 0x6B
|
||||
SX126X_CAL_IMG_430_MHZ_2 = 0x6F
|
||||
SX126X_CAL_IMG_470_MHZ_1 = 0x75
|
||||
SX126X_CAL_IMG_470_MHZ_2 = 0x81
|
||||
SX126X_CAL_IMG_779_MHZ_1 = 0xC1
|
||||
SX126X_CAL_IMG_779_MHZ_2 = 0xC5
|
||||
SX126X_CAL_IMG_863_MHZ_1 = 0xD7
|
||||
SX126X_CAL_IMG_863_MHZ_2 = 0xDB
|
||||
SX126X_CAL_IMG_902_MHZ_1 = 0xE1
|
||||
SX126X_CAL_IMG_902_MHZ_2 = 0xE9
|
||||
|
||||
//SX126X_CMD_SET_PA_CONFIG
|
||||
SX126X_PA_CONFIG_HP_MAX = 0x07
|
||||
SX126X_PA_CONFIG_PA_LUT = 0x01
|
||||
SX126X_PA_CONFIG_SX1262_8 = 0x00
|
||||
|
||||
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE
|
||||
SX126X_RX_TX_FALLBACK_MODE_FS = 0x40 // 7 0 after Rx/Tx go to: FS mode
|
||||
SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC = 0x30 // 7 0 standby with crystal oscillator
|
||||
SX126X_RX_TX_FALLBACK_MODE_STDBY_RC = 0x20 // 7 0 standby with RC oscillator (default)
|
||||
|
||||
//SX126X_CMD_SET_DIO_IRQ_PARAMS
|
||||
SX126X_IRQ_TIMEOUT = 0b1000000000 // 9 9 Rx or Tx timeout
|
||||
SX126X_IRQ_CAD_DETECTED = 0b0100000000 // 8 8 channel activity detected
|
||||
SX126X_IRQ_CAD_DONE = 0b0010000000 // 7 7 channel activity detection finished
|
||||
SX126X_IRQ_CRC_ERR = 0b0001000000 // 6 6 wrong CRC received
|
||||
SX126X_IRQ_HEADER_ERR = 0b0000100000 // 5 5 LoRa header CRC error
|
||||
SX126X_IRQ_HEADER_VALID = 0b0000010000 // 4 4 valid LoRa header received
|
||||
SX126X_IRQ_SYNC_WORD_VALID = 0b0000001000 // 3 3 valid sync word detected
|
||||
SX126X_IRQ_PREAMBLE_DETECTED = 0b0000000100 // 2 2 preamble detected
|
||||
SX126X_IRQ_RX_DONE = 0b0000000010 // 1 1 packet received
|
||||
SX126X_IRQ_TX_DONE = 0b0000000001 // 0 0 packet transmission completed
|
||||
SX126X_IRQ_ALL = 0b1111111111 // 9 0 all interrupts
|
||||
SX126X_IRQ_NONE = 0b0000000000 // 9 0 no interrupts
|
||||
|
||||
//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
|
||||
SX126X_DIO2_AS_IRQ = 0x00 // 7 0 DIO2 configuration: IRQ
|
||||
SX126X_DIO2_AS_RF_SWITCH = 0x01 // 7 0 RF switch control
|
||||
|
||||
//SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
|
||||
SX126X_DIO3_OUTPUT_1_6 = 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V
|
||||
SX126X_DIO3_OUTPUT_1_7 = 0x01 // 7 0 1.7 V
|
||||
SX126X_DIO3_OUTPUT_1_8 = 0x02 // 7 0 1.8 V
|
||||
SX126X_DIO3_OUTPUT_2_2 = 0x03 // 7 0 2.2 V
|
||||
SX126X_DIO3_OUTPUT_2_4 = 0x04 // 7 0 2.4 V
|
||||
SX126X_DIO3_OUTPUT_2_7 = 0x05 // 7 0 2.7 V
|
||||
SX126X_DIO3_OUTPUT_3_0 = 0x06 // 7 0 3.0 V
|
||||
SX126X_DIO3_OUTPUT_3_3 = 0x07 // 7 0 3.3 V
|
||||
|
||||
//SX126X_CMD_SET_PACKET_TYPE
|
||||
SX126X_PACKET_TYPE_GFSK = 0x00 // 7 0 packet type: GFSK
|
||||
SX126X_PACKET_TYPE_LORA = 0x01 // 7 0 LoRa
|
||||
|
||||
//SX126X_CMD_SET_TX_PARAMS
|
||||
SX126X_PA_RAMP_10U = 0x00 // 7 0 ramp time: 10 us
|
||||
SX126X_PA_RAMP_20U = 0x01 // 7 0 20 us
|
||||
SX126X_PA_RAMP_40U = 0x02 // 7 0 40 us
|
||||
SX126X_PA_RAMP_80U = 0x03 // 7 0 80 us
|
||||
SX126X_PA_RAMP_200U = 0x04 // 7 0 200 us
|
||||
SX126X_PA_RAMP_800U = 0x05 // 7 0 800 us
|
||||
SX126X_PA_RAMP_1700U = 0x06 // 7 0 1700 us
|
||||
SX126X_PA_RAMP_3400U = 0x07 // 7 0 3400 us
|
||||
|
||||
//SX126X_CMD_SET_MODULATION_PARAMS
|
||||
SX126X_GFSK_FILTER_NONE = 0x00 // 7 0 GFSK filter: none
|
||||
SX126X_GFSK_FILTER_GAUSS_0_3 = 0x08 // 7 0 Gaussian, BT = 0.3
|
||||
SX126X_GFSK_FILTER_GAUSS_0_5 = 0x09 // 7 0 Gaussian, BT = 0.5
|
||||
SX126X_GFSK_FILTER_GAUSS_0_7 = 0x0A // 7 0 Gaussian, BT = 0.7
|
||||
SX126X_GFSK_FILTER_GAUSS_1 = 0x0B // 7 0 Gaussian, BT = 1
|
||||
SX126X_GFSK_RX_BW_4_8 = 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz
|
||||
SX126X_GFSK_RX_BW_5_8 = 0x17 // 7 0 5.8 kHz
|
||||
SX126X_GFSK_RX_BW_7_3 = 0x0F // 7 0 7.3 kHz
|
||||
SX126X_GFSK_RX_BW_9_7 = 0x1E // 7 0 9.7 kHz
|
||||
SX126X_GFSK_RX_BW_11_7 = 0x16 // 7 0 11.7 kHz
|
||||
SX126X_GFSK_RX_BW_14_6 = 0x0E // 7 0 14.6 kHz
|
||||
SX126X_GFSK_RX_BW_19_5 = 0x1D // 7 0 19.5 kHz
|
||||
SX126X_GFSK_RX_BW_23_4 = 0x15 // 7 0 23.4 kHz
|
||||
SX126X_GFSK_RX_BW_29_3 = 0x0D // 7 0 29.3 kHz
|
||||
SX126X_GFSK_RX_BW_39_0 = 0x1C // 7 0 39.0 kHz
|
||||
SX126X_GFSK_RX_BW_46_9 = 0x14 // 7 0 46.9 kHz
|
||||
SX126X_GFSK_RX_BW_58_6 = 0x0C // 7 0 58.6 kHz
|
||||
SX126X_GFSK_RX_BW_78_2 = 0x1B // 7 0 78.2 kHz
|
||||
SX126X_GFSK_RX_BW_93_8 = 0x13 // 7 0 93.8 kHz
|
||||
SX126X_GFSK_RX_BW_117_3 = 0x0B // 7 0 117.3 kHz
|
||||
SX126X_GFSK_RX_BW_156_2 = 0x1A // 7 0 156.2 kHz
|
||||
SX126X_GFSK_RX_BW_187_2 = 0x12 // 7 0 187.2 kHz
|
||||
SX126X_GFSK_RX_BW_234_3 = 0x0A // 7 0 234.3 kHz
|
||||
SX126X_GFSK_RX_BW_312_0 = 0x19 // 7 0 312.0 kHz
|
||||
SX126X_GFSK_RX_BW_373_6 = 0x11 // 7 0 373.6 kHz
|
||||
SX126X_GFSK_RX_BW_467_0 = 0x09 // 7 0 467.0 kHz
|
||||
SX126X_LORA_BW_7_8 = 0x00 // 7 0 LoRa bandwidth: 7.8 kHz
|
||||
SX126X_LORA_BW_10_4 = 0x08 // 7 0 10.4 kHz
|
||||
SX126X_LORA_BW_15_6 = 0x01 // 7 0 15.6 kHz
|
||||
SX126X_LORA_BW_20_8 = 0x09 // 7 0 20.8 kHz
|
||||
SX126X_LORA_BW_31_25 = 0x02 // 7 0 31.25 kHz
|
||||
SX126X_LORA_BW_41_7 = 0x0A // 7 0 41.7 kHz
|
||||
SX126X_LORA_BW_62_5 = 0x03 // 7 0 62.5 kHz
|
||||
SX126X_LORA_BW_125_0 = 0x04 // 7 0 125.0 kHz
|
||||
SX126X_LORA_BW_250_0 = 0x05 // 7 0 250.0 kHz
|
||||
SX126X_LORA_BW_500_0 = 0x06 // 7 0 500.0 kHz
|
||||
SX126X_LORA_CR_4_5 = 0x01 // 7 0 LoRa coding rate: 4/5
|
||||
SX126X_LORA_CR_4_6 = 0x02 // 7 0 4/6
|
||||
SX126X_LORA_CR_4_7 = 0x03 // 7 0 4/7
|
||||
SX126X_LORA_CR_4_8 = 0x04 // 7 0 4/8
|
||||
SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF = 0x00 // 7 0 LoRa low data rate optimization: disabled
|
||||
SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON = 0x01 // 7 0 enabled
|
||||
|
||||
//SX126X_CMD_SET_PACKET_PARAMS
|
||||
SX126X_GFSK_PREAMBLE_DETECT_OFF = 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
|
||||
SX126X_GFSK_PREAMBLE_DETECT_8 = 0x04 // 7 0 8 bits
|
||||
SX126X_GFSK_PREAMBLE_DETECT_16 = 0x05 // 7 0 16 bits
|
||||
SX126X_GFSK_PREAMBLE_DETECT_24 = 0x06 // 7 0 24 bits
|
||||
SX126X_GFSK_PREAMBLE_DETECT_32 = 0x07 // 7 0 32 bits
|
||||
SX126X_GFSK_ADDRESS_FILT_OFF = 0x00 // 7 0 GFSK address filtering: disabled
|
||||
SX126X_GFSK_ADDRESS_FILT_NODE = 0x01 // 7 0 node only
|
||||
SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST = 0x02 // 7 0 node and broadcast
|
||||
SX126X_GFSK_PACKET_FIXED = 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides)
|
||||
SX126X_GFSK_PACKET_VARIABLE = 0x01 // 7 0 variable (payload length added to packet)
|
||||
SX126X_GFSK_CRC_OFF = 0x01 // 7 0 GFSK packet CRC: disabled
|
||||
SX126X_GFSK_CRC_1_BYTE = 0x00 // 7 0 1 byte
|
||||
SX126X_GFSK_CRC_2_BYTE = 0x02 // 7 0 2 byte
|
||||
SX126X_GFSK_CRC_1_BYTE_INV = 0x04 // 7 0 1 byte, inverted
|
||||
SX126X_GFSK_CRC_2_BYTE_INV = 0x06 // 7 0 2 byte, inverted
|
||||
SX126X_GFSK_WHITENING_OFF = 0x00 // 7 0 GFSK data whitening: disabled
|
||||
SX126X_GFSK_WHITENING_ON = 0x01 // 7 0 enabled
|
||||
SX126X_LORA_HEADER_EXPLICIT = 0x00 // 7 0 LoRa header mode: explicit
|
||||
SX126X_LORA_HEADER_IMPLICIT = 0x01 // 7 0 implicit
|
||||
SX126X_LORA_CRC_OFF = 0x00 // 7 0 LoRa CRC mode: disabled
|
||||
SX126X_LORA_CRC_ON = 0x01 // 7 0 enabled
|
||||
SX126X_LORA_IQ_STANDARD = 0x00 // 7 0 LoRa IQ setup: standard
|
||||
SX126X_LORA_IQ_INVERTED = 0x01 // 7 0 inverted
|
||||
|
||||
//SX126X_CMD_SET_CAD_PARAMS
|
||||
SX126X_CAD_ON_1_SYMB = 0x00 // 7 0 number of symbols used for CAD: 1
|
||||
SX126X_CAD_ON_2_SYMB = 0x01 // 7 0 2
|
||||
SX126X_CAD_ON_4_SYMB = 0x02 // 7 0 4
|
||||
SX126X_CAD_ON_8_SYMB = 0x03 // 7 0 8
|
||||
SX126X_CAD_ON_16_SYMB = 0x04 // 7 0 16
|
||||
SX126X_CAD_GOTO_STDBY = 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode
|
||||
SX126X_CAD_GOTO_RX = 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected
|
||||
|
||||
//SX126X_CMD_GET_STATUS
|
||||
SX126X_STATUS_MODE_STDBY_RC = 0b00100000 // 6 4 current chip mode: STDBY_RC
|
||||
SX126X_STATUS_MODE_STDBY_XOSC = 0b00110000 // 6 4 STDBY_XOSC
|
||||
SX126X_STATUS_MODE_FS = 0b01000000 // 6 4 FS
|
||||
SX126X_STATUS_MODE_RX = 0b01010000 // 6 4 RX
|
||||
SX126X_STATUS_MODE_TX = 0b01100000 // 6 4 TX
|
||||
SX126X_STATUS_DATA_AVAILABLE = 0b00000100 // 3 1 command status: packet received and data can be retrieved
|
||||
SX126X_STATUS_CMD_TIMEOUT = 0b00000110 // 3 1 SPI command timed out
|
||||
SX126X_STATUS_CMD_INVALID = 0b00001000 // 3 1 invalid SPI command
|
||||
SX126X_STATUS_CMD_FAILED = 0b00001010 // 3 1 SPI command failed to execute
|
||||
SX126X_STATUS_TX_DONE = 0b00001100 // 3 1 packet transmission done
|
||||
SX126X_STATUS_SPI_FAILED = 0b11111111 // 7 0 SPI transaction failed
|
||||
|
||||
//SX126X_CMD_GET_PACKET_STATUS
|
||||
SX126X_GFSK_RX_STATUS_PREAMBLE_ERR = 0b10000000 // 7 7 GFSK Rx status: preamble error
|
||||
SX126X_GFSK_RX_STATUS_SYNC_ERR = 0b01000000 // 6 6 sync word error
|
||||
SX126X_GFSK_RX_STATUS_ADRS_ERR = 0b00100000 // 5 5 address error
|
||||
SX126X_GFSK_RX_STATUS_CRC_ERR = 0b00010000 // 4 4 CRC error
|
||||
SX126X_GFSK_RX_STATUS_LENGTH_ERR = 0b00001000 // 3 3 length error
|
||||
SX126X_GFSK_RX_STATUS_ABORT_ERR = 0b00000100 // 2 2 abort error
|
||||
SX126X_GFSK_RX_STATUS_PACKET_RECEIVED = 0b00000010 // 2 2 packet received
|
||||
SX126X_GFSK_RX_STATUS_PACKET_SENT = 0b00000001 // 2 2 packet sent
|
||||
|
||||
//SX126X_CMD_GET_DEVICE_ERRORS
|
||||
SX126X_PA_RAMP_ERR = 0b100000000 // 8 8 device errors: PA ramping failed
|
||||
SX126X_PLL_LOCK_ERR = 0b001000000 // 6 6 PLL failed to lock
|
||||
SX126X_XOSC_START_ERR = 0b000100000 // 5 5 crystal oscillator failed to start
|
||||
SX126X_IMG_CALIB_ERR = 0b000010000 // 4 4 image calibration failed
|
||||
SX126X_ADC_CALIB_ERR = 0b000001000 // 3 3 ADC calibration failed
|
||||
SX126X_PLL_CALIB_ERR = 0b000000100 // 2 2 PLL calibration failed
|
||||
SX126X_RC13M_CALIB_ERR = 0b000000010 // 1 1 RC13M calibration failed
|
||||
SX126X_RC64K_CALIB_ERR = 0b000000001 // 0 0 RC64K calibration failed
|
||||
|
||||
// SX126X SPI register variables
|
||||
//SX126X_REG_LORA_SYNC_WORD_MSB + LSB
|
||||
SX126X_SYNC_WORD_PUBLIC = 0x34 // actually 0x3444 NOTE: The low nibbles in each byte (0x_4_4) are masked out since apparently, they're reserved.
|
||||
SX126X_SYNC_WORD_PRIVATE = 0x12 // actually 0x1424 You couldn't make this up if you tried.
|
||||
|
||||
SX126X_LORA_MAC_PUBLIC_SYNCWORD = 0x3444
|
||||
SX126X_LORA_MAC_PRIVATE_SYNCWORD = 0x1424
|
||||
|
||||
SX126X_LORA_SF5 = 0x05
|
||||
SX126X_LORA_SF6 = 0x06
|
||||
SX126X_LORA_SF7 = 0x07
|
||||
SX126X_LORA_SF8 = 0x08
|
||||
SX126X_LORA_SF9 = 0x09
|
||||
SX126X_LORA_SF10 = 0x0A
|
||||
SX126X_LORA_SF11 = 0x0B
|
||||
SX126X_LORA_SF12 = 0x0C
|
||||
)
|
||||
@@ -0,0 +1,85 @@
|
||||
//go:build stm32wlx
|
||||
// +build stm32wlx
|
||||
|
||||
package sx126x
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"errors"
|
||||
"machine"
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// New creates a new SX126x connection.
|
||||
func New(spi drivers.SPI) *Device {
|
||||
c := make(chan RadioEvent, 10)
|
||||
d := Device{
|
||||
spi: spi,
|
||||
radioEventChan: c,
|
||||
}
|
||||
if d.spi == machine.SPI3 {
|
||||
d.SubGhzInit()
|
||||
d.SetDeviceType(DEVICE_TYPE_SX1262)
|
||||
} else {
|
||||
panic("Driver only support SUBGHZSPI (SPI3) on stm32wlx targets")
|
||||
}
|
||||
return &d
|
||||
}
|
||||
|
||||
//SpiSetNss Sets the NSS line
|
||||
func (d *Device) SpiSetNss(state bool) {
|
||||
if state {
|
||||
stm32.PWR.SUBGHZSPICR.SetBits(stm32.PWR_SUBGHZSPICR_NSS)
|
||||
} else {
|
||||
stm32.PWR.SUBGHZSPICR.ClearBits(stm32.PWR_SUBGHZSPICR_NSS)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// WaitBusy sleep until all busy flags clears
|
||||
func (d *Device) WaitBusy() error {
|
||||
count := 100
|
||||
var rfbusyms, rfbusys bool
|
||||
for count > 0 {
|
||||
rfbusyms = stm32.PWR.SR2.HasBits(stm32.PWR_SR2_RFBUSYMS)
|
||||
rfbusys = stm32.PWR.SR2.HasBits(stm32.PWR_SR2_RFBUSYS)
|
||||
|
||||
if !(rfbusyms && rfbusys) {
|
||||
return nil
|
||||
}
|
||||
count--
|
||||
}
|
||||
return errors.New("WaitBusy Timeout")
|
||||
}
|
||||
|
||||
// SubGhzInit() configures internal SX1262's SPI bus.
|
||||
func (d *Device) SubGhzInit() {
|
||||
|
||||
// Enable APB3 Periph clock and delay
|
||||
stm32.RCC.APB3ENR.SetBits(stm32.RCC_APB3ENR_SUBGHZSPIEN)
|
||||
_ = stm32.RCC.APB3ENR.Get()
|
||||
|
||||
// Disable radio reset and wait it's ready
|
||||
stm32.RCC.CSR.ClearBits(stm32.RCC_CSR_RFRST)
|
||||
for stm32.RCC.CSR.HasBits(stm32.RCC_CSR_RFRSTF) {
|
||||
}
|
||||
|
||||
// Set NSS line low
|
||||
stm32.PWR.SUBGHZSPICR.SetBits(stm32.PWR_SUBGHZSPICR_NSS)
|
||||
|
||||
// Enable radio busy wakeup from Standby for CPU
|
||||
stm32.PWR.CR3.SetBits(stm32.PWR_CR3_EWRFBUSY)
|
||||
|
||||
// Clear busy flag
|
||||
stm32.PWR.SCR.Set(stm32.PWR_SCR_CWRFBUSYF)
|
||||
|
||||
// Enable SUBGHZ Spi
|
||||
// - /8 Prescaler
|
||||
// - Software Slave Management (NSS)
|
||||
// - FIFO Threshold and 8bit size
|
||||
stm32.SPI3.CR1.ClearBits(stm32.SPI_CR1_SPE)
|
||||
stm32.SPI3.CR1.Set(stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI | (0b010 << 3) | stm32.SPI_CR1_SSM)
|
||||
stm32.SPI3.CR2.Set(stm32.SPI_CR2_FRXTH | (0b111 << 8))
|
||||
stm32.SPI3.CR1.SetBits(stm32.SPI_CR1_SPE)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,699 @@
|
||||
// Package sx126x provides a driver for SX126x LoRa transceivers.
|
||||
// Inspired from https://github.com/Lora-net/sx126x_driver/
|
||||
|
||||
package sx126x
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// SX126X radio transceiver RF_IN and RF_OUT may be connected
|
||||
// to RF Switch. This interface allows the creation of struct
|
||||
// that can drive the RF Switch (Used in Lora RX and Lora Tx)
|
||||
type RFSwitch interface {
|
||||
InitRFSwitch()
|
||||
SetRfSwitchMode(mode int) error
|
||||
}
|
||||
|
||||
const (
|
||||
DEVICE_TYPE_SX1261 = iota
|
||||
DEVICE_TYPE_SX1262 = iota
|
||||
DEVICE_TYPE_SX1268 = iota
|
||||
)
|
||||
|
||||
const (
|
||||
RFSWITCH_RX = iota
|
||||
RFSWITCH_TX_LP = iota
|
||||
RFSWITCH_TX_HP = iota
|
||||
)
|
||||
|
||||
const (
|
||||
RadioEventRxDone = iota
|
||||
RadioEventTxDone = iota
|
||||
RadioEventTimeout = iota
|
||||
RadioEventWatchdog = iota
|
||||
RadioEventCrcError = iota
|
||||
RadioEventUnhandled = iota
|
||||
)
|
||||
|
||||
// RadioEvent are used for communicating in the radio Event Channel
|
||||
type RadioEvent struct {
|
||||
EventType int
|
||||
IRQStatus uint16
|
||||
EventData []byte
|
||||
}
|
||||
|
||||
const (
|
||||
PERIOD_PER_SEC = (uint32)(1000000 / 15.625) // SX1261 DS 13.1.4
|
||||
SPI_BUFFER_SIZE = 256
|
||||
)
|
||||
|
||||
// Device wraps an SPI connection to a SX127x device.
|
||||
type Device struct {
|
||||
spi drivers.SPI // SPI bus for module communication
|
||||
radioEventChan chan RadioEvent // Channel for Receiving events
|
||||
loraConf LoraConfig // Current Lora configuration
|
||||
rfswitch RFSwitch // RF Switch, if any
|
||||
deepSleep bool // Internal Sleep state
|
||||
deviceType int // sx1261,sx1262,sx1268 (defaults sx1261)
|
||||
spiBuffer [SPI_BUFFER_SIZE]uint8
|
||||
}
|
||||
|
||||
// Config holds the LoRa configuration parameters
|
||||
type LoraConfig struct {
|
||||
Freq uint32 // Frequency
|
||||
Cr uint8 // Coding Rate
|
||||
Sf uint8 // Spread Factor
|
||||
Bw uint8 // Bandwidth
|
||||
Ldr uint8 // Low Data Rate
|
||||
Preamble uint16 // PreambleLength
|
||||
SyncWord uint16 // Sync Word
|
||||
HeaderType uint8 // Header : Implicit/explicit
|
||||
Crc uint8 // CRC : Yes/No
|
||||
Iq uint8 // iq : Standard/inverted
|
||||
LoraTxPowerDBm int8 // Tx power in Dbm
|
||||
}
|
||||
|
||||
const (
|
||||
SX126X_RTC_FREQ_IN_HZ uint32 = 64000
|
||||
)
|
||||
|
||||
var (
|
||||
errUndefinedLoraConf = errors.New("Undefined Lora configuration")
|
||||
)
|
||||
|
||||
// --------------------------------------------------
|
||||
// Helper functions
|
||||
// --------------------------------------------------
|
||||
|
||||
// timeoutMsToRtcSteps converts Timeout (in ms) to RTC Steps
|
||||
func timeoutMsToRtcSteps(timeoutMs uint32) uint32 {
|
||||
r := uint32(timeoutMs * (SX126X_RTC_FREQ_IN_HZ / 1000))
|
||||
return r
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Channel and events
|
||||
// --------------------------------------------------
|
||||
//NewRadioEvent() returns a new RadioEvent that can be used in the RadioChannel
|
||||
func NewRadioEvent(eType int, irqStatus uint16, eData []byte) RadioEvent {
|
||||
r := RadioEvent{EventType: eType, IRQStatus: irqStatus, EventData: eData}
|
||||
return r
|
||||
}
|
||||
|
||||
// Get the RadioEvent channel of the device
|
||||
func (d *Device) GetRadioEventChan() chan RadioEvent {
|
||||
return d.radioEventChan
|
||||
}
|
||||
|
||||
// Specify device type (SX1261/2/8)
|
||||
func (d *Device) SetDeviceType(devType int) {
|
||||
d.deviceType = devType
|
||||
}
|
||||
|
||||
// SetRfSwitch let you define a custom RF Switch driver if needed
|
||||
func (d *Device) SetRfSwitch(rfswitch RFSwitch) {
|
||||
d.rfswitch = rfswitch
|
||||
d.rfswitch.InitRFSwitch()
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Operational modes functions
|
||||
// --------------------------------------------------
|
||||
|
||||
// DetectDevice() tries to detect the radio module by changing SyncWord value
|
||||
func (d *Device) DetectDevice() bool {
|
||||
bak := d.GetSyncWord()
|
||||
d.SetSyncWord(0xBEEF)
|
||||
tmp := d.GetSyncWord()
|
||||
if tmp != 0xBEEF {
|
||||
return false
|
||||
} else {
|
||||
d.SetSyncWord(bak)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// SetSleep sets the device in SLEEP mode with the lowest current consumption possible.
|
||||
func (d *Device) SetSleep() {
|
||||
d.ExecSetCommand(SX126X_CMD_SET_SLEEP, []uint8{SX126X_SLEEP_START_WARM | SX126X_SLEEP_RTC_OFF})
|
||||
}
|
||||
|
||||
// SetStandby sets the device in a configuration mode which is at an intermediate level of consumption
|
||||
func (d *Device) SetStandby() {
|
||||
d.ExecSetCommand(SX126X_CMD_SET_STANDBY, []uint8{SX126X_STANDBY_RC})
|
||||
}
|
||||
|
||||
// SetFs sets the device in frequency synthesis mode where the PLL is locked to the carrier frequency.
|
||||
func (d *Device) SetFs() {
|
||||
d.ExecSetCommand(SX126X_CMD_SET_FS, []uint8{})
|
||||
}
|
||||
|
||||
// SetTxContinuousWave set device in test mode to generate a continuous wave (RF tone)
|
||||
func (d *Device) SetTxContinuousWave() {
|
||||
if d.rfswitch != nil {
|
||||
d.rfswitch.SetRfSwitchMode(RFSWITCH_TX_HP)
|
||||
}
|
||||
d.ExecSetCommand(SX126X_CMD_SET_TX_CONTINUOUS_WAVE, []uint8{})
|
||||
}
|
||||
|
||||
// SetTxContinuousPreamble set device in test mode to constantly modulate LoRa preamble symbols.
|
||||
// Take care to initialize all Lora settings like it's done in LoraTx before calling this function
|
||||
// If you don't init properly all the settings, it'll fail
|
||||
func (d *Device) SetTxContinuousPreamble() {
|
||||
if d.rfswitch != nil {
|
||||
d.rfswitch.SetRfSwitchMode(RFSWITCH_TX_HP)
|
||||
}
|
||||
d.ExecSetCommand(SX126X_CMD_SET_TX_INFINITE_PREAMBLE, []uint8{})
|
||||
}
|
||||
|
||||
// SetTx() sets the device in TX mode
|
||||
// timeout is expressed in RTC Step unit (15uS)
|
||||
// The device will stay in Tx until countdown or packet transmitted
|
||||
// Value of 0x000000 will disable timer and device will stay TX
|
||||
func (d *Device) SetTx(timeoutRtcStep uint32) {
|
||||
var p [3]uint8
|
||||
p[0] = uint8((timeoutRtcStep >> 16) & 0xFF)
|
||||
p[1] = uint8((timeoutRtcStep >> 8) & 0xFF)
|
||||
p[2] = uint8((timeoutRtcStep >> 0) & 0xFF)
|
||||
d.ExecSetCommand(SX126X_CMD_SET_TX, p[:])
|
||||
}
|
||||
|
||||
// SetRx() sets the device in RX mode
|
||||
// timeout is expressed in RTC Step unit (15uS)
|
||||
// Value of 0x000000 => No timeout. Rx Single mode.
|
||||
// Value of 0xffffff => Rx Continuous mode
|
||||
// Other values => Timeout active. The device remains in RX until countdown or packet received
|
||||
func (d *Device) SetRx(timeoutRtcStep uint32) {
|
||||
var p [3]uint8
|
||||
p[0] = uint8(((timeoutRtcStep >> 16) & 0xFF))
|
||||
p[1] = uint8(((timeoutRtcStep >> 8) & 0xFF))
|
||||
p[2] = uint8(((timeoutRtcStep >> 0) & 0xFF))
|
||||
d.ExecSetCommand(SX126X_CMD_SET_RX, p[:])
|
||||
}
|
||||
|
||||
// StopTimerOnPreamble allows the user to select if the timer is stopped upon preamble detection of SyncWord / header detection.
|
||||
func (d *Device) StopTimerOnPreamble(enable bool) {
|
||||
var p [1]uint8
|
||||
if enable {
|
||||
p[0] = 1
|
||||
} else {
|
||||
p[0] = 0
|
||||
}
|
||||
d.ExecSetCommand(SX126X_CMD_STOP_TIMER_ON_PREAMBLE, p[:])
|
||||
}
|
||||
|
||||
// SetRegulatorMode sets the regulator more (depends on hardware implementation)
|
||||
func (d *Device) SetRegulatorMode(mode uint8) {
|
||||
p := []uint8{mode}
|
||||
d.ExecSetCommand(SX126X_CMD_SET_REGULATOR_MODE, p[:])
|
||||
}
|
||||
|
||||
// Calibrate starts the calibration of a block defined by calibParam
|
||||
func (d *Device) Calibrate(calibParam uint8) {
|
||||
p := []uint8{calibParam}
|
||||
d.ExecSetCommand(SX126X_CMD_CALIBRATE, p[:])
|
||||
}
|
||||
|
||||
// CalibrateImage calibrates the image rejection of the device for the device operating
|
||||
func (d *Device) CalibrateImage(freq uint32) {
|
||||
var calFreq [2]uint8
|
||||
if freq > 900000000 {
|
||||
calFreq[0] = 0xE1
|
||||
calFreq[1] = 0xE9
|
||||
} else if freq > 850000000 {
|
||||
calFreq[0] = 0xD7
|
||||
calFreq[1] = 0xD8
|
||||
} else if freq > 770000000 {
|
||||
calFreq[0] = 0xC1
|
||||
calFreq[1] = 0xC5
|
||||
} else if freq > 460000000 {
|
||||
calFreq[0] = 0x75
|
||||
calFreq[1] = 0x81
|
||||
} else if freq > 425000000 {
|
||||
calFreq[0] = 0x6B
|
||||
calFreq[1] = 0x6F
|
||||
}
|
||||
d.ExecSetCommand(SX126X_CMD_CALIBRATE_IMAGE, calFreq[:])
|
||||
}
|
||||
|
||||
// SetPaConfig sets the Power Amplifier configuration
|
||||
// deviceSel: 0 for SX1262, 1 for SX1261
|
||||
func (d *Device) SetPaConfig(paDutyCycle, hpMax, deviceSel, paLut uint8) {
|
||||
var p [4]uint8
|
||||
p[0] = paDutyCycle
|
||||
p[1] = hpMax
|
||||
p[2] = deviceSel
|
||||
p[3] = paLut
|
||||
d.ExecSetCommand(SX126X_CMD_SET_PA_CONFIG, p[:])
|
||||
}
|
||||
|
||||
// SetRxTxFallbackMode defines into which mode the chip goes after a successful transmission or after a packet reception.
|
||||
func (d *Device) SetRxTxFallbackMode(fallbackMode uint8) {
|
||||
d.ExecSetCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, []uint8{fallbackMode})
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Registers and Buffers
|
||||
// --------------------------------------------------
|
||||
|
||||
// ReadRegister reads register value
|
||||
func (d *Device) ReadRegister(addr, size uint16) ([]uint8, error) {
|
||||
d.CheckDeviceReady()
|
||||
d.SpiSetNss(false)
|
||||
// Send command
|
||||
cmd := []uint8{SX126X_CMD_READ_REGISTER, uint8((addr & 0xFF00) >> 8), uint8(addr & 0x00FF), 0x00}
|
||||
d.spi.Tx(cmd, nil)
|
||||
ret := d.spiBuffer[0:size]
|
||||
d.spi.Tx(nil, ret)
|
||||
d.SpiSetNss(true)
|
||||
d.WaitBusy()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// WriteRegister writes value to register
|
||||
func (d *Device) WriteRegister(addr uint16, data []uint8) {
|
||||
d.CheckDeviceReady()
|
||||
d.SpiSetNss(false)
|
||||
cmd := []uint8{SX126X_CMD_WRITE_REGISTER, uint8((addr & 0xFF00) >> 8), uint8(addr & 0x00FF)}
|
||||
d.spi.Tx(append(cmd, data...), nil)
|
||||
d.SpiSetNss(true)
|
||||
d.WaitBusy()
|
||||
}
|
||||
|
||||
// WriteBuffer write data from current buffer position
|
||||
func (d *Device) WriteBuffer(data []uint8) {
|
||||
p := []uint8{0}
|
||||
p = append(p, data...)
|
||||
d.ExecSetCommand(SX126X_CMD_WRITE_BUFFER, p)
|
||||
}
|
||||
|
||||
// ReadBuffer Reads size bytes from current buffer position
|
||||
func (d *Device) ReadBuffer(size uint8) []uint8 {
|
||||
ret := d.ExecGetCommand(SX126X_CMD_READ_BUFFER, size)
|
||||
return ret
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// DIO and IRQ
|
||||
// --------------------------------------------------
|
||||
|
||||
// SetDioIrqParams configures DIO Irq
|
||||
func (d *Device) SetDioIrqParams(irqMask, dio1Mask, dio2Mask, dio3Mask uint16) {
|
||||
var p [8]uint8
|
||||
p[0] = uint8((irqMask >> 8) & 0xFF)
|
||||
p[1] = uint8(irqMask & 0xFF)
|
||||
p[2] = uint8((dio1Mask >> 8) & 0xFF)
|
||||
p[3] = uint8(dio1Mask & 0xFF)
|
||||
p[4] = uint8((dio2Mask >> 8) & 0xFF)
|
||||
p[5] = uint8(dio2Mask & 0xFF)
|
||||
p[6] = uint8((dio3Mask >> 8) & 0xFF)
|
||||
p[7] = uint8(dio3Mask & 0xFF)
|
||||
d.ExecSetCommand(SX126X_CMD_SET_DIO_IRQ_PARAMS, p[:])
|
||||
}
|
||||
|
||||
// GetIrqStatus returns IRQ status
|
||||
func (d *Device) GetIrqStatus() (irqStatus uint16) {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_IRQ_STATUS, 2)
|
||||
ret := (uint16(r[0]) << 8) | uint16(r[1])
|
||||
return ret
|
||||
}
|
||||
|
||||
// ClearIrqStatus clears IRQ flags
|
||||
func (d *Device) ClearIrqStatus(clearIrqParams uint16) {
|
||||
var p [2]uint8
|
||||
p[0] = uint8((clearIrqParams >> 8) & 0xFF)
|
||||
p[1] = uint8(clearIrqParams & 0xFF)
|
||||
d.ExecSetCommand(SX126X_CMD_CLEAR_IRQ_STATUS, p[:])
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Communication Status Information
|
||||
// --------------------------------------------------
|
||||
|
||||
// GetStatus returns radio status(13.5.1)
|
||||
func (d *Device) GetStatus() (radioStatus uint8) {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_STATUS, 1)
|
||||
return r[0]
|
||||
}
|
||||
|
||||
// GetRxBufferStatus returns the length of the last received packet (PayloadLengthRx)
|
||||
// and the address of the first byte received (RxStartBufferPointer). (13.5.2)
|
||||
func (d *Device) GetRxBufferStatus() (payloadLengthRx uint8, rxStartBufferPointer uint8) {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, 2)
|
||||
return r[0], r[1]
|
||||
}
|
||||
|
||||
// GetPackeType returns current Packet Type (13.4.3)
|
||||
func (d *Device) GetPacketType() (packetType uint8) {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_PACKET_TYPE, 1)
|
||||
return r[0]
|
||||
}
|
||||
|
||||
// GetDeviceErrors returns current Device Errors
|
||||
func (d *Device) GetDeviceErrors() uint16 {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_DEVICE_ERRORS, 2)
|
||||
ret := uint16(r[0]<<8 + r[1])
|
||||
return ret
|
||||
}
|
||||
|
||||
// ClearDeviceErrors clears device Errors
|
||||
func (d *Device) ClearDeviceErrors() {
|
||||
p := [2]uint8{0x00, 0x00}
|
||||
d.ExecSetCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, p[:])
|
||||
}
|
||||
|
||||
// GetStats returns the number of informations received on a few last packets
|
||||
// Lora: NbPktReceived, NbPktCrcError, NbPktHeaderErr
|
||||
func (d *Device) GetLoraStats() (nbPktReceived, nbPktCrcError, nbPktHeaderErr uint16) {
|
||||
r := d.ExecGetCommand(SX126X_CMD_GET_STATS, 6)
|
||||
return uint16(r[0]<<8 | r[1]), uint16(r[2]<<8 | r[3]), uint16(r[4]<<8 | r[5])
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
// PACKET / RADIO / PROTOCOL CONFIGURATION
|
||||
// ---------------------------------------
|
||||
|
||||
// SetPacketType sets the packet type
|
||||
func (d *Device) SetPacketType(packetType uint8) {
|
||||
var p [1]uint8
|
||||
p[0] = packetType
|
||||
d.ExecSetCommand(SX126X_CMD_SET_PACKET_TYPE, p[:])
|
||||
}
|
||||
|
||||
// SetSyncWord defines the Sync Word to yse
|
||||
func (d *Device) SetSyncWord(syncword uint16) {
|
||||
var p [2]uint8
|
||||
d.loraConf.SyncWord = syncword
|
||||
p[0] = uint8((syncword >> 8) & 0xFF)
|
||||
p[1] = uint8((syncword >> 0) & 0xFF)
|
||||
d.WriteRegister(SX126X_REG_LORA_SYNC_WORD_MSB, p[:])
|
||||
}
|
||||
|
||||
// GetSyncWord gets the Sync Word to use
|
||||
func (d *Device) GetSyncWord() uint16 {
|
||||
p, _ := d.ReadRegister(SX126X_REG_LORA_SYNC_WORD_MSB, 2)
|
||||
r := uint16(p[0])<<8 + uint16(p[1])
|
||||
return r
|
||||
}
|
||||
|
||||
// SetLoraPublicNetwork sets Sync Word to 0x3444 (Public) or 0x1424 (Private)
|
||||
func (d *Device) SetLoraPublicNetwork(enable bool) {
|
||||
if enable {
|
||||
d.SetSyncWord(SX126X_LORA_MAC_PUBLIC_SYNCWORD)
|
||||
} else {
|
||||
d.SetSyncWord(SX126X_LORA_MAC_PRIVATE_SYNCWORD)
|
||||
}
|
||||
}
|
||||
|
||||
// SetPacketParam sets various packet-related params
|
||||
func (d *Device) SetPacketParam(preambleLength uint16, headerType, crcType, payloadLength, invertIQ uint8) {
|
||||
var p [6]uint8
|
||||
p[0] = uint8((preambleLength >> 8) & 0xFF)
|
||||
p[1] = uint8(preambleLength & 0xFF)
|
||||
p[2] = headerType
|
||||
p[3] = payloadLength
|
||||
p[4] = crcType
|
||||
p[5] = invertIQ
|
||||
d.ExecSetCommand(SX126X_CMD_SET_PACKET_PARAMS, p[:])
|
||||
}
|
||||
|
||||
// SetBufferBaseAddress sets base address for buffer
|
||||
func (d *Device) SetBufferBaseAddress(txBaseAddress, rxBaseAddress uint8) {
|
||||
var p [2]uint8
|
||||
p[0] = txBaseAddress
|
||||
p[1] = rxBaseAddress
|
||||
d.ExecSetCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, p[:])
|
||||
}
|
||||
|
||||
// SetRfFrequency sets the radio frequency
|
||||
func (d *Device) SetRfFrequency(frequency uint32) {
|
||||
var p [4]uint8
|
||||
freq := uint32((uint64(frequency) << 25) / 32000000)
|
||||
p[0] = uint8((freq >> 24) & 0xFF)
|
||||
p[1] = uint8((freq >> 16) & 0xFF)
|
||||
p[2] = uint8((freq >> 8) & 0xFF)
|
||||
p[3] = uint8((freq >> 0) & 0xFF)
|
||||
d.ExecSetCommand(SX126X_CMD_SET_RF_FREQUENCY, p[:])
|
||||
}
|
||||
|
||||
// SetCurrentLimit sets max current in the module
|
||||
func (d *Device) SetCurrentLimit(limit uint8) {
|
||||
if limit > 140 {
|
||||
limit = 140
|
||||
}
|
||||
rawLimit := uint8(float32(limit) / 2.5)
|
||||
p := []uint8{rawLimit}
|
||||
d.WriteRegister(SX126X_REG_OCP_CONFIGURATION, p[:])
|
||||
}
|
||||
|
||||
// SetTxConfig sets power and rampup time
|
||||
func (d *Device) SetTxParams(power int8, rampTime uint8) {
|
||||
var p [2]uint8
|
||||
|
||||
if d.deviceType == DEVICE_TYPE_SX1261 {
|
||||
if power == 15 {
|
||||
d.SetPaConfig(0x06, 0x00, 0x01, 0x01)
|
||||
} else {
|
||||
d.SetPaConfig(0x04, 0x00, 0x01, 0x01)
|
||||
}
|
||||
if power > 14 {
|
||||
power = 14
|
||||
} else if power < -3 {
|
||||
power = -3
|
||||
}
|
||||
d.SetCurrentLimit(80) // Set max current limit to 80mA
|
||||
} else { // sx1262 and sx1268
|
||||
d.SetPaConfig(0x04, 0x07, 0x00, 0x01)
|
||||
if power > 22 {
|
||||
power = 22
|
||||
} else if power < -3 {
|
||||
power = -3
|
||||
}
|
||||
d.SetCurrentLimit(140) // Set max current limit to 140 mA
|
||||
}
|
||||
|
||||
p[0] = uint8(power)
|
||||
p[1] = rampTime
|
||||
d.ExecSetCommand(SX126X_CMD_SET_TX_PARAMS, p[:])
|
||||
}
|
||||
|
||||
// SetModulationParams sets the Lora modulation frequency
|
||||
func (d *Device) SetModulationParams(spreadingFactor, bandwidth, codingRate, lowDataRateOptimize uint8) {
|
||||
var p [4]uint8
|
||||
p[0] = spreadingFactor
|
||||
p[1] = bandwidth
|
||||
p[2] = codingRate
|
||||
p[3] = lowDataRateOptimize
|
||||
d.ExecSetCommand(SX126X_CMD_SET_MODULATION_PARAMS, p[:])
|
||||
}
|
||||
|
||||
// CheckDeviceReady sleep until all busy flags clears
|
||||
func (d *Device) CheckDeviceReady() error {
|
||||
if d.deepSleep == true {
|
||||
d.SpiSetNss(false)
|
||||
time.Sleep(time.Millisecond)
|
||||
d.SpiSetNss(true)
|
||||
d.deepSleep = false
|
||||
}
|
||||
return d.WaitBusy()
|
||||
}
|
||||
|
||||
// ExecSetCommand send a command to configure the peripheral
|
||||
func (d *Device) ExecSetCommand(cmd uint8, buf []uint8) {
|
||||
d.CheckDeviceReady()
|
||||
if cmd == SX126X_CMD_SET_SLEEP {
|
||||
d.deepSleep = true
|
||||
} else {
|
||||
d.deepSleep = false
|
||||
}
|
||||
d.SpiSetNss(false)
|
||||
// Send command and params
|
||||
d.spi.Tx(append([]uint8{cmd}, buf...), nil)
|
||||
d.SpiSetNss(true)
|
||||
if cmd != SX126X_CMD_SET_SLEEP {
|
||||
d.WaitBusy()
|
||||
}
|
||||
}
|
||||
|
||||
// ExecGetCommand queries the peripheral the peripheral
|
||||
func (d *Device) ExecGetCommand(cmd uint8, size uint8) []uint8 {
|
||||
d.CheckDeviceReady()
|
||||
d.SpiSetNss(false)
|
||||
// Send the command and flush first status byte (as not used)
|
||||
d.spi.Tx([]uint8{cmd, 0x00}, nil)
|
||||
d.spi.Tx(nil, d.spiBuffer[:size])
|
||||
d.SpiSetNss(true)
|
||||
d.WaitBusy()
|
||||
return d.spiBuffer[:size]
|
||||
}
|
||||
|
||||
//
|
||||
// Configuration
|
||||
//
|
||||
|
||||
// SetLoraFrequency() Sets current Lora Frequency
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraFrequency(freq uint32) {
|
||||
d.loraConf.Freq = d.loraConf.Freq
|
||||
}
|
||||
|
||||
// SetLoraIqMode() defines the current IQ Mode (Standard/Inverted)
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraIqMode(mode uint8) {
|
||||
if mode == 0 {
|
||||
d.loraConf.Iq = SX126X_LORA_IQ_STANDARD
|
||||
} else {
|
||||
d.loraConf.Iq = SX126X_LORA_IQ_INVERTED
|
||||
}
|
||||
}
|
||||
|
||||
// SetLoraCodingRate() sets current Lora Coding Rate
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraCodingRate(cr uint8) {
|
||||
d.loraConf.Cr = cr
|
||||
}
|
||||
|
||||
// SetLoraBandwidth() sets current Lora Bandwidth
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraBandwidth(bw uint8) {
|
||||
d.loraConf.Cr = bw
|
||||
}
|
||||
|
||||
// SetLoraCrc() sets current CRC mode (ON/OFF)
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraCrc(enable bool) {
|
||||
if enable {
|
||||
d.loraConf.Crc = SX126X_LORA_CRC_ON
|
||||
} else {
|
||||
d.loraConf.Crc = SX126X_LORA_CRC_OFF
|
||||
}
|
||||
}
|
||||
|
||||
//SetLoraSpreadingFactor setc surrent Lora Spreading Factor
|
||||
// NB: Change will be applied at next RX / TX
|
||||
func (d *Device) SetLoraSpreadingFactor(sf uint8) {
|
||||
d.loraConf.Sf = sf
|
||||
}
|
||||
|
||||
//
|
||||
// Lora functions
|
||||
//
|
||||
//
|
||||
|
||||
// LoraConfig() defines Lora configuration for next Lora operations
|
||||
func (d *Device) LoraConfig(cnf LoraConfig) {
|
||||
// Save given configuration
|
||||
d.loraConf = cnf
|
||||
// Switch to standby prior to configuration changes
|
||||
d.SetStandby()
|
||||
// Clear errors, disable radio interrupts for the moment
|
||||
d.ClearDeviceErrors()
|
||||
d.ClearIrqStatus(SX126X_IRQ_ALL)
|
||||
d.SetDioIrqParams(0x00, 0x00, 0x00, 0x00)
|
||||
// Define radio operation mode
|
||||
d.SetPacketType(SX126X_PACKET_TYPE_LORA)
|
||||
d.SetRfFrequency(d.loraConf.Freq)
|
||||
d.SetModulationParams(d.loraConf.Sf, d.loraConf.Bw, d.loraConf.Cr, d.loraConf.Ldr)
|
||||
d.SetTxParams(d.loraConf.LoraTxPowerDBm, SX126X_PA_RAMP_200U)
|
||||
d.SetSyncWord(d.loraConf.SyncWord)
|
||||
d.SetBufferBaseAddress(0, 0)
|
||||
}
|
||||
|
||||
// LoraTx sends a lora packet, (with timeout)
|
||||
func (d *Device) LoraTx(pkt []uint8, timeoutMs uint32) error {
|
||||
|
||||
if d.loraConf.Freq == 0 {
|
||||
return errUndefinedLoraConf
|
||||
}
|
||||
if d.rfswitch != nil {
|
||||
err := d.rfswitch.SetRfSwitchMode(RFSWITCH_TX_HP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.ClearIrqStatus(SX126X_IRQ_ALL)
|
||||
irqVal := uint16(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR)
|
||||
d.SetStandby()
|
||||
d.SetPacketType(SX126X_PACKET_TYPE_LORA)
|
||||
d.SetRfFrequency(d.loraConf.Freq)
|
||||
d.SetTxParams(d.loraConf.LoraTxPowerDBm, SX126X_PA_RAMP_200U)
|
||||
d.SetBufferBaseAddress(0, 0)
|
||||
d.WriteBuffer(pkt)
|
||||
d.SetModulationParams(d.loraConf.Sf, d.loraConf.Bw, d.loraConf.Cr, d.loraConf.Ldr)
|
||||
d.SetPacketParam(d.loraConf.Preamble, d.loraConf.HeaderType, d.loraConf.Crc, uint8(len(pkt)), d.loraConf.Iq)
|
||||
d.SetDioIrqParams(irqVal, irqVal, SX126X_IRQ_NONE, SX126X_IRQ_NONE)
|
||||
d.SetSyncWord(d.loraConf.SyncWord)
|
||||
d.SetTx(timeoutMsToRtcSteps(timeoutMs))
|
||||
|
||||
msg := <-d.GetRadioEventChan()
|
||||
if msg.EventType != RadioEventTxDone {
|
||||
return errors.New("Unexpected Radio Event while TX")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoraRx tries to receive a Lora packet (with timeout in milliseconds)
|
||||
func (d *Device) LoraRx(timeoutMs uint32) ([]uint8, error) {
|
||||
|
||||
if d.loraConf.Freq == 0 {
|
||||
return nil, errUndefinedLoraConf
|
||||
}
|
||||
if d.rfswitch != nil {
|
||||
err := d.rfswitch.SetRfSwitchMode(RFSWITCH_RX)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
d.ClearIrqStatus(SX126X_IRQ_ALL)
|
||||
irqVal := uint16(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR)
|
||||
d.SetStandby()
|
||||
d.SetBufferBaseAddress(0, 0)
|
||||
d.SetModulationParams(d.loraConf.Sf, d.loraConf.Bw, d.loraConf.Cr, d.loraConf.Ldr)
|
||||
d.SetPacketParam(d.loraConf.Preamble, d.loraConf.HeaderType, d.loraConf.Crc, 0xFF, d.loraConf.Iq)
|
||||
d.SetDioIrqParams(irqVal, irqVal, SX126X_IRQ_NONE, SX126X_IRQ_NONE)
|
||||
d.SetRx(timeoutMsToRtcSteps(timeoutMs))
|
||||
|
||||
msg := <-d.GetRadioEventChan()
|
||||
|
||||
if msg.EventType == RadioEventTimeout {
|
||||
return nil, nil
|
||||
} else if msg.EventType != RadioEventRxDone {
|
||||
return nil, errors.New("Unexpected Radio Event while RX")
|
||||
}
|
||||
|
||||
pLen, pStart := d.GetRxBufferStatus()
|
||||
d.SetBufferBaseAddress(0, pStart+1)
|
||||
pkt := d.ReadBuffer(pLen + 1)
|
||||
pkt = pkt[1:]
|
||||
|
||||
return pkt, nil
|
||||
}
|
||||
|
||||
// HandleInterrupt must be called by main code on DIO state change.
|
||||
func (d *Device) HandleInterrupt() {
|
||||
st := d.GetIrqStatus()
|
||||
d.ClearIrqStatus(SX126X_IRQ_ALL)
|
||||
|
||||
rChan := d.GetRadioEventChan()
|
||||
|
||||
if (st & SX126X_IRQ_RX_DONE) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventRxDone, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX126X_IRQ_TX_DONE) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTxDone, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX126X_IRQ_TIMEOUT) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTimeout, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX126X_IRQ_CRC_ERR) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventCrcError, st, nil)
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -2,4 +2,4 @@ package drivers
|
||||
|
||||
// Version returns a user-readable string showing the version of the drivers package for support purposes.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.18.0"
|
||||
const Version = "0.19.0"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package wifinina
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
d.SetPassphrase(ssid, pass)
|
||||
|
||||
for time.Since(start) < timeout {
|
||||
st, _ := d.GetConnectionStatus()
|
||||
if st == StatusConnected {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
return net.ErrWiFiConnectTimeout
|
||||
}
|
||||
|
||||
func (d *Device) GetClientIP() (string, error) {
|
||||
ip, _, _, err := d.GetIP()
|
||||
return ip.String(), err
|
||||
}
|
||||
+65
-82
@@ -4,50 +4,34 @@ import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net"
|
||||
)
|
||||
|
||||
const (
|
||||
ReadBufferSize = 128
|
||||
)
|
||||
|
||||
func (d *Device) NewDriver() net.DeviceDriver {
|
||||
return &Driver{dev: d, sock: NoSocketAvail}
|
||||
}
|
||||
|
||||
type Driver struct {
|
||||
dev *Device
|
||||
sock uint8
|
||||
readBuf readBuffer
|
||||
|
||||
proto uint8
|
||||
ip uint32
|
||||
port uint16
|
||||
}
|
||||
|
||||
type readBuffer struct {
|
||||
data [ReadBufferSize]byte
|
||||
head int
|
||||
size int
|
||||
}
|
||||
|
||||
func (drv *Driver) GetDNS(domain string) (string, error) {
|
||||
ipAddr, err := drv.dev.GetHostByName(domain)
|
||||
func (d *Device) GetDNS(domain string) (string, error) {
|
||||
ipAddr, err := d.GetHostByName(domain)
|
||||
return ipAddr.String(), err
|
||||
}
|
||||
|
||||
func (drv *Driver) ConnectTCPSocket(addr, portStr string) error {
|
||||
return drv.connectSocket(addr, portStr, ProtoModeTCP)
|
||||
func (d *Device) ConnectTCPSocket(addr, portStr string) error {
|
||||
return d.connectSocket(addr, portStr, ProtoModeTCP)
|
||||
}
|
||||
|
||||
func (drv *Driver) ConnectSSLSocket(addr, portStr string) error {
|
||||
return drv.connectSocket(addr, portStr, ProtoModeTLS)
|
||||
func (d *Device) ConnectSSLSocket(addr, portStr string) error {
|
||||
return d.connectSocket(addr, portStr, ProtoModeTLS)
|
||||
}
|
||||
|
||||
func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error {
|
||||
func (d *Device) connectSocket(addr, portStr string, mode uint8) error {
|
||||
|
||||
drv.proto, drv.ip, drv.port = mode, 0, 0
|
||||
d.proto, d.ip, d.port = mode, 0, 0
|
||||
|
||||
// convert port to uint16
|
||||
port, err := convertPort(portStr)
|
||||
@@ -61,7 +45,7 @@ func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error {
|
||||
if mode != ProtoModeTLS {
|
||||
// look up the hostname if necessary; if an IP address was specified, the
|
||||
// same will be returned. Otherwise, an IPv4 for the hostname is returned.
|
||||
ipAddr, err := drv.dev.GetHostByName(addr)
|
||||
ipAddr, err := d.GetHostByName(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -70,32 +54,33 @@ func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error {
|
||||
}
|
||||
|
||||
// check to see if socket is already set; if so, stop it
|
||||
if drv.sock != NoSocketAvail {
|
||||
if err := drv.stop(); err != nil {
|
||||
if d.sock != NoSocketAvail {
|
||||
if err := d.stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// get a socket from the device
|
||||
if drv.sock, err = drv.dev.GetSocket(); err != nil {
|
||||
if d.sock, err = d.GetSocket(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// attempt to start the client
|
||||
if err := drv.dev.StartClient(hostname, ip, port, drv.sock, mode); err != nil {
|
||||
if err := d.StartClient(hostname, ip, port, d.sock, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: this 4 second timeout is simply mimicking the Arduino driver
|
||||
for t := newTimer(4 * time.Second); !t.Expired(); {
|
||||
connected, err := drv.IsConnected()
|
||||
start := time.Now()
|
||||
for time.Since(start) < 4*time.Second {
|
||||
connected, err := d.IsConnected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if connected {
|
||||
return nil
|
||||
}
|
||||
wait(1 * time.Millisecond)
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
|
||||
return ErrConnectionTimeout
|
||||
@@ -109,12 +94,12 @@ func convertPort(portStr string) (uint16, error) {
|
||||
return uint16(p64), nil
|
||||
}
|
||||
|
||||
func (drv *Driver) ConnectUDPSocket(addr, portStr, lportStr string) (err error) {
|
||||
func (d *Device) ConnectUDPSocket(addr, portStr, lportStr string) (err error) {
|
||||
|
||||
drv.proto, drv.ip, drv.port = ProtoModeUDP, 0, 0
|
||||
d.proto, d.ip, d.port = ProtoModeUDP, 0, 0
|
||||
|
||||
// convert remote port to uint16
|
||||
if drv.port, err = convertPort(portStr); err != nil {
|
||||
if d.port, err = convertPort(portStr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -126,73 +111,73 @@ func (drv *Driver) ConnectUDPSocket(addr, portStr, lportStr string) (err error)
|
||||
|
||||
// look up the hostname if necessary; if an IP address was specified, the
|
||||
// same will be returned. Otherwise, an IPv4 for the hostname is returned.
|
||||
ipAddr, err := drv.dev.GetHostByName(addr)
|
||||
ipAddr, err := d.GetHostByName(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
drv.ip = ipAddr.AsUint32()
|
||||
d.ip = ipAddr.AsUint32()
|
||||
|
||||
// check to see if socket is already set; if so, stop it
|
||||
// TODO: we can probably have more than one socket at once right?
|
||||
if drv.sock != NoSocketAvail {
|
||||
if err := drv.stop(); err != nil {
|
||||
if d.sock != NoSocketAvail {
|
||||
if err := d.stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// get a socket from the device
|
||||
if drv.sock, err = drv.dev.GetSocket(); err != nil {
|
||||
if d.sock, err = d.GetSocket(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start listening for UDP packets on the local port
|
||||
if err := drv.dev.StartServer(lport, drv.sock, drv.proto); err != nil {
|
||||
if err := d.StartServer(lport, d.sock, d.proto); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (drv *Driver) DisconnectSocket() error {
|
||||
return drv.stop()
|
||||
func (d *Device) DisconnectSocket() error {
|
||||
return d.stop()
|
||||
}
|
||||
|
||||
func (drv *Driver) StartSocketSend(size int) error {
|
||||
func (d *Device) StartSocketSend(size int) error {
|
||||
// not needed for WiFiNINA???
|
||||
return nil
|
||||
}
|
||||
|
||||
func (drv *Driver) Response(timeout int) ([]byte, error) {
|
||||
func (d *Device) Response(timeout int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (drv *Driver) Write(b []byte) (n int, err error) {
|
||||
if drv.sock == NoSocketAvail {
|
||||
func (d *Device) Write(b []byte) (n int, err error) {
|
||||
if d.sock == NoSocketAvail {
|
||||
return 0, ErrNoSocketAvail
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return 0, ErrNoData
|
||||
}
|
||||
if drv.proto == ProtoModeUDP {
|
||||
if err := drv.dev.StartClient("", drv.ip, drv.port, drv.sock, drv.proto); err != nil {
|
||||
if d.proto == ProtoModeUDP {
|
||||
if err := d.StartClient("", d.ip, d.port, d.sock, d.proto); err != nil {
|
||||
return 0, errors.New("error in startClient: " + err.Error())
|
||||
}
|
||||
if _, err := drv.dev.InsertDataBuf(b, drv.sock); err != nil {
|
||||
if _, err := d.InsertDataBuf(b, d.sock); err != nil {
|
||||
return 0, errors.New("error in insertDataBuf: " + err.Error())
|
||||
}
|
||||
if _, err := drv.dev.SendUDPData(drv.sock); err != nil {
|
||||
if _, err := d.SendUDPData(d.sock); err != nil {
|
||||
return 0, errors.New("error in sendUDPData: " + err.Error())
|
||||
}
|
||||
return len(b), nil
|
||||
} else {
|
||||
written, err := drv.dev.SendData(b, drv.sock)
|
||||
written, err := d.SendData(b, d.sock)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if written == 0 {
|
||||
return 0, ErrDataNotWritten
|
||||
}
|
||||
if sent, _ := drv.dev.CheckDataSent(drv.sock); !sent {
|
||||
if sent, _ := d.CheckDataSent(d.sock); !sent {
|
||||
return 0, ErrCheckDataError
|
||||
}
|
||||
return len(b), nil
|
||||
@@ -201,8 +186,8 @@ func (drv *Driver) Write(b []byte) (n int, err error) {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (drv *Driver) ReadSocket(b []byte) (n int, err error) {
|
||||
avail, err := drv.available()
|
||||
func (d *Device) ReadSocket(b []byte) (n int, err error) {
|
||||
avail, err := d.available()
|
||||
if err != nil {
|
||||
println("ReadSocket error: " + err.Error())
|
||||
return 0, err
|
||||
@@ -214,37 +199,37 @@ func (drv *Driver) ReadSocket(b []byte) (n int, err error) {
|
||||
if avail < length {
|
||||
length = avail
|
||||
}
|
||||
copy(b, drv.readBuf.data[drv.readBuf.head:drv.readBuf.head+length])
|
||||
drv.readBuf.head += length
|
||||
drv.readBuf.size -= length
|
||||
copy(b, d.readBuf.data[d.readBuf.head:d.readBuf.head+length])
|
||||
d.readBuf.head += length
|
||||
d.readBuf.size -= length
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// IsSocketDataAvailable returns of there is socket data available
|
||||
func (drv *Driver) IsSocketDataAvailable() bool {
|
||||
n, err := drv.available()
|
||||
func (d *Device) IsSocketDataAvailable() bool {
|
||||
n, err := d.available()
|
||||
return err == nil && n > 0
|
||||
}
|
||||
|
||||
func (drv *Driver) available() (int, error) {
|
||||
if drv.readBuf.size == 0 {
|
||||
n, err := drv.dev.GetDataBuf(drv.sock, drv.readBuf.data[:])
|
||||
func (d *Device) available() (int, error) {
|
||||
if d.readBuf.size == 0 {
|
||||
n, err := d.GetDataBuf(d.sock, d.readBuf.data[:])
|
||||
if n > 0 {
|
||||
drv.readBuf.head = 0
|
||||
drv.readBuf.size = n
|
||||
d.readBuf.head = 0
|
||||
d.readBuf.size = n
|
||||
}
|
||||
if err != nil {
|
||||
return int(n), err
|
||||
}
|
||||
}
|
||||
return drv.readBuf.size, nil
|
||||
return d.readBuf.size, nil
|
||||
}
|
||||
|
||||
func (drv *Driver) IsConnected() (bool, error) {
|
||||
if drv.sock == NoSocketAvail {
|
||||
func (d *Device) IsConnected() (bool, error) {
|
||||
if d.sock == NoSocketAvail {
|
||||
return false, nil
|
||||
}
|
||||
s, err := drv.status()
|
||||
s, err := d.status()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -260,28 +245,26 @@ func (drv *Driver) IsConnected() (bool, error) {
|
||||
return isConnected, nil
|
||||
}
|
||||
|
||||
func (drv *Driver) status() (uint8, error) {
|
||||
if drv.sock == NoSocketAvail {
|
||||
func (d *Device) status() (uint8, error) {
|
||||
if d.sock == NoSocketAvail {
|
||||
return TCPStateClosed, nil
|
||||
}
|
||||
return drv.dev.GetClientState(drv.sock)
|
||||
return d.GetClientState(d.sock)
|
||||
}
|
||||
|
||||
func (drv *Driver) stop() error {
|
||||
if drv.sock == NoSocketAvail {
|
||||
func (d *Device) stop() error {
|
||||
if d.sock == NoSocketAvail {
|
||||
return nil
|
||||
}
|
||||
drv.dev.StopClient(drv.sock)
|
||||
for t := newTimer(5 * time.Second); !t.Expired(); {
|
||||
st, _ := drv.status()
|
||||
d.StopClient(d.sock)
|
||||
start := time.Now()
|
||||
for time.Since(start) < 5*time.Second {
|
||||
st, _ := d.status()
|
||||
if st == TCPStateClosed {
|
||||
break
|
||||
}
|
||||
// FIXME: without the time.Sleep below this blocks until TCPStateClosed,
|
||||
// however with it got goroutine stack overflows; not sure if this is still
|
||||
// an issue so should investigate further
|
||||
//time.Sleep(1 * time.Millisecond)
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
drv.sock = NoSocketAvail
|
||||
d.sock = NoSocketAvail
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package wifinina
|
||||
|
||||
import "time"
|
||||
|
||||
func wait(duration time.Duration) {
|
||||
newTimer(duration).WaitUntilExpired()
|
||||
}
|
||||
|
||||
type timer struct {
|
||||
start int64
|
||||
interval int64
|
||||
}
|
||||
|
||||
func newTimer(interval time.Duration) timer {
|
||||
return timer{
|
||||
start: time.Now().UnixNano(),
|
||||
interval: int64(interval),
|
||||
}
|
||||
}
|
||||
|
||||
func (t timer) Expired() bool {
|
||||
return time.Now().UnixNano() > (t.start + t.interval)
|
||||
}
|
||||
|
||||
func (t timer) WaitUntilExpired() {
|
||||
for !t.Expired() {
|
||||
}
|
||||
}
|
||||
+20
-11
@@ -281,9 +281,16 @@ type Device struct {
|
||||
|
||||
buf [64]byte
|
||||
ssids [10]string
|
||||
|
||||
sock uint8
|
||||
readBuf readBuffer
|
||||
|
||||
proto uint8
|
||||
ip uint32
|
||||
port uint16
|
||||
}
|
||||
|
||||
// New returns a new Wifinina driver.
|
||||
// New returns a new Wifinina device.
|
||||
func New(bus drivers.SPI, csPin, ackPin, gpio0Pin, resetPin machine.Pin) *Device {
|
||||
return &Device{
|
||||
SPI: bus,
|
||||
@@ -295,8 +302,7 @@ func New(bus drivers.SPI, csPin, ackPin, gpio0Pin, resetPin machine.Pin) *Device
|
||||
}
|
||||
|
||||
func (d *Device) Configure() {
|
||||
|
||||
net.UseDriver(d.NewDriver())
|
||||
net.UseDriver(d)
|
||||
pinUseDevice(d)
|
||||
|
||||
d.CS.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
@@ -379,7 +385,7 @@ func (d *Device) CheckDataSent(sock uint8) (bool, error) {
|
||||
if sent > 0 {
|
||||
return true, nil
|
||||
}
|
||||
wait(100 * time.Microsecond)
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
}
|
||||
return false, lastErr
|
||||
}
|
||||
@@ -1023,8 +1029,7 @@ func (d *Device) checkStartCmd() (bool, error) {
|
||||
}
|
||||
|
||||
func (d *Device) waitForChipSelect() (err error) {
|
||||
err = d.waitForChipReady()
|
||||
if err == nil {
|
||||
if err = d.waitForChipReady(); err == nil {
|
||||
err = d.spiChipSelect()
|
||||
}
|
||||
return
|
||||
@@ -1034,12 +1039,14 @@ func (d *Device) waitForChipReady() error {
|
||||
if _debug {
|
||||
println("waitForChipReady()\r")
|
||||
}
|
||||
for t := newTimer(10 * time.Second); !(d.ACK.Get() == false); {
|
||||
if t.Expired() {
|
||||
return ErrTimeoutChipReady
|
||||
start := time.Now()
|
||||
for time.Since(start) < 10*time.Second {
|
||||
if !d.ACK.Get() {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
return nil
|
||||
return ErrTimeoutChipReady
|
||||
}
|
||||
|
||||
func (d *Device) spiChipSelect() error {
|
||||
@@ -1047,10 +1054,12 @@ func (d *Device) spiChipSelect() error {
|
||||
println("spiChipSelect()\r")
|
||||
}
|
||||
d.CS.Low()
|
||||
for t := newTimer(5 * time.Millisecond); !t.Expired(); {
|
||||
start := time.Now()
|
||||
for time.Since(start) < 5*time.Millisecond {
|
||||
if d.ACK.Get() {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
}
|
||||
return ErrTimeoutChipSelect
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
// Package xpt2046 implements a driver for the XPT2046 resistive touch controller as packaged on the TFT_320QVT board
|
||||
//
|
||||
// Datasheet: http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf
|
||||
package xpt2046
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/touch"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
t_clk machine.Pin
|
||||
t_cs machine.Pin
|
||||
t_din machine.Pin
|
||||
t_dout machine.Pin
|
||||
t_irq machine.Pin
|
||||
|
||||
precision uint8
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Precision uint8
|
||||
}
|
||||
|
||||
func New(t_clk, t_cs, t_din, t_dout, t_irq machine.Pin) Device {
|
||||
return Device{
|
||||
precision: 10,
|
||||
t_clk: t_clk,
|
||||
t_cs: t_cs,
|
||||
t_din: t_din,
|
||||
t_dout: t_dout,
|
||||
t_irq: t_irq,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) Configure(config *Config) error {
|
||||
|
||||
if config.Precision == 0 {
|
||||
d.precision = 10
|
||||
} else {
|
||||
d.precision = config.Precision
|
||||
}
|
||||
|
||||
d.t_clk.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
d.t_cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
d.t_din.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
d.t_dout.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
d.t_irq.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
|
||||
d.t_clk.Low()
|
||||
d.t_cs.High()
|
||||
d.t_din.Low()
|
||||
|
||||
d.readRaw() //Set Powerdown mode to enable T_IRQ
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func busSleep() {
|
||||
time.Sleep(5 * time.Nanosecond)
|
||||
}
|
||||
|
||||
func pulseHigh(p machine.Pin) {
|
||||
p.High()
|
||||
busSleep()
|
||||
p.Low()
|
||||
busSleep()
|
||||
}
|
||||
|
||||
func (d *Device) writeCommand(data uint8) {
|
||||
|
||||
for count := uint8(0); count < 8; count++ {
|
||||
d.t_din.Set((data & 0x80) != 0)
|
||||
data <<= 1
|
||||
pulseHigh(d.t_clk)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d *Device) readData() uint16 {
|
||||
|
||||
data := uint16(0)
|
||||
|
||||
for count := uint8(0); count < 12; count++ {
|
||||
data <<= 1
|
||||
pulseHigh(d.t_clk)
|
||||
if d.t_dout.Get() {
|
||||
data |= 1
|
||||
}
|
||||
}
|
||||
pulseHigh(d.t_clk) //13
|
||||
pulseHigh(d.t_clk) //14
|
||||
pulseHigh(d.t_clk) //15
|
||||
pulseHigh(d.t_clk) //16
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func (d *Device) ReadTouchPoint() touch.Point {
|
||||
|
||||
tx := uint32(0)
|
||||
ty := uint32(0)
|
||||
tz := uint32(0)
|
||||
sampleCount := uint8(0)
|
||||
|
||||
d.t_cs.Low()
|
||||
|
||||
for ; sampleCount < d.precision && d.Touched(); sampleCount++ {
|
||||
rx, ry, rz := d.readRaw()
|
||||
tx += uint32(rx)
|
||||
ty += uint32(ry)
|
||||
tz += uint32(rz)
|
||||
}
|
||||
d.t_cs.High()
|
||||
|
||||
if sampleCount > 0 {
|
||||
x := int(tx / uint32(sampleCount))
|
||||
y := int(ty / uint32(sampleCount))
|
||||
z := int(tz / uint32(sampleCount))
|
||||
return touch.Point{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
}
|
||||
} else {
|
||||
return touch.Point{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
Z: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) Touched() bool {
|
||||
avail := !d.t_irq.Get()
|
||||
return avail
|
||||
}
|
||||
|
||||
func (d *Device) readRaw() (int32, int32, int32) {
|
||||
|
||||
d.t_cs.Low()
|
||||
|
||||
//S = 1 --> Required Control bit
|
||||
//A2-A0 = 001 --> Y-Position
|
||||
//MODE = 0 --> 12 bit conversion
|
||||
//SER/DFR = 0 --> Differential preferred for X,Y position
|
||||
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
|
||||
d.writeCommand(0x90)
|
||||
ty := d.readData()
|
||||
|
||||
//S = 1 --> Required Control bit
|
||||
//A2-A0 = 101 --> X-Position
|
||||
//MODE = 0 --> 12 bit conversion
|
||||
//SER/DFR = 0 --> Differential preferred for X,Y position
|
||||
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
|
||||
d.writeCommand(0xD0)
|
||||
tx := d.readData()
|
||||
|
||||
//S = 1 --> Required Control bit
|
||||
//A2-A0 = 011 --> Z1-position (pressure)
|
||||
//MODE = 0 --> 12 bit conversion
|
||||
//SER/DFR = 0 --> Differential preferred for pressure
|
||||
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
|
||||
d.writeCommand(0xB0)
|
||||
tz1 := int32(d.readData())
|
||||
|
||||
//S = 1 --> Required Control bit
|
||||
//A2-A0 = 100 --> Z2-position (pressure)
|
||||
//MODE = 0 --> 12 bit conversion
|
||||
//SER/DFR = 0 --> Differential preferred for pressure
|
||||
//PD1-PD0 = 00 --> Powerdown and enable PEN_IRQ
|
||||
d.writeCommand(0xC0)
|
||||
tz2 := int32(d.readData())
|
||||
|
||||
tz := int32(0)
|
||||
if tz1 != 0 {
|
||||
//Touch pressure is proportional to the ratio of z2 to z1 and the x position.
|
||||
tz = int32(tx) * ((tz2 << 12) / (tz1 << 12))
|
||||
}
|
||||
|
||||
d.t_cs.High()
|
||||
|
||||
//Scale X&Y to 16 bit for consistency across touch drivers
|
||||
return int32(tx) << 4, int32(4096-ty) << 4, tz
|
||||
}
|
||||
Reference in New Issue
Block a user