Compare commits

...

27 Commits

Author SHA1 Message Date
deadprogram b6b5668945 examples: correct missing const for lora atcmd
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 19:13:18 +01:00
deadprogram 24b6f0f296 examples: use shorter names for Lora radio functions
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 18:51:03 +01:00
deadprogram 38ba7772e2 sx126x, sx127x: remove extra Lora in functions to avoid stuttering
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 17:17:05 +01:00
deadprogram 6df6bf4880 examples: add SEND/RECV to lora at-cmd for LoRa P2P/P2MP (not LoRaWAN) testing
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram 8cfe5ebc4a examples: lora atcmd minimal rx and tx
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram f098853465 examples: add minimal README to at-cmd
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram dc953b09b6 examples: lora atcmd compiled for simulator, sx126x, and sx127x
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram 59ff8a4585 examples: further work on at-lora
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram 125d8b6530 examples: WIP on adding LoRa AT command set implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:31:25 +01:00
deadprogram 1832e40f4d sx127x: correct header type implicit/explcit as they were reversed
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-08 14:30:55 +01:00
deadprogram 9af4640788 sx126x: add Reset() and needed pin
Signed-off-by: deadprogram <ron@hybridgroup.com>
2023-01-06 14:15:38 +01:00
deadprogram 65677a3836 sx127x: lora rx/tx example working, now assumes pybadge+featherwing
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-12-30 10:09:47 +01:00
deadprogram f67130b52d lora: created shared RadioEvent
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-12-30 10:09:47 +01:00
deadprogram d94003bd3a lora: move shared config for sx126x/sx127x to single package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-12-30 10:09:47 +01:00
Olivier Fauchon a421318a4d sx127x: Ajout du support d'interruptions RXTimeout (DIO1) 2022-12-23 11:07:55 +01:00
Olivier Fauchon deb22c4a57 sx127x: Major cleanup/rewrite, and tests pass with lorawan stack tests 2022-12-23 11:07:55 +01:00
Olivier Fauchon 67d2af5d45 sx127x: Driver for Semtech sx127x radio modules
This first version of the driver has been tested with BB-FRM9x module
2022-12-23 11:07:55 +01:00
BCG 877342d0ff add suport for SH1106 display driver 2022-12-23 09:30:37 +01:00
deadprogram 8b3075fdba build: remove older format build tags
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-12-21 17:47:14 -05:00
Kenneth Bell 7d58709b7d bme280: improve config support 2022-12-20 11:13:43 +01:00
Jason Del Ponte 789bbbd89f Update DHT22 receive to use runtime/interrupt
Fixes #483 by updating the DHT22 device to use runtime/interrupt instead
of machine.UART1 for interrupt disabling while receiving signals from the
device.
2022-12-20 11:10:52 +01:00
Lucas Bremgartner ea944c8933 buzzer: no tone during rest 2022-12-19 22:01:39 +01:00
Lucas Bremgartner d27859453c buzzer: make all note durations float64 2022-12-19 22:01:39 +01:00
Damian Gryski 0ccd979f23 examples: fix odd if sequence found by static analysis 2022-12-04 21:26:47 +01:00
John Clark a888570c8c fix broken link for lora sx1261 2022-11-23 22:13:43 +01:00
Michael Meister 5b2c2f800d vl53l1x: Add getter for the effective SPAD count
Implement function to get the effective SPAD count.

