mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-18 13:43:58 +00:00
Lorawan uplink support and new lorawan 'basic-demo' example
This commit is contained in:
committed by
Ron Evans
parent
301e6bc35b
commit
889536f7f0
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
"tinygo.org/x/drivers/lora/lorawan"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ func quicktest() {
|
|||||||
|
|
||||||
// Check firmware version.
|
// Check firmware version.
|
||||||
func version() {
|
func version() {
|
||||||
writeCommandOutput("VER", currentVersion()+" ("+firmwareVersion()+")")
|
writeCommandOutput("VER", common.CurrentVersion()+" ("+common.FirmwareVersion()+")")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use to check the ID of the LoRaWAN module, or change the ID.
|
// Use to check the ID of the LoRaWAN module, or change the ID.
|
||||||
@@ -443,7 +444,7 @@ func sendhex(data string) error {
|
|||||||
func recv(setting string) error {
|
func recv(setting string) error {
|
||||||
cmd := "RECV"
|
cmd := "RECV"
|
||||||
|
|
||||||
data, err := lorarx()
|
data, err := common.Lorarx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeCommandOutput(cmd, "ERROR "+err.Error())
|
writeCommandOutput(cmd, "ERROR "+err.Error())
|
||||||
return err
|
return err
|
||||||
@@ -456,7 +457,7 @@ func recv(setting string) error {
|
|||||||
func recvhex(setting string) error {
|
func recvhex(setting string) error {
|
||||||
cmd := "RECVHEX"
|
cmd := "RECVHEX"
|
||||||
|
|
||||||
data, err := lorarx()
|
data, err := common.Lorarx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeCommandOutput(cmd, "ERROR "+err.Error())
|
writeCommandOutput(cmd, "ERROR "+err.Error())
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"machine"
|
"machine"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
||||||
"tinygo.org/x/drivers/lora"
|
"tinygo.org/x/drivers/lora"
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
"tinygo.org/x/drivers/lora/lorawan"
|
||||||
)
|
)
|
||||||
@@ -34,7 +35,7 @@ func main() {
|
|||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
radio, err = setupLora()
|
radio, err = common.SetupLora()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fail(err.Error())
|
fail(err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
const VERSION = "0.0.1"
|
|
||||||
|
|
||||||
func currentVersion() string {
|
|
||||||
return VERSION
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Simple Lorawan example
|
||||||
|
|
||||||
|
This demo code will connect Lorawan network and send sample uplink message
|
||||||
|
|
||||||
|
You may change your Lorawan keys (AppEUI, DevEUI, AppKEY) in key-default.go
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
$ tinygo monitor
|
||||||
|
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
|
||||||
|
Lorawan Simple Demo
|
||||||
|
Start Lorawan Join sequence
|
||||||
|
loraConnect: Connected !
|
||||||
|
```
|
||||||
|
|
||||||
|
# Building
|
||||||
|
|
||||||
|
## Simulator
|
||||||
|
|
||||||
|
```
|
||||||
|
tinygo flash -target pico ./examples/lora/lorawan/basic-demo
|
||||||
|
```
|
||||||
|
|
||||||
|
## PyBadge with LoRa Featherwing
|
||||||
|
|
||||||
|
```
|
||||||
|
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/basic-demo
|
||||||
|
```
|
||||||
|
|
||||||
|
## LoRa-E5
|
||||||
|
|
||||||
|
```
|
||||||
|
tinygo flash -target lorae5 ./examples/lora/lorawan/basic-demo
|
||||||
|
```
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
//go:build !customkeys
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// These are sample keys, so the example builds
|
||||||
|
// Either change here, or create a new go file and use customkeys build tag
|
||||||
|
func setLorawanKeys() {
|
||||||
|
otaa.SetAppEUI([]uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
otaa.SetDevEUI([]uint8{0xB3, 0xD5, 0x41, 0x00, 0x0A, 0xF1, 0xA4, 0x45})
|
||||||
|
otaa.SetAppKey([]uint8{0x12, 0x22, 0xA3, 0xFF, 0x0C, 0x7B, 0x76, 0x7B, 0x8F, 0xD3, 0x12, 0x4F, 0xCE, 0x7A, 0x32, 0x16})
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// Simple code for connecting to Lorawan network and uploading sample payload
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
||||||
|
"tinygo.org/x/drivers/lora"
|
||||||
|
"tinygo.org/x/drivers/lora/lorawan"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LORAWAN_JOIN_TIMEOUT_SEC = 180
|
||||||
|
LORAWAN_RECONNECT_DELAY_SEC = 15
|
||||||
|
LORAWAN_UPLINK_DELAY_SEC = 60
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
radio lora.Radio
|
||||||
|
session *lorawan.Session
|
||||||
|
otaa *lorawan.Otaa
|
||||||
|
)
|
||||||
|
|
||||||
|
func loraConnect() error {
|
||||||
|
start := time.Now()
|
||||||
|
var err error
|
||||||
|
for time.Since(start) < LORAWAN_JOIN_TIMEOUT_SEC*time.Second {
|
||||||
|
println("Trying to join network")
|
||||||
|
err = lorawan.Join(otaa, session)
|
||||||
|
if err == nil {
|
||||||
|
println("Connected to network !")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
println("Join error:", err, "retrying in", LORAWAN_RECONNECT_DELAY_SEC, "sec")
|
||||||
|
time.Sleep(time.Second * LORAWAN_RECONNECT_DELAY_SEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = errors.New("Unable to join Lorawan network")
|
||||||
|
println(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func failMessage(err error) {
|
||||||
|
println("FATAL:", err)
|
||||||
|
for {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("*** Lorawan basic join and uplink demo ***")
|
||||||
|
|
||||||
|
// Board specific Lorawan initialization
|
||||||
|
var err error
|
||||||
|
radio, err = common.SetupLora()
|
||||||
|
if err != nil {
|
||||||
|
failMessage(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for LoraWan operations
|
||||||
|
session = &lorawan.Session{}
|
||||||
|
otaa = &lorawan.Otaa{}
|
||||||
|
|
||||||
|
// Initial Lora modulation configuration
|
||||||
|
loraConf := lora.Config{
|
||||||
|
Freq: 868100000,
|
||||||
|
Bw: lora.Bandwidth_125_0,
|
||||||
|
Sf: lora.SpreadingFactor9,
|
||||||
|
Cr: lora.CodingRate4_7,
|
||||||
|
HeaderType: lora.HeaderExplicit,
|
||||||
|
Preamble: 12,
|
||||||
|
Ldr: lora.LowDataRateOptimizeOff,
|
||||||
|
Iq: lora.IQStandard,
|
||||||
|
Crc: lora.CRCOn,
|
||||||
|
SyncWord: lora.SyncPublic,
|
||||||
|
LoraTxPowerDBm: 20,
|
||||||
|
}
|
||||||
|
radio.LoraConfig(loraConf)
|
||||||
|
|
||||||
|
// Connect the lorawan with the Lora Radio device.
|
||||||
|
lorawan.UseRadio(radio)
|
||||||
|
|
||||||
|
// Configure AppEUI, DevEUI, APPKey
|
||||||
|
setLorawanKeys()
|
||||||
|
|
||||||
|
// Try to connect Lorawan network
|
||||||
|
if err := loraConnect(); err != nil {
|
||||||
|
failMessage(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to periodicaly send an uplink sample message
|
||||||
|
upCount := 1
|
||||||
|
for {
|
||||||
|
payload := "Hello TinyGo #" + strconv.Itoa(upCount)
|
||||||
|
|
||||||
|
if err := lorawan.SendUplink([]byte(payload), session); err != nil {
|
||||||
|
println("Uplink error:", err)
|
||||||
|
} else {
|
||||||
|
println("Uplink success, msg=", payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Sleeping for", LORAWAN_UPLINK_DELAY_SEC, "sec")
|
||||||
|
time.Sleep(time.Second * LORAWAN_UPLINK_DELAY_SEC)
|
||||||
|
upCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
//go:build !featherwing && !gnse && !lorae5 && !nucleowl55jc
|
//go:build !featherwing && !gnse && !lorae5 && !nucleowl55jc
|
||||||
|
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import "tinygo.org/x/drivers/lora"
|
import "tinygo.org/x/drivers/lora"
|
||||||
|
|
||||||
// do simulator setup here
|
// do simulator setup here
|
||||||
func setupLora() (lora.Radio, error) {
|
func SetupLora() (lora.Radio, error) {
|
||||||
return &SimLoraRadio{}, nil
|
return &SimLoraRadio{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,11 +29,12 @@ func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
|||||||
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
||||||
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
||||||
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
||||||
|
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
||||||
|
|
||||||
func firmwareVersion() string {
|
func FirmwareVersion() string {
|
||||||
return "simulator " + currentVersion()
|
return "simulator " + CurrentVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
func lorarx() ([]byte, error) {
|
func Lorarx() ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build gnse || lorae5 || nucleowl55jc
|
//go:build gnse || lorae5 || nucleowl55jc
|
||||||
|
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
@@ -24,7 +24,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// do sx126x setup here
|
// do sx126x setup here
|
||||||
func setupLora() (lora.Radio, error) {
|
func SetupLora() (lora.Radio, error) {
|
||||||
loraRadio = sx126x.New(machine.SPI3)
|
loraRadio = sx126x.New(machine.SPI3)
|
||||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
||||||
|
|
||||||
@@ -64,10 +64,10 @@ func radioIntHandler(intr interrupt.Interrupt) {
|
|||||||
loraRadio.HandleInterrupt()
|
loraRadio.HandleInterrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
func firmwareVersion() string {
|
func FirmwareVersion() string {
|
||||||
return "sx126x"
|
return "sx126x"
|
||||||
}
|
}
|
||||||
|
|
||||||
func lorarx() ([]byte, error) {
|
func Lorarx() ([]byte, error) {
|
||||||
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build featherwing
|
//go:build featherwing
|
||||||
|
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -28,7 +28,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// do sx127x setup here
|
// do sx127x setup here
|
||||||
func setupLora() (lora.Radio, error) {
|
func SetupLora() (lora.Radio, error) {
|
||||||
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
dio0Pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
dio0Pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
@@ -75,11 +75,11 @@ func dioIrqHandler(machine.Pin) {
|
|||||||
loraRadio.HandleInterrupt()
|
loraRadio.HandleInterrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
func firmwareVersion() string {
|
func FirmwareVersion() string {
|
||||||
v := loraRadio.GetVersion()
|
v := loraRadio.GetVersion()
|
||||||
return "sx127x v" + strconv.Itoa(int(v))
|
return "sx127x v" + strconv.Itoa(int(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func lorarx() ([]byte, error) {
|
func Lorarx() ([]byte, error) {
|
||||||
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
const VERSION = "0.0.1"
|
||||||
|
|
||||||
|
func CurrentVersion() string {
|
||||||
|
return VERSION
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
| RX | HIGH | LOW | HIGH |
|
| RX | HIGH | LOW | HIGH |
|
||||||
+-----------+----------+-----------+------------+
|
+-----------+----------+-----------+------------+
|
||||||
*/
|
*/
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
"machine"
|
||||||
+11
-1
@@ -71,7 +71,17 @@ func Join(otaa *Otaa, session *Session) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendUplink() error {
|
func SendUplink(data []uint8, session *Session) error {
|
||||||
|
payload, err := session.GenMessage(0, []byte(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ActiveRadio.SetCrc(true)
|
||||||
|
ActiveRadio.SetIqMode(0) // IQ Standard
|
||||||
|
ActiveRadio.Tx(payload, LORA_RXTX_TIMEOUT)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func (o *Otaa) GenerateJoinRequest() ([]uint8, error) {
|
|||||||
o.buf = append(o.buf, 0x00)
|
o.buf = append(o.buf, 0x00)
|
||||||
o.buf = append(o.buf, reverseBytes(o.AppEUI[:])...)
|
o.buf = append(o.buf, reverseBytes(o.AppEUI[:])...)
|
||||||
o.buf = append(o.buf, reverseBytes(o.DevEUI[:])...)
|
o.buf = append(o.buf, reverseBytes(o.DevEUI[:])...)
|
||||||
o.buf = append(o.buf, reverseBytes(o.DevNonce[:])...)
|
o.buf = append(o.buf, o.DevNonce[:]...)
|
||||||
mic := genPayloadMIC(o.buf, o.AppKey)
|
mic := genPayloadMIC(o.buf, o.AppKey)
|
||||||
o.buf = append(o.buf, mic[:]...)
|
o.buf = append(o.buf, mic[:]...)
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ type Radio interface {
|
|||||||
SetBandwidth(bw uint8)
|
SetBandwidth(bw uint8)
|
||||||
SetCrc(enable bool)
|
SetCrc(enable bool)
|
||||||
SetSpreadingFactor(sf uint8)
|
SetSpreadingFactor(sf uint8)
|
||||||
|
LoraConfig(cnf Config)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user