Signed-off-by: Michael Meister <michael.meister@bytesatwork.ch>
2022-11-15 17:58:24 +01:00
Scott Feldman 0ec887c9d8 wifinina: add support for http server (#480)
* wifinina: add support for http server

This adds http.ListenAndServe() implementation for wifinina.  Included
is an example webserver, basically copied from the rtl8720dn/webserver.

Tested on Arduino Nano RP2040 Connect.  Also tried testing on Arduino
Nano33 IoT but test panics with "out of memory".  There's only 32K of
SRAM on the Nano33, vs 264K on the rp2040 Connect.
2022-11-14 22:24:15 +01:00
112 changed files with 3036 additions and 277 deletions
+4 -3
View File
@@ -112,7 +112,7 @@ The following 90 devices are supported.
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
| [QMI8658C accelerometer/gyroscope](https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf) | I2C |
| [QMI8658C accelerometer/gyroscope](https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf) | I2C |
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
| [RTL8720DN 2.4G/5G Dual Bands Wireless and BLE5.0](https://www.seeedstudio.com/Realtek8720DN-2-4G-5G-Dual-Bands-Wireless-and-BLE5-0-Combo-Module-p-4442.html) | UART |
| [SCD4x CO2 Sensor](https://sensirion.com/media/documents/C4B87CE6/627C2DCD/CD_DS_SCD40_SCD41_Datasheet_D1.pdf) | I2C |
@@ -120,6 +120,7 @@ The following 90 devices are supported.
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
| [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 |
| [SH1106 OLED display](https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf) | I2C / SPI |
| [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 |
@@ -141,10 +142,10 @@ The following 90 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 2.9" e-paper display (V1)](https://www.waveshare.com/w/upload/e/e6/2.9inch_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 |
| [Waveshare GC9A01 TFT round display](https://www.waveshare.com/w/upload/5/5e/GC9A01A.pdf) | SPI |
| [Waveshare GC9A01 TFT round display](https://www.waveshare.com/w/upload/5/5e/GC9A01A.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 |
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-connect/sx1261) | SPI |
| [SSD1289 TFT color display](http://aitendo3.sakura.ne.jp/aitendo_data/product_img/lcd/tft2/M032C1289TP/3.2-SSD1289.pdf) | GPIO |
## Contributing
-1
View File
@@ -1,5 +1,4 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package apds9960
-1
View File
@@ -1,5 +1,4 @@
//go:build nano_33_ble
// +build nano_33_ble
package apds9960
+115 -5
View File
@@ -7,6 +7,7 @@ package bme280
import (
"math"
"time"
"tinygo.org/x/drivers"
)
@@ -33,11 +34,27 @@ type calibrationCoefficients struct {
h6 int8
}
type Oversampling byte
type Mode byte
type FilterCoefficient byte
type Period byte
// Config contains settings for filtering, sampling, and modes of operation
type Config struct {
Pressure Oversampling
Temperature Oversampling
Humidity Oversampling
Period Period
Mode Mode
IIR FilterCoefficient
}
// Device wraps an I2C connection to a BME280 device.
type Device struct {
bus drivers.I2C
Address uint16
calibrationCoefficients calibrationCoefficients
Config Config
}
// New creates a new BME280 connection. The I2C bus must already be
@@ -51,9 +68,34 @@ func New(bus drivers.I2C) Device {
}
}
// Configure sets up the device for communication and
// read the calibration coefficientes.
// ConfigureWithSettings sets up the device for communication and
// read the calibration coefficients.
//
// The default configuration is the Indoor Navigation settings
// from the BME280 datasheet.
func (d *Device) Configure() {
d.ConfigureWithSettings(Config{})
}
// ConfigureWithSettings sets up the device for communication and
// read the calibration coefficients.
//
// The default configuration if config is left at defaults is
// the Indoor Navigation settings from the BME280 datasheet.
func (d *Device) ConfigureWithSettings(config Config) {
d.Config = config
// If config is not initialized, use Indoor Navigation defaults.
if d.Config == (Config{}) {
d.Config = Config{
Mode: ModeNormal,
Period: Period0_5ms,
Temperature: Sampling2X,
Humidity: Sampling1X,
Pressure: Sampling16X,
IIR: Coeff16,
}
}
var data [24]byte
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
@@ -93,10 +135,18 @@ func (d *Device) Configure() {
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{0x3f})
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{0xB7})
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{0x00})
d.Reset()
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
// Normal mode, start measuring now
if d.Config.Mode == ModeNormal {
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
}
}
// Connected returns whether a BME280 has been found.
@@ -112,6 +162,20 @@ func (d *Device) Reset() {
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
}
// SetMode can set the device to Sleep, Normal or Forced mode
//
// Calling this method is optional, Configure can be used to set the
// initial mode if no mode change is desired. This method is most
// useful to switch between Sleep and Normal modes.
func (d *Device) SetMode(mode Mode) {
d.Config.Mode = mode
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
}
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (int32, error) {
data, err := d.readData()
@@ -186,6 +250,16 @@ func readIntLE(msb byte, lsb byte) int16 {
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
func (d *Device) readData() (data [8]byte, err error) {
if d.Config.Mode == ModeForced {
// Write the CTRL_MEAS register to trigger a measurement
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
byte(d.Config.Temperature<<5) |
byte(d.Config.Pressure<<2) |
byte(d.Config.Mode)})
time.Sleep(d.measurementDelay())
}
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
if err != nil {
println(err)
@@ -256,3 +330,39 @@ func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
return int32(100 * h)
}
// measurementDelay returns how much time each measurement will take
// on the device.
//
// This is used in forced mode to wait until a measurement is complete.
func (d *Device) measurementDelay() time.Duration {
const MeasOffset = 1250
const MeasDur = 2300
const HumMeasOffset = 575
const MeasScalingFactor = 1000
// delay is based on over-sampling rate - this table converts from
// setting to number samples
sampleRateConv := []int{0, 1, 2, 4, 8, 16}
tempOsr := 16
if d.Config.Temperature <= Sampling16X {
tempOsr = sampleRateConv[d.Config.Temperature]
}
presOsr := 16
if d.Config.Temperature <= Sampling16X {
presOsr = sampleRateConv[d.Config.Pressure]
}
humOsr := 16
if d.Config.Temperature <= Sampling16X {
humOsr = sampleRateConv[d.Config.Humidity]
}
max_delay := ((MeasOffset + (MeasDur * tempOsr) +
((MeasDur * presOsr) + HumMeasOffset) +
((MeasDur * humOsr) + HumMeasOffset)) / MeasScalingFactor)
return time.Duration(max_delay) * time.Millisecond
}
+44
View File
@@ -20,6 +20,50 @@ const (
CHIP_ID = 0x60
)
// Increasing sampling rate increases precision but also the wait time for measurements. The datasheet has a table of
// suggested values for oversampling, output data rates, and iir filter coefficients by use case.
const (
SamplingOff Oversampling = iota
Sampling1X
Sampling2X
Sampling4X
Sampling8X
Sampling16X
)
// In normal mode (the default) the sensor takes masurements periodically. In forced
// mode, the sensor takes a measurement only when requested.
//
// For use-cases with infrequent sampling, forced mode is more power efficient.
const (
ModeNormal Mode = 0x03
ModeForced Mode = 0x01
ModeSleep Mode = 0x00
)
// IIR filter coefficients, higher values means steadier measurements but slower reaction times
const (
Coeff0 FilterCoefficient = iota
Coeff2
Coeff4
Coeff8
Coeff16
)
// Period of standby in normal mode which controls how often measurements are taken
//
// Note Period10ms and Period20ms are out of sequence, but are per the datasheet
const (
Period0_5ms Period = 0b000
Period62_5ms = 0b001
Period125ms = 0b010
Period250ms = 0b011
Period500ms = 0b100
Period1000ms = 0b101
Period10ms = 0b110
Period20ms = 0b111
)
const (
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
)
+6
View File
@@ -54,6 +54,12 @@ func (l *Device) Tone(hz, duration float64) (err error) {
tempo := ((60 / l.BPM) * (duration * 1000))
// no tone during rest, just let the duration pass.
if hz == Rest {
time.Sleep(time.Duration(tempo) * time.Millisecond)
return
}
for i := 0.0; i < tempo*1000; i += tone * 2.0 {
if err = l.On(); err != nil {
return
+3 -3
View File
@@ -1,9 +1,9 @@
package buzzer
const (
Whole = 4
Half = 2
Quarter = 1
Whole = 4.0
Half = 2.0
Quarter = 1.0
Eighth = 0.500
)
-1
View File
@@ -1,5 +1,4 @@
//go:build tinygo
// +build tinygo
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
-1
View File
@@ -1,5 +1,4 @@
//go:build mimxrt1062 || stm32f405 || atsamd51 || stm32f103xx || k210 || stm32f407
// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407
package dht // import "tinygo.org/x/drivers/dht"
-1
View File
@@ -1,5 +1,4 @@
//go:build !mimxrt1062 && !stm32f405 && !atsamd51 && !stm32f103xx && !k210 && !stm32f407
// +build !mimxrt1062,!stm32f405,!atsamd51,!stm32f103xx,!k210,!stm32f407
package dht // import "tinygo.org/x/drivers/dht"
+3 -3
View File
@@ -1,5 +1,4 @@
//go:build tinygo
// +build tinygo
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
@@ -11,6 +10,7 @@ package dht // import "tinygo.org/x/drivers/dht"
import (
"machine"
"runtime/interrupt"
"time"
)
@@ -160,8 +160,8 @@ func (t *device) read() error {
// interrupts
func receiveSignals(pin machine.Pin, result []counter) {
i := uint8(0)
machine.UART1.Interrupt.Disable()
defer machine.UART1.Interrupt.Enable()
mask := interrupt.Disable()
defer interrupt.Restore(mask)
for ; i < 40; i++ {
result[i*2] = expectChange(pin, false)
result[i*2+1] = expectChange(pin, true)
-1
View File
@@ -1,5 +1,4 @@
//go:build tinygo
// +build tinygo
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
//
-1
View File
@@ -1,5 +1,4 @@
//go:build tinygo
// +build tinygo
package dht // import "tinygo.org/x/drivers/dht"
-1
View File
@@ -1,5 +1,4 @@
//go:build m5stack_core2
// +build m5stack_core2
package main
@@ -1,5 +1,4 @@
//go:build m5stack_core2
// +build m5stack_core2
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd21
// +build atsamd21
package initdisplay
-1
View File
@@ -1,5 +1,4 @@
//go:build feather_m0 || feather_m4 || feather_m4_can || feather_nrf52840 || feather_nrf52840_sense || feather_stm32f405 || feather_rp2040
// +build feather_m0 feather_m4 feather_m4_can feather_nrf52840 feather_nrf52840_sense feather_stm32f405 feather_rp2040
package initdisplay
-1
View File
@@ -1,5 +1,4 @@
//go:build m5stack
// +build m5stack
package initdisplay
@@ -1,5 +1,4 @@
//go:build m5stack_core2
// +build m5stack_core2
package initdisplay
-1
View File
@@ -1,5 +1,4 @@
//go:build pyportal
// +build pyportal
package initdisplay
@@ -1,5 +1,4 @@
//go:build wioterminal
// +build wioterminal
package initdisplay
+29
View File
@@ -0,0 +1,29 @@
# AT-CMD implementation of at-lora command set
```
$ tinygo monitor
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
+AT: OK
+VER: 0.0.1 (sx127x v18)
```
# Building
## Simulator
```
tinygo flash -target pico ./examples/lora/atcmd/
```
## PyBadge with LoRa Featherwing
```
tinygo flash -target pybadge -tags featherwing ./examples/lora/atcmd/
```
## LoRa-E5
```
tinygo flash -target lorae5 ./examples/lora/atcmd/
```
+410
View File
@@ -0,0 +1,410 @@
package main
import (
"encoding/hex"
"strings"
)
// Use to test if connection to module is OK.
func quicktest() {
writeCommandOutput("AT", "OK")
}
// Check firmware version.
func version() {
writeCommandOutput("VER", currentVersion()+" ("+firmwareVersion()+")")
}
// Use to check the ID of the LoRaWAN module, or change the ID.
func id(args string) error {
cmd := "ID"
// look for comma in args
param, val, hasComma := strings.Cut(args, ",")
if hasComma {
// set
switch param {
case "DevAddr":
writeCommandOutput(cmd, "DevAddr, "+val)
case "DevEui":
writeCommandOutput(cmd, "DevEui, "+val)
case "AppEui":
writeCommandOutput(cmd, "AppEui, "+val)
default:
return errInvalidCommand
}
return nil
}
// get
switch param {
case "DevAddr":
writeCommandOutput(cmd, "DevAddr, xx:xx:xx:xx")
case "DevEui":
writeCommandOutput(cmd, "DevEui, xx:xx:xx:xx:xx:xx:xx:xx")
case "AppEui":
writeCommandOutput(cmd, "AppEui, xx:xx:xx:xx:xx:xx:xx:xx")
default:
writeCommandOutput(cmd, "DevAddr, xx:xx:xx:xx")
writeCommandOutput(cmd, "DevEui, xx:xx:xx:xx:xx:xx:xx:xx")
writeCommandOutput(cmd, "AppEui, xx:xx:xx:xx:xx:xx:xx:xx")
}
return nil
}
// Use to reset the module. If module returns error, then reset function is invalid.
func reset() error {
radio.Reset()
writeCommandOutput("RESET", "OK")
return nil
}
// Use to send string format frame which is no need to be confirmed by the server.
func msg(data string) error {
cmd := "MSG"
writeCommandOutput(cmd, "Start")
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
writeCommandOutput(cmd, err.Error())
return err
}
writeCommandOutput(cmd, "Done")
return nil
}
// Use to send string format frame which must be confirmed by the server
func cmsg(data string) error {
cmd := "CMSG"
writeCommandOutput(cmd, "Start")
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
writeCommandOutput(cmd, err.Error())
return err
}
// TODO: confirmation
writeCommandOutput(cmd, "Done")
return nil
}
// Use to send hex format frame which is no need to be confirmed by the server
func msghex(data string) error {
cmd := "MSGHEX"
writeCommandOutput(cmd, "Start")
writeCommandOutput(cmd, "Done")
return nil
}
// Use to send hex format frame which must be confirmed by the server.
func cmsghex(data string) error {
cmd := "CMSGHEX"
writeCommandOutput(cmd, "Start")
writeCommandOutput(cmd, "Done")
return nil
}
// Use to send string format LoRaWAN proprietary frames
func pmsg(data string) error {
cmd := "PMSG"
writeCommandOutput(cmd, "Start")
writeCommandOutput(cmd, "Done")
return nil
}
// Use to send hex format LoRaWAN proprietary frames.
func pmsghex(data string) error {
cmd := "PMSGHEX"
writeCommandOutput(cmd, "Start")
writeCommandOutput(cmd, "Done")
return nil
}
// Set PORT number which will be used by MSG/CMSG/MSGHEX/CMSGHEX command to send
// message, port number should range from 1 to 255. User should refer to LoRaWAN
// specification to choose port.
func port(p string) error {
cmd := "PMSG"
writeCommandOutput(cmd, p)
return nil
}
// Set ADR function of LoRaWAN module
func adr(state string) error {
cmd := "ADR"
writeCommandOutput(cmd, state)
return nil
}
// Use LoRaWAN defined DRx to set datarate of LoRaWAN AT modem.
func dr(rate string) error {
cmd := "DR"
writeCommandOutput(cmd, rate)
return nil
}
// Channel Configuration
func ch(channel string) error {
cmd := "CH"
writeCommandOutput(cmd, channel)
return nil
}
// Set and Check Power
func power(setting string) error {
cmd := "POWER"
writeCommandOutput(cmd, setting)
return nil
}
// Unconfirmed message repeats times.
func rept(setting string) error {
cmd := "REPT"
writeCommandOutput(cmd, setting)
return nil
}
// Confirmed message retry times. Valid range 0~254,
// if retry times is less than 2, only one message will
// be sent. Random delay 3 - 10s between each retry
// (band duty cycle limitation has the priority)
func retry(setting string) error {
cmd := "RETRY"
writeCommandOutput(cmd, setting)
return nil
}
func rxwin2(setting string) error {
cmd := "RXWIN2"
writeCommandOutput(cmd, setting)
return nil
}
func rxwin1(setting string) error {
cmd := "RXWIN1"
writeCommandOutput(cmd, setting)
return nil
}
func key(setting string) error {
cmd := "KEY"
writeCommandOutput(cmd, setting)
return nil
}
func fdefault(setting string) error {
cmd := "FDEFAULT"
writeCommandOutput(cmd, "OK")
return nil
}
func mode(setting string) error {
cmd := "MODE"
writeCommandOutput(cmd, setting)
return nil
}
func join(setting string) error {
cmd := "JOIN"
writeCommandOutput(cmd, "Starting")
writeCommandOutput(cmd, "Done")
return nil
}
func beacon(setting string) error {
cmd := "BEACON"
writeCommandOutput(cmd, "Starting")
writeCommandOutput(cmd, "Done")
return nil
}
func class(setting string) error {
cmd := "CLASS"
writeCommandOutput(cmd, "Starting")
writeCommandOutput(cmd, "Done")
return nil
}
func delay(setting string) error {
cmd := "DELAY"
writeCommandOutput(cmd, setting)
return nil
}
func lw(setting string) error {
cmd := "LW"
writeCommandOutput(cmd, setting)
return nil
}
func wdt(setting string) error {
cmd := "WDT"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func lowpower(setting string) error {
cmd := "LOWPOWER"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func vdd(setting string) error {
cmd := "VDD"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func temp(setting string) error {
cmd := "TEMP"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func rtc(setting string) error {
cmd := "RTC"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func eeprom(setting string) error {
cmd := "EEPROM"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func uartcmd(setting string) error {
cmd := "UART"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func test(setting string) error {
cmd := "TEST"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func log(setting string) error {
cmd := "LOG"
writeCommandOutput(cmd, "Not implemented")
return nil
}
func send(data string) error {
cmd := "SEND"
writeCommandOutput(cmd, "Start")
// remove leading/trailing quotes
data = strings.Trim(data, "\"'")
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
writeCommandOutput(cmd, err.Error())
return err
}
writeCommandOutput(cmd, "Done")
return nil
}
func sendhex(data string) error {
cmd := "SENDHEX"
writeCommandOutput(cmd, "Start")
// remove leading/trailing quotes
data = strings.Trim(data, "\"'")
// convert data from hex formatted string
data = strings.ReplaceAll(data, " ", "")
payload, err := hex.DecodeString(data)
if err != nil {
writeCommandOutput(cmd, err.Error())
return err
}
if err := radio.Tx(payload, defaultTimeout); err != nil {
writeCommandOutput(cmd, err.Error())
return err
}
writeCommandOutput(cmd, "Done")
return nil
}
func recv(setting string) error {
cmd := "RECV"
data, err := lorarx()
if err != nil {
writeCommandOutput(cmd, "ERROR "+err.Error())
return err
}
writeCommandOutput(cmd, string(data))
return nil
}
func recvhex(setting string) error {
cmd := "RECVHEX"
data, err := lorarx()
if err != nil {
writeCommandOutput(cmd, "ERROR "+err.Error())
return err
}
writeCommandOutput(cmd, string(data))
return nil
}
func crlf() {
uart.Write([]byte("\r\n"))
}
func writeCommandOutput(cmd, data string) {
uart.Write([]byte("+" + cmd + ": "))
uart.Write([]byte(data))
crlf()
}
+65
View File
@@ -0,0 +1,65 @@
// AT command set console running on the device UART to communicate with
// an attached LoRa device.
//
// Computer <-> UART <-> MCU <-> SPI <-> SX126x/SX127x
//
// Connect using default baudrate for this hardware, 8-N-1 with your terminal program.
// For details on the AT command set, see:
// https://files.seeedstudio.com/products/317990687/res/LoRa-E5%20AT%20Command%20Specification_V1.0%20.pdf
package main
import (
"machine"
"time"
)
// change these to test a different UART or pins if available
var (
uart = machine.Serial
tx = machine.UART_TX_PIN
rx = machine.UART_RX_PIN
input = make([]byte, 0, 64)
radio LoraRadio
defaultTimeout uint32 = 1000
)
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
var err error
radio, err = setupLora()
if err != nil {
fail(err.Error())
}
for {
if uart.Buffered() > 0 {
data, _ := uart.ReadByte()
switch data {
case 13:
// return key
if err := parse(input); err != nil {
uart.Write([]byte("ERROR: "))
uart.Write([]byte(err.Error()))
crlf()
}
input = input[:0]
default:
// just capture the character
input = append(input, data)
}
}
time.Sleep(10 * time.Millisecond)
}
}
func fail(msg string) {
for {
uart.Write([]byte(msg))
crlf()
time.Sleep(time.Minute)
}
}
+115
View File
@@ -0,0 +1,115 @@
package main
import (
"errors"
"strings"
)
var (
errInvalidCommand = errors.New("Invalid command")
)
func parse(data []byte) error {
switch {
case len(data) < 2, string(data[0:2]) != "AT":
return errInvalidCommand
case len(data) == 2:
// just the AT command by itself
quicktest()
case len(data) < 6 || data[2] != '+':
return errInvalidCommand
default:
// parse the rest of the command
cmd, args, _ := strings.Cut(string(data[3:]), "=")
return parseCommand(cmd, args)
}
return nil
}
func parseCommand(cmd, args string) error {
switch cmd {
case "VER":
version()
case "ID":
id(args)
case "RESET":
reset()
case "MSG":
msg(args)
case "CMSG":
cmsg(args)
case "MSGHEX":
msghex(args)
case "CMSGHEX":
cmsghex(args)
case "PMSG":
pmsg(args)
case "PMSGHEX":
pmsg(args)
case "PORT":
port(args)
case "ADR":
adr(args)
case "DR":
dr(args)
case "CH":
ch(args)
case "POWER":
power(args)
case "REPT":
rept(args)
case "RETRY":
retry(args)
case "RXWIN2":
rxwin2(args)
case "RXWIN1":
rxwin1(args)
case "KEY":
key(args)
case "FDEFAULT":
fdefault(args)
case "MODE":
mode(args)
case "JOIN":
join(args)
case "BEACON":
join(args)
case "CLASS":
class(args)
case "DELAY":
delay(args)
case "LW":
lw(args)
case "WDT":
wdt(args)
case "LOWPOWER":
lowpower(args)
case "VDD":
vdd(args)
case "TEMP":
temp(args)
case "RTC":
rtc(args)
case "EEPROM":
eeprom(args)
case "UART":
uartcmd(args)
case "TEST":
test(args)
case "LOG":
log(args)
case "RECV":
recv(args)
case "RECVHEX":
recvhex(args)
case "SEND":
send(args)
case "SENDHEX":
sendhex(args)
default:
return errInvalidCommand
}
return nil
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"errors"
)
var (
errRadioNotFound = errors.New("radio not found")
errRxTimeout = errors.New("radio RX timeout")
)
type LoraRadio interface {
Reset()
Tx(pkt []uint8, timeoutMs uint32) error
Rx(timeoutMs uint32) ([]uint8, error)
SetFrequency(freq uint32)
SetIqMode(mode uint8)
SetCodingRate(cr uint8)
SetBandwidth(bw uint8)
SetCrc(enable bool)
SetSpreadingFactor(sf uint8)
}
+37
View File
@@ -0,0 +1,37 @@
//go:build !featherwing && !gnse && !lorae5 && !nucleowl55jc
package main
// do simulator setup here
func setupLora() (LoraRadio, error) {
return &SimLoraRadio{}, nil
}
type SimLoraRadio struct {
}
func (sr *SimLoraRadio) Reset() {
}
func (sr *SimLoraRadio) Tx(pkt []uint8, timeoutMs uint32) error {
return nil
}
func (sr *SimLoraRadio) Rx(timeoutMs uint32) ([]uint8, error) {
return nil, nil
}
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
func (sr *SimLoraRadio) SetCrc(enable bool) {}
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
func firmwareVersion() string {
return "simulator " + currentVersion()
}
func lorarx() ([]byte, error) {
return nil, nil
}
+73
View File
@@ -0,0 +1,73 @@
//go:build gnse || lorae5 || nucleowl55jc
package main
import (
"device/stm32"
"machine"
"runtime/interrupt"
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
"tinygo.org/x/drivers/lora"
"tinygo.org/x/drivers/sx126x"
)
const (
FREQ = 868100000
LORA_DEFAULT_RXTIMEOUT_MS = 1000
LORA_DEFAULT_TXTIMEOUT_MS = 5000
)
var (
loraRadio *sx126x.Device
)
// do sx126x setup here
func setupLora() (LoraRadio, error) {
loraRadio = sx126x.New(machine.SPI3)
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
// Create RF Switch
var radioSwitch rfswitch.CustomSwitch
loraRadio.SetRfSwitch(radioSwitch)
if state := loraRadio.DetectDevice(); !state {
return nil, errRadioNotFound
}
// Add interrupt handler for Radio IRQs
intr := interrupt.New(stm32.IRQ_Radio_IRQ_Busy, radioIntHandler)
intr.Enable()
loraConf := lora.Config{
Freq: FREQ,
Bw: lora.Bandwidth_500_0,
Sf: lora.SpreadingFactor9,
Cr: lora.CodingRate4_7,
HeaderType: lora.HeaderExplicit,
Preamble: 12,
Ldr: lora.LowDataRateOptimizeOff,
Iq: lora.IQStandard,
Crc: lora.CRCOn,
SyncWord: lora.SyncPrivate,
LoraTxPowerDBm: 20,
}
loraRadio.LoraConfig(loraConf)
return loraRadio, nil
}
// radioIntHandler will take care of radio interrupts
func radioIntHandler(intr interrupt.Interrupt) {
loraRadio.HandleInterrupt()
}
func firmwareVersion() string {
return "sx126x"
}
func lorarx() ([]byte, error) {
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
}
+85
View File
@@ -0,0 +1,85 @@
//go:build featherwing
package main
import (
"strconv"
"machine"
"tinygo.org/x/drivers/lora"
"tinygo.org/x/drivers/sx127x"
)
const (
FREQ = 868100000
LORA_DEFAULT_RXTIMEOUT_MS = 1000
LORA_DEFAULT_TXTIMEOUT_MS = 5000
)
var (
// We assume LoRa Featherwing module is connected to PyBadge:
rstPin = machine.D11
csPin = machine.D10
dio0Pin = machine.D6
dio1Pin = machine.D9
spi = machine.SPI0
loraRadio *sx127x.Device
)
// do sx127x setup here
func setupLora() (LoraRadio, error) {
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dio0Pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
dio1Pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
spi.Configure(machine.SPIConfig{Frequency: 500000, Mode: 0})
loraRadio = sx127x.New(spi, csPin, rstPin)
loraRadio.Reset()
if state := loraRadio.DetectDevice(); !state {
return nil, errRadioNotFound
}
// Setup DIO0 interrupt Handling
if err := dio0Pin.SetInterrupt(machine.PinRising, dioIrqHandler); err != nil {
println("could not configure DIO0 pin interrupt:", err.Error())
}
// Setup DIO1 interrupt Handling
if err := dio1Pin.SetInterrupt(machine.PinRising, dioIrqHandler); err != nil {
println("could not configure DIO1 pin interrupt:", err.Error())
}
// Prepare for Lora Operation
loraConf := lora.Config{
Freq: FREQ,
Bw: lora.Bandwidth_500_0,
Sf: lora.SpreadingFactor9,
Cr: lora.CodingRate4_7,
HeaderType: lora.HeaderExplicit,
Preamble: 12,
Iq: lora.IQStandard,
Crc: lora.CRCOn,
SyncWord: lora.SyncPrivate,
LoraTxPowerDBm: 20,
}
loraRadio.LoraConfig(loraConf)
return loraRadio, nil
}
func dioIrqHandler(machine.Pin) {
loraRadio.HandleInterrupt()
}
func firmwareVersion() string {
v := loraRadio.GetVersion()
return "sx127x v" + strconv.Itoa(int(v))
}
func lorarx() ([]byte, error) {
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
}
+7
View File
@@ -0,0 +1,7 @@
package main
const VERSION = "0.0.1"
func currentVersion() string {
return VERSION
}
+54
View File
@@ -0,0 +1,54 @@
//go: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 main
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
}
+1 -3
View File
@@ -100,9 +100,7 @@ func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
} else if n == 0 {
continue // no packet received yet
} else if n != NTP_PACKET_SIZE {
if n != NTP_PACKET_SIZE {
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
}
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
}
return parseNTPpacket(), nil
}
-1
View File
@@ -1,5 +1,4 @@
//go:build feather_m4 || feather_m4_can || feather_nrf52840
// +build feather_m4 feather_m4_can feather_nrf52840
package main
@@ -1,5 +1,4 @@
//go:build grandcentral_m4
// +build grandcentral_m4
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd21 && !p1am_100
// +build atsamd21,!p1am_100
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build p1am_100
// +build p1am_100
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build pygamer
// +build pygamer
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build pyportal
// +build pyportal
package main
@@ -1,5 +1,4 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build wioterminal
// +build wioterminal
package main
@@ -1,5 +1,4 @@
//go:build tinygo
// +build tinygo
package console
-1
View File
@@ -1,5 +1,4 @@
//go:build feather_m4 || feather_m4_can || feather_nrf52840
// +build feather_m4 feather_m4_can feather_nrf52840
package main
@@ -1,5 +1,4 @@
//go:build grandcentral_m4
// +build grandcentral_m4
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd21 && !p1am_100
// +build atsamd21,!p1am_100
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build p1am_100
// +build p1am_100
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build pygamer
// +build pygamer
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build pyportal
// +build pyportal
package main
@@ -1,5 +1,4 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build wioterminal
// +build wioterminal
package main
+56
View File
@@ -0,0 +1,56 @@
//go:build macropad_rp2040
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/sh1106"
)
var (
display = sh1106.NewSPI(machine.SPI1, machine.OLED_DC, machine.OLED_RST, machine.OLED_CS)
)
func init() {
machine.SPI1.Configure(machine.SPIConfig{
Frequency: 48000000,
})
display.Configure(sh1106.Config{
Width: 128,
Height: 64,
})
}
func main() {
display.ClearDisplay()
x := int16(0)
y := int16(0)
deltaX := int16(1)
deltaY := int16(1)
for {
pixel := display.GetPixel(x, y)
c := color.RGBA{255, 255, 255, 255}
if pixel {
c = color.RGBA{0, 0, 0, 255}
}
display.SetPixel(x, y, c)
display.Display()
x += deltaX
y += deltaY
if x == 0 || x == 127 {
deltaX = -deltaX
}
if y == 0 || y == 63 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
@@ -7,6 +7,7 @@ import (
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
"tinygo.org/x/drivers/lora"
"tinygo.org/x/drivers/sx126x"
)
@@ -36,17 +37,17 @@ func main() {
}
// Prepare for Lora operation
loraConf := sx126x.LoraConfig{
loraConf := lora.Config{
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,
Bw: lora.Bandwidth_500_0,
Sf: lora.SpreadingFactor9,
Cr: lora.CodingRate4_7,
HeaderType: lora.HeaderExplicit,
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,
Ldr: lora.LowDataRateOptimizeOff,
Iq: lora.IQStandard,
Crc: lora.CRCOn,
SyncWord: lora.SyncPrivate,
LoraTxPowerDBm: 14,
}
loraRadio.LoraConfig(loraConf)
+15 -17
View File
@@ -11,6 +11,7 @@ import (
rfswitch "tinygo.org/x/drivers/examples/sx126x/rfswitch"
"tinygo.org/x/drivers/lora"
"tinygo.org/x/drivers/sx126x"
)
@@ -54,17 +55,17 @@ func main() {
intr := interrupt.New(stm32.IRQ_Radio_IRQ_Busy, radioIntHandler)
intr.Enable()
loraConf := sx126x.LoraConfig{
loraConf := lora.Config{
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,
Bw: lora.Bandwidth_500_0,
Sf: lora.SpreadingFactor9,
Cr: lora.CodingRate4_7,
HeaderType: lora.HeaderExplicit,
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,
Ldr: lora.LowDataRateOptimizeOff,
Iq: lora.IQStandard,
Crc: lora.CRCOn,
SyncWord: lora.SyncPrivate,
LoraTxPowerDBm: 20,
}
@@ -74,21 +75,18 @@ func main() {
for {
tStart := time.Now()
// Blocking RX for LORA_DEFAULT_RXTIMEOUT_MS
println("Start Lora RX for 10 sec")
println("main: Receiving Lora for 10 seconds")
for int(time.Now().Sub(tStart).Seconds()) < 10 {
buf, err := loraRadio.LoraRx(LORA_DEFAULT_RXTIMEOUT_MS)
buf, err := loraRadio.Rx(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)
println("main: End Lora RX")
println("LORA TX size=", len(txmsg), " -> ", string(txmsg))
err := loraRadio.Tx(txmsg, LORA_DEFAULT_TXTIMEOUT_MS)
if err != nil {
println("TX Error:", err)
}
-1
View File
@@ -1,5 +1,4 @@
//go:build gnse
// +build gnse
/*
Generic Node Sensor Edition
-1
View File
@@ -1,5 +1,4 @@
//go:build lorae5
// +build lorae5
package radio
-1
View File
@@ -1,5 +1,4 @@
//go:build nucleowl55jc
// +build nucleowl55jc
/*
Nucleo WL55JC1
+106
View File
@@ -0,0 +1,106 @@
package main
// This example code demonstrates Lora RX/TX With SX127x driver
// You need to connect SPI, RST, CS, DIO0 (aka IRQ) and DIO1 to use.
import (
"machine"
"time"
"tinygo.org/x/drivers/lora"
"tinygo.org/x/drivers/sx127x"
)
const FREQ = 868100000
const (
LORA_DEFAULT_RXTIMEOUT_MS = 1000
LORA_DEFAULT_TXTIMEOUT_MS = 5000
)
var (
loraRadio *sx127x.Device
txmsg = []byte("Hello TinyGO")
// We assume LoRa Featherwing module is connected to PyBadge:
SX127X_PIN_RST = machine.D11
SX127X_PIN_CS = machine.D10
SX127X_PIN_DIO0 = machine.D6
SX127X_PIN_DIO1 = machine.D9
SX127X_SPI = machine.SPI0
)
func dioIrqHandler(machine.Pin) {
loraRadio.HandleInterrupt()
}
func main() {
time.Sleep(5 * time.Second)
println("\n# TinyGo Lora RX/TX test")
println("# ----------------------")
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
SX127X_PIN_RST.Configure(machine.PinConfig{Mode: machine.PinOutput})
SX127X_PIN_CS.Configure(machine.PinConfig{Mode: machine.PinOutput})
SX127X_PIN_DIO0.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
SX127X_PIN_DIO1.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
SX127X_SPI.Configure(machine.SPIConfig{Frequency: 500000, Mode: 0})
println("main: create and start SX127x driver")
loraRadio = sx127x.New(SX127X_SPI, SX127X_PIN_CS, SX127X_PIN_RST)
loraRadio.Reset()
state := loraRadio.DetectDevice()
if !state {
panic("main: sx127x NOT FOUND !!!")
} else {
println("main: sx127x found")
}
// Setup DIO0 interrupt Handling
if err := SX127X_PIN_DIO0.SetInterrupt(machine.PinRising, dioIrqHandler); err != nil {
println("could not configure DIO0 pin interrupt:", err.Error())
}
// Setup DIO1 interrupt Handling
if err := SX127X_PIN_DIO1.SetInterrupt(machine.PinRising, dioIrqHandler); err != nil {
println("could not configure DIO1 pin interrupt:", err.Error())
}
// Prepare for Lora Operation
loraConf := lora.Config{
Freq: FREQ,
Bw: lora.Bandwidth_500_0,
Sf: lora.SpreadingFactor9,
Cr: lora.CodingRate4_7,
HeaderType: lora.HeaderExplicit,
Preamble: 12,
Iq: lora.IQStandard,
Crc: lora.CRCOn,
SyncWord: lora.SyncPrivate,
LoraTxPowerDBm: 20,
}
loraRadio.LoraConfig(loraConf)
var count uint
for {
tStart := time.Now()
println("main: Receiving Lora for 10 seconds")
for time.Since(tStart) < 10*time.Second {
buf, err := loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
if err != nil {
println("RX Error: ", err)
} else if buf != nil {
println("Packet Received: len=", len(buf), string(buf))
}
}
println("main: End Lora RX")
println("LORA TX size=", len(txmsg), " -> ", string(txmsg))
err := loraRadio.Tx(txmsg, LORA_DEFAULT_TXTIMEOUT_MS)
if err != nil {
println("TX Error:", err)
}
count++
}
}
-1
View File
@@ -1,5 +1,4 @@
//go:build espat
// +build espat
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build rtl8720dn
// +build rtl8720dn
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build wifinina
// +build wifinina
package main
+1 -3
View File
@@ -111,9 +111,7 @@ func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
} else if n == 0 {
continue // no packet received yet
} else if n != NTP_PACKET_SIZE {
if n != NTP_PACKET_SIZE {
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
}
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
}
return parseNTPpacket(), nil
}
-1
View File
@@ -1,5 +1,4 @@
//go:build nano_rp2040
// +build nano_rp2040
// This examples shows how to control RGB LED connected to
// NINA-W102 chip on Arduino Nano RP2040 Connect board
+209
View File
@@ -0,0 +1,209 @@
package main
import (
"fmt"
"machine"
"strconv"
"time"
"tinygo.org/x/drivers/net/http"
"tinygo.org/x/drivers/wifinina"
)
// You can override the settings with the init() in another source code:
//
// func init() {
// ssid = "your-ssid"
// pass = "your-password"
// }
//
// Or use -ldflags option on tinygo command to set at compile-time:
//
// tinygo flash ... -ldflags '-X "main.ssid=xxx" -X "main.pass=xxx"' ...
//
var (
ssid string
pass string
)
var led = machine.LED
func main() {
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
err := run()
for err != nil {
fmt.Printf("error: %s\r\n", err.Error())
time.Sleep(5 * time.Second)
}
}
func run() error {
spi := machine.NINA_SPI
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
adaptor := wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
time.Sleep(2 * time.Second)
println("Connecting to " + ssid)
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
if err != nil {
return err
}
println("Connected.")
time.Sleep(2 * time.Second)
ip, subnet, gateway, err := adaptor.GetIP()
if err != nil {
return err
}
fmt.Printf("IP Address : %s\r\n", ip)
fmt.Printf("Mask : %s\r\n", subnet)
fmt.Printf("Gateway : %s\r\n", gateway)
http.UseDriver(adaptor)
http.HandleFunc("/", root)
http.HandleFunc("/hello", hello)
http.HandleFunc("/cnt", cnt)
http.HandleFunc("/6", sixlines)
http.HandleFunc("/off", LED_OFF)
http.HandleFunc("/on", LED_ON)
return http.ListenAndServe(":80", nil)
}
func root(w http.ResponseWriter, r *http.Request) {
access := 1
cookie, err := r.Cookie("access")
if err != nil {
if err == http.ErrNoCookie {
cookie = &http.Cookie{
Name: "access",
Value: "1",
}
} else {
http.Error(w, fmt.Sprintf("%s", err.Error()), http.StatusBadRequest)
return
}
} else {
v, err := strconv.ParseInt(cookie.Value, 10, 0)
if err != nil {
http.Error(w, fmt.Sprintf("invalid cookie.Value : %s", cookie.Value), http.StatusBadRequest)
return
}
cookie.Value = fmt.Sprintf("%d", v+1)
access = int(v) + 1
}
http.SetCookie(w, cookie)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `
<html>
<head>
<title>TinyGo HTTP Server</title>
<script language="javascript" type="text/javascript">
var counter = 0
function ledOn() { fetch("/on"); }
function ledOff() { fetch("/off"); }
function fetchCnt() { fetch("/cnt").then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
function incrCnt() { counter = counter + 1; fetch("/cnt?cnt=" + counter, { method: 'POST' }).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
function setCnt() { fetch("/cnt", {
method: "POST",
body: "cnt=" + document.getElementsByName("cnt")[0].value,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); return false; }
function onLoad() { fetchCnt(); }
</script>
</head>
<body onLoad="onLoad()">
<h5>TinyGo HTTP Server</h5>
<p>
access: %d
</p>
<a href="/hello">/hello</a><br>
<a href="/6">/6</a><br>
<p>
LED<br>
<a href="javascript:ledOn();">/on</a><br>
<a href="javascript:ledOff();">/off</a><br>
</p>
<p>
<a href="/cnt">/cnt</a><br>
cnt: <span id="cnt"></span><br>
<a href="javascript:incrCnt()">incrCnt()</a><br>
<form id="form1" style="display: inline" onSubmit="return setCnt()">
<input type="text" name="cnt">
<input type="button" value="set cnt", onClick="setCnt()">
</form>
</p>
</body>
</html>
`, access)
}
func sixlines(w http.ResponseWriter, r *http.Request) {
// https://fukuno.jig.jp/3267
fmt.Fprint(w, `<body onload='onkeydown=e=>K=parseInt(e.key[5]||6,28)/3-8;Z=X=[B=A=12];Y=_=>`+
`{for(C=[q=c=i=4];f=i--*K;c-=!Z[h+(K+6?p+K:C[i]=p*A-(p/9|0)*145)])p=B[i];for(c?0:K+6?h+=K:B=C;`+
`i=K=q--;f+=Z[A+p])X[p=h+B[q]]=1;h+=A;if(f|B)for(Z=X,X=[l=228],B=[[-7,-20,6,h=17,-9,3,3][t=++t%7]-4,0,1,t-6?-A:2];l--;)`+
`for(l%A?l-=l%A*!Z[l]:(P++,c=l+=A);--c>A;)Z[c]=Z[c-A];for(S="";i<240;S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?i%A?"■":"■<br>":" ");`+
`D.innerHTML=S+P;setTimeout(Y,i-P)};Y(h=K=t=P=0)'id=D>`)
}
func LED_ON(w http.ResponseWriter, r *http.Request) {
led.High()
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
fmt.Fprintf(w, "led.High()")
}
func LED_OFF(w http.ResponseWriter, r *http.Request) {
led.Low()
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
fmt.Fprintf(w, "led.Low()")
}
func hello(w http.ResponseWriter, r *http.Request) {
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
fmt.Fprintf(w, "hello")
}
var counter int
func cnt(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
if r.Method == "POST" {
c := r.Form.Get("cnt")
if c != "" {
i64, _ := strconv.ParseInt(c, 0, 0)
counter = int(i64)
}
}
w.Header().Set(`Content-Type`, `application/json`)
fmt.Fprintf(w, `{"cnt": %d}`, counter)
}
func message(msg string) {
println(msg, "\r")
}
-1
View File
@@ -1,5 +1,4 @@
//go:build arduino
// +build arduino
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build digispark
// +build digispark
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3 && !thingplus_rp2040
// +build !digispark,!arduino,!qtpy,!m5stamp_c3,!thingplus_rp2040
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build qtpy || m5stamp_c3
// +build qtpy m5stamp_c3
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build qtpy
// +build qtpy
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build thingplus_rp2040
// +build thingplus_rp2040
package main
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd51
// +build atsamd51
package flash
-1
View File
@@ -1,5 +1,4 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package hts221
-1
View File
@@ -1,5 +1,4 @@
//go:build nano_33_ble
// +build nano_33_ble
package hts221
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd51 || atsame5x
// +build atsamd51 atsame5x
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build esp32
// +build esp32
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build nrf52840
// +build nrf52840
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build !esp32 && !atsamd51 && !atsame5x && !stm32f4 && !rp2040 && !nrf52840
// +build !esp32,!atsamd51,!atsame5x,!stm32f4,!rp2040,!nrf52840
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build rp2040
// +build rp2040
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build stm32f4
// +build stm32f4
package i2csoft
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd51
// +build atsamd51
package ili9341
-1
View File
@@ -1,5 +1,4 @@
//go:build !atsamd51 && !atsame5x && !atsamd21
// +build !atsamd51,!atsame5x,!atsamd21
package ili9341
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd21
// +build atsamd21
package ili9341
-1
View File
@@ -1,5 +1,4 @@
//go:build atsamd51 || atsame5x
// +build atsamd51 atsame5x
package ili9341
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
package main
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gofuzz
// +build gofuzz
package png
+78
View File
@@ -0,0 +1,78 @@
package lora
import "errors"
// Config holds the LoRa configuration parameters
type Config 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
}
var (
ErrUndefinedLoraConf = errors.New("Undefined Lora configuration")
)
const (
SpreadingFactor5 = 0x05
SpreadingFactor6 = 0x06
SpreadingFactor7 = 0x07
SpreadingFactor8 = 0x08
SpreadingFactor9 = 0x09
SpreadingFactor10 = 0x0A
SpreadingFactor11 = 0x0B
SpreadingFactor12 = 0x0C
)
const (
CodingRate4_5 = 0x01 // 7 0 LoRa coding rate: 4/5
CodingRate4_6 = 0x02 // 7 0 4/6
CodingRate4_7 = 0x03 // 7 0 4/7
CodingRate4_8 = 0x04 // 7 0 4/8
)
const (
HeaderExplicit = 0x00 // 7 0 LoRa header mode: explicit
HeaderImplicit = 0x01 // 7 0 implicit
)
const (
LowDataRateOptimizeOff = 0x00 // 7 0 LoRa low data rate optimization: disabled
LowDataRateOptimizeOn = 0x01 // 7 0 enabled
)
const (
CRCOff = 0x00 // 7 0 LoRa CRC mode: disabled
CRCOn = 0x01 // 7 0 enabled
)
const (
IQStandard = 0x00 // 7 0 LoRa IQ setup: standard
IQInverted = 0x01 // 7 0 inverted
)
const (
Bandwidth_7_8 = iota // 7.8 kHz
Bandwidth_10_4 // 10.4 kHz
Bandwidth_15_6 // 15.6 kHz
Bandwidth_20_8 // 20.8 kHz
Bandwidth_31_25 // 31.25 kHz
Bandwidth_41_7 // 41.7 kHz
Bandwidth_62_5 // 62.5 kHz
Bandwidth_125_0 // 125.0 kHz
Bandwidth_250_0 // 250.0 kHz
Bandwidth_500_0 // 500.0 kHz
)
const (
SyncPublic = iota
SyncPrivate
)
+23
View File
@@ -0,0 +1,23 @@
package lora
const (
RadioEventRxDone = iota
RadioEventTxDone
RadioEventTimeout
RadioEventWatchdog
RadioEventCrcError
RadioEventUnhandled
)
// RadioEvent are used for communicating in the radio Event Channel
type RadioEvent struct {
EventType int
IRQStatus uint16
EventData []byte
}
// 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
}
-1
View File
@@ -1,5 +1,4 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package lps22hb
-1
View File
@@ -1,5 +1,4 @@
//go:build nano_33_ble
// +build nano_33_ble
package lps22hb
-1
View File
@@ -1,5 +1,4 @@
//go:build !xiao_ble
// +build !xiao_ble
package lsm6ds3tr
-1
View File
@@ -1,5 +1,4 @@
//go:build xiao_ble
// +build xiao_ble
package lsm6ds3tr
-1
View File
@@ -1,5 +1,4 @@
//go:build !nano_33_ble
// +build !nano_33_ble
package lsm9ds1
-1
View File
@@ -1,5 +1,4 @@
//go:build nano_33_ble
// +build nano_33_ble
// Nano 33 BLE [Sense] has LSM9DS1 unit on-board.
// This custom Configure function powers unit up
-1
View File
@@ -1,5 +1,4 @@
//go:build microbit
// +build microbit
// Package microbitmatrix implements a driver for the BBC micro:bit's LED matrix.
//
-1
View File
@@ -1,5 +1,4 @@
//go:build microbit_v2
// +build microbit_v2
// Package microbitmatrix implements a driver for the BBC micro:bit version 2 LED matrix.
//
+40
View File
@@ -0,0 +1,40 @@
package sh1106
// Registers
const (
Address = 0x3C
SETCONTRAST = 0x81
DISPLAYALLON_RESUME = 0xA4
DISPLAYALLON = 0xA5
NORMALDISPLAY = 0xA6
INVERTDISPLAY = 0xA7
DISPLAYOFF = 0xAE
DISPLAYON = 0xAF
SETDISPLAYOFFSET = 0xD3
SETCOMPINS = 0xDA
SETVCOMDETECT = 0xDB
SETDISPLAYCLOCKDIV = 0xD5
SETPRECHARGE = 0xD9
SETMULTIPLEX = 0xA8
SETLOWCOLUMN = 0x00
SETHIGHCOLUMN = 0x10
SETSTARTLINE = 0x40
MEMORYMODE = 0x20
COLUMNADDR = 0x21
PAGEADDR = 0x22
COMSCANINC = 0xC0
COMSCANDEC = 0xC8
SEGREMAP = 0xA0
CHARGEPUMP = 0x8D
ACTIVATE_SCROLL = 0x2F
DEACTIVATE_SCROLL = 0x2E
SET_VERTICAL_SCROLL_AREA = 0xA3
RIGHT_HORIZONTAL_SCROLL = 0x26
LEFT_HORIZONTAL_SCROLL = 0x27
VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29
VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A
EXTERNALVCC VccMode = 0x1
SWITCHCAPVCC VccMode = 0x2
)
+326
View File
@@ -0,0 +1,326 @@
// Package sh1106 implements a driver for the SH1106 display controller
//
// Copied from https://github.com/toyo/tinygo-sh1106 (under BSD 3-clause license)
package sh1106 // import "tinygo.org/x/drivers/sh1106"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
)
// Device wraps an SPI connection.
type Device struct {
bus Buser
buffer []byte
cmdbuf [1]byte
width int16
height int16
bufferSize int16
vccState VccMode
}
// Config is the configuration for the display
type Config struct {
Width int16
Height int16
VccState VccMode
Address uint16
}
type I2CBus struct {
wire drivers.I2C
Address uint16
}
type SPIBus struct {
wire drivers.SPI
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
}
type Buser interface {
configure()
tx(data []byte, isCommand bool)
setAddress(address uint16)
}
type VccMode uint8
// NewI2C creates a new SSD1306 connection. The I2C wire must already be configured.
func NewI2C(bus drivers.I2C) Device {
return Device{
bus: &I2CBus{
wire: bus,
Address: Address,
},
}
}
// NewSPI creates a new SSD1306 connection. The SPI wire must already be configured.
func NewSPI(bus drivers.SPI, dcPin, resetPin, csPin machine.Pin) Device {
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return Device{
bus: &SPIBus{
wire: bus,
dcPin: dcPin,
resetPin: resetPin,
csPin: csPin,
},
}
}
// Configure initializes the display with default configuration
func (d *Device) Configure(cfg Config) {
if cfg.Width != 0 {
d.width = cfg.Width
} else {
d.width = 128
}
if cfg.Height != 0 {
d.height = cfg.Height
} else {
d.height = 64
}
if cfg.Address != 0 {
d.bus.setAddress(cfg.Address)
}
if cfg.VccState != 0 {
d.vccState = cfg.VccState
} else {
d.vccState = SWITCHCAPVCC
}
d.bufferSize = d.width * d.height / 8
d.buffer = make([]byte, d.bufferSize)
d.bus.configure()
// busyWaitDelay(100 * time.Nanosecond)
time.Sleep(100 * time.Nanosecond)
d.Command(DISPLAYOFF)
d.Command(SETDISPLAYCLOCKDIV)
d.Command(0x80)
d.Command(SETMULTIPLEX)
d.Command(uint8(d.height - 1))
d.Command(SETDISPLAYOFFSET)
d.Command(0x0)
d.Command(SETSTARTLINE | 0x0)
d.Command(CHARGEPUMP)
if d.vccState == EXTERNALVCC {
d.Command(0x10)
} else {
d.Command(0x14)
}
d.Command(MEMORYMODE)
d.Command(0x00)
d.Command(SEGREMAP | 0x1)
d.Command(COMSCANDEC)
if (d.width == 128 && d.height == 64) || (d.width == 64 && d.height == 48) { // 128x64 or 64x48
d.Command(SETCOMPINS)
d.Command(0x12)
d.Command(SETCONTRAST)
if d.vccState == EXTERNALVCC {
d.Command(0x9F)
} else {
d.Command(0xCF)
}
} else if d.width == 128 && d.height == 32 { // 128x32
d.Command(SETCOMPINS)
d.Command(0x02)
d.Command(SETCONTRAST)
d.Command(0x8F)
} else if d.width == 96 && d.height == 16 { // 96x16
d.Command(SETCOMPINS)
d.Command(0x2)
d.Command(SETCONTRAST)
if d.vccState == EXTERNALVCC {
d.Command(0x10)
} else {
d.Command(0xAF)
}
} else {
// fail silently, it might work
println("there's no configuration for this display's size")
}
d.Command(SETPRECHARGE)
if d.vccState == EXTERNALVCC {
d.Command(0x22)
} else {
d.Command(0xF1)
}
d.Command(SETVCOMDETECT)
d.Command(0x40)
d.Command(DISPLAYALLON_RESUME)
d.Command(NORMALDISPLAY)
d.Command(DEACTIVATE_SCROLL)
d.Command(DISPLAYON)
}
// ClearBuffer clears the image buffer
func (d *Device) ClearBuffer() {
for i := int16(0); i < d.bufferSize; i++ {
d.buffer[i] = 0
}
}
// ClearDisplay clears the image buffer and clear the display
func (d *Device) ClearDisplay() {
d.ClearBuffer()
d.Display()
}
// Display sends the whole buffer to the screen
func (d *Device) Display() error {
// In the 128x64 (SPI) screen resetting to 0x0 after 128 times corrupt the buffer
// Since we're printing the whole buffer, avoid resetting it
if d.width != 128 || d.height != 64 {
d.Command(COLUMNADDR)
d.Command(0)
d.Command(uint8(d.width - 1))
d.Command(PAGEADDR)
d.Command(0)
d.Command(uint8(d.height/8) - 1)
}
for pg := uint8(0); pg < uint8(d.height/8); pg++ {
d.Command(0xB0 | (pg & 0x07)) // SET_PAGE_ADDR
d.Command(SETLOWCOLUMN | 2)
d.Command(SETHIGHCOLUMN | 0)
d.Tx(d.buffer[uint16(pg)*0x80:uint16(pg+1)*0x80], false)
}
return nil
}
// SetPixel enables or disables a pixel in the buffer
// color.RGBA{0, 0, 0, 255} is consider transparent, anything else
// with enable a pixel on the screen
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
if x < 0 || x >= d.width || y < 0 || y >= d.height {
return
}
byteIndex := x + (y/8)*d.width
if c.R != 0 || c.G != 0 || c.B != 0 {
d.buffer[byteIndex] |= 1 << uint8(y%8)
} else {
d.buffer[byteIndex] &^= 1 << uint8(y%8)
}
}
// GetPixel returns if the specified pixel is on (true) or off (false)
func (d *Device) GetPixel(x int16, y int16) bool {
if x < 0 || x >= d.width || y < 0 || y >= d.height {
return false
}
byteIndex := x + (y/8)*d.width
return (d.buffer[byteIndex] >> uint8(y%8) & 0x1) == 1
}
// SetBuffer changes the whole buffer at once
func (d *Device) SetBuffer(buffer []byte) error {
if int16(len(buffer)) != d.bufferSize {
//return ErrBuffer
return errors.New("wrong size buffer")
}
for i := int16(0); i < d.bufferSize; i++ {
d.buffer[i] = buffer[i]
}
return nil
}
func (d *Device) SetScroll(line int16) {
d.Command(SETSTARTLINE + uint8(line&0b111111))
}
// Command sends a command to the display
func (d *Device) Command(command uint8) {
d.cmdbuf[0] = command
d.bus.tx(d.cmdbuf[:], true)
}
// setAddress sets the address to the I2C bus
func (b *I2CBus) setAddress(address uint16) {
b.Address = address
}
// setAddress does nothing, but it's required to avoid reflection
func (b *SPIBus) setAddress(address uint16) {
// do nothing
println("trying to Configure an address on a SPI device")
}
// configure does nothing, but it's required to avoid reflection
func (b *I2CBus) configure() {}
// configure configures some pins with the SPI bus
func (b *SPIBus) configure() {
b.csPin.Low()
b.dcPin.Low()
b.resetPin.Low()
b.resetPin.High()
// busyWaitDelay(time.Millisecond)
time.Sleep(1 * time.Millisecond)
b.resetPin.Low()
// busyWaitDelay(10 * time.Millisecond)
time.Sleep(10 * time.Millisecond)
b.resetPin.High()
}
// Tx sends data to the display
func (d *Device) Tx(data []byte, isCommand bool) {
d.bus.tx(data, isCommand)
}
// tx sends data to the display (I2CBus implementation)
func (b *I2CBus) tx(data []byte, isCommand bool) {
if isCommand {
b.wire.WriteRegister(uint8(b.Address), 0x00, data)
} else {
b.wire.WriteRegister(uint8(b.Address), 0x40, data)
}
}
// tx sends data to the display (SPIBus implementation)
func (b *SPIBus) tx(data []byte, isCommand bool) {
if isCommand {
b.csPin.High()
riseTimeDelay()
b.dcPin.Low()
b.csPin.Low()
b.wire.Tx(data, nil)
b.csPin.High()
} else {
b.csPin.High()
riseTimeDelay()
b.dcPin.High()
b.csPin.Low()
b.wire.Tx(data, nil)
b.csPin.High()
}
}
// Size returns the current size of the display.
func (d *Device) Size() (w, h int16) {
return d.width, d.height
}
// TODO: is this really necessary? seems to work fine without this on macropad-rp2040 at least
func riseTimeDelay() {
busyWaitDelay(1 * time.Microsecond)
}
func busyWaitDelay(duration time.Duration) {
for start := time.Now(); time.Since(start) < duration; {
}
}
-1
View File
@@ -1,5 +1,4 @@
//go:build pybadge
// +build pybadge
package shifter
-1
View File
@@ -1,5 +1,4 @@
//go:build rp2040
// +build rp2040
package ssd1289
+36 -57
View File
@@ -206,48 +206,42 @@ const (
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_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_CMD_SET_PACKET_PARAMS
SX126X_GFSK_PREAMBLE_DETECT_OFF = 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
@@ -267,12 +261,6 @@ const (
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
@@ -323,13 +311,4 @@ const (
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
)
+2 -2
View File
@@ -1,5 +1,4 @@
//go:build stm32wlx
// +build stm32wlx
package sx126x
@@ -8,11 +7,12 @@ import (
"errors"
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/lora"
)
// New creates a new SX126x connection.
func New(spi drivers.SPI) *Device {
c := make(chan RadioEvent, 10)
c := make(chan lora.RadioEvent, 10)
d := Device{
spi: spi,
radioEventChan: c,
+96 -89
View File
@@ -7,7 +7,10 @@ import (
"errors"
"time"
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/lora"
)
// SX126X radio transceiver RF_IN and RF_OUT may be connected
@@ -30,22 +33,6 @@ const (
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
@@ -53,38 +40,20 @@ const (
// 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)
spi drivers.SPI // SPI bus for module communication
rstPin, csPin machine.Pin // GPIOs for reset and chip select
radioEventChan chan lora.RadioEvent // Channel for Receiving events
loraConf lora.Config // 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
// --------------------------------------------------
@@ -100,14 +69,8 @@ func timeoutMsToRtcSteps(timeoutMs uint32) uint32 {
// 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 {
func (d *Device) GetRadioEventChan() chan lora.RadioEvent {
return d.radioEventChan
}
@@ -126,6 +89,13 @@ func (d *Device) SetRfSwitch(rfswitch RFSwitch) {
// Operational modes functions
// --------------------------------------------------
func (d *Device) Reset() {
d.rstPin.Low()
time.Sleep(100 * time.Millisecond)
d.rstPin.High()
time.Sleep(100 * time.Millisecond)
}
// DetectDevice() tries to detect the radio module by changing SyncWord value
func (d *Device) DetectDevice() bool {
bak := d.GetSyncWord()
@@ -163,7 +133,7 @@ func (d *Device) SetTxContinuousWave() {
}
// 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
// Take care to initialize all Lora settings like it's done in Tx before calling this function
// If you don't init properly all the settings, it'll fail
func (d *Device) SetTxContinuousPreamble() {
if d.rfswitch != nil {
@@ -387,11 +357,11 @@ func (d *Device) SetPacketType(packetType uint8) {
}
// SetSyncWord defines the Sync Word to yse
func (d *Device) SetSyncWord(syncword uint16) {
func (d *Device) SetSyncWord(sw uint16) {
var p [2]uint8
d.loraConf.SyncWord = syncword
p[0] = uint8((syncword >> 8) & 0xFF)
p[1] = uint8((syncword >> 0) & 0xFF)
d.loraConf.SyncWord = sw
p[0] = uint8((d.loraConf.SyncWord >> 8) & 0xFF)
p[1] = uint8((d.loraConf.SyncWord >> 0) & 0xFF)
d.WriteRegister(SX126X_REG_LORA_SYNC_WORD_MSB, p[:])
}
@@ -402,8 +372,8 @@ func (d *Device) GetSyncWord() uint16 {
return r
}
// SetLoraPublicNetwork sets Sync Word to 0x3444 (Public) or 0x1424 (Private)
func (d *Device) SetLoraPublicNetwork(enable bool) {
// SetPublicNetwork sets Sync Word to 0x3444 (Public) or 0x1424 (Private)
func (d *Device) SetPublicNetwork(enable bool) {
if enable {
d.SetSyncWord(SX126X_LORA_MAC_PUBLIC_SYNCWORD)
} else {
@@ -537,47 +507,47 @@ func (d *Device) ExecGetCommand(cmd uint8, size uint8) []uint8 {
// Configuration
//
// SetLoraFrequency() Sets current Lora Frequency
// SetFrequency() Sets current Lora Frequency
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraFrequency(freq uint32) {
func (d *Device) SetFrequency(freq uint32) {
d.loraConf.Freq = d.loraConf.Freq
}
// SetLoraIqMode() defines the current IQ Mode (Standard/Inverted)
// SetIqMode() defines the current IQ Mode (Standard/Inverted)
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraIqMode(mode uint8) {
func (d *Device) SetIqMode(mode uint8) {
if mode == 0 {
d.loraConf.Iq = SX126X_LORA_IQ_STANDARD
d.loraConf.Iq = lora.IQStandard
} else {
d.loraConf.Iq = SX126X_LORA_IQ_INVERTED
d.loraConf.Iq = lora.IQInverted
}
}
// SetLoraCodingRate() sets current Lora Coding Rate
// SetCodingRate() sets current Lora Coding Rate
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraCodingRate(cr uint8) {
func (d *Device) SetCodingRate(cr uint8) {
d.loraConf.Cr = cr
}
// SetLoraBandwidth() sets current Lora Bandwidth
// SetBandwidth() sets current Lora Bandwidth
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraBandwidth(bw uint8) {
func (d *Device) SetBandwidth(bw uint8) {
d.loraConf.Cr = bw
}
// SetLoraCrc() sets current CRC mode (ON/OFF)
// SetCrc() sets current CRC mode (ON/OFF)
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraCrc(enable bool) {
func (d *Device) SetCrc(enable bool) {
if enable {
d.loraConf.Crc = SX126X_LORA_CRC_ON
d.loraConf.Crc = lora.CRCOn
} else {
d.loraConf.Crc = SX126X_LORA_CRC_OFF
d.loraConf.Crc = lora.CRCOn
}
}
// SetLoraSpreadingFactor setc surrent Lora Spreading Factor
// SetSpreadingFactor setc surrent Lora Spreading Factor
// NB: Change will be applied at next RX / TX
func (d *Device) SetLoraSpreadingFactor(sf uint8) {
func (d *Device) SetSpreadingFactor(sf uint8) {
d.loraConf.Sf = sf
}
@@ -587,9 +557,10 @@ func (d *Device) SetLoraSpreadingFactor(sf uint8) {
//
// LoraConfig() defines Lora configuration for next Lora operations
func (d *Device) LoraConfig(cnf LoraConfig) {
func (d *Device) LoraConfig(cnf lora.Config) {
// Save given configuration
d.loraConf = cnf
d.loraConf.SyncWord = syncword(int(cnf.SyncWord))
// Switch to standby prior to configuration changes
d.SetStandby()
// Clear errors, disable radio interrupts for the moment
@@ -599,24 +570,25 @@ func (d *Device) LoraConfig(cnf LoraConfig) {
// 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.SetModulationParams(d.loraConf.Sf, bandwidth(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 {
// Tx sends a lora packet, (with timeout)
func (d *Device) Tx(pkt []uint8, timeoutMs uint32) error {
if d.loraConf.Freq == 0 {
return errUndefinedLoraConf
return lora.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()
@@ -625,45 +597,46 @@ func (d *Device) LoraTx(pkt []uint8, timeoutMs uint32) error {
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.SetModulationParams(d.loraConf.Sf, bandwidth(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 {
if msg.EventType != lora.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) {
func (d *Device) Rx(timeoutMs uint32) ([]uint8, error) {
if d.loraConf.Freq == 0 {
return nil, errUndefinedLoraConf
return nil, lora.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.SetModulationParams(d.loraConf.Sf, bandwidth(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 {
if msg.EventType == lora.RadioEventTimeout {
return nil, nil
} else if msg.EventType != RadioEventRxDone {
} else if msg.EventType != lora.RadioEventRxDone {
return nil, errors.New("Unexpected Radio Event while RX")
}
@@ -683,19 +656,53 @@ func (d *Device) HandleInterrupt() {
rChan := d.GetRadioEventChan()
if (st & SX126X_IRQ_RX_DONE) > 0 {
rChan <- NewRadioEvent(RadioEventRxDone, st, nil)
rChan <- lora.NewRadioEvent(lora.RadioEventRxDone, st, nil)
}
if (st & SX126X_IRQ_TX_DONE) > 0 {
rChan <- NewRadioEvent(RadioEventTxDone, st, nil)
rChan <- lora.NewRadioEvent(lora.RadioEventTxDone, st, nil)
}
if (st & SX126X_IRQ_TIMEOUT) > 0 {
rChan <- NewRadioEvent(RadioEventTimeout, st, nil)
rChan <- lora.NewRadioEvent(lora.RadioEventTimeout, st, nil)
}
if (st & SX126X_IRQ_CRC_ERR) > 0 {
rChan <- NewRadioEvent(RadioEventCrcError, st, nil)
rChan <- lora.NewRadioEvent(lora.RadioEventCrcError, st, nil)
}
}
func bandwidth(bw uint8) uint8 {
switch bw {
case lora.Bandwidth_7_8:
return SX126X_LORA_BW_7_8
case lora.Bandwidth_10_4:
return SX126X_LORA_BW_10_4
case lora.Bandwidth_15_6:
return SX126X_LORA_BW_15_6
case lora.Bandwidth_20_8:
return SX126X_LORA_BW_20_8
case lora.Bandwidth_31_25:
return SX126X_LORA_BW_31_25
case lora.Bandwidth_41_7:
return SX126X_LORA_BW_41_7
case lora.Bandwidth_62_5:
return SX126X_LORA_BW_62_5
case lora.Bandwidth_125_0:
return SX126X_LORA_BW_125_0
case lora.Bandwidth_250_0:
return SX126X_LORA_BW_250_0
case lora.Bandwidth_500_0:
return SX126X_LORA_BW_500_0
default:
return 0
}
}
func syncword(sw int) uint16 {
if sw == lora.SyncPublic {
return SX126X_LORA_MAC_PUBLIC_SYNCWORD
}
return SX126X_LORA_MAC_PRIVATE_SYNCWORD
}

Some files were not shown because too many files have changed in this diff Show More