diff --git a/examples/lora/lorawan/atcmd/commands.go b/examples/lora/lorawan/atcmd/commands.go index 3584b68..0d79a3e 100644 --- a/examples/lora/lorawan/atcmd/commands.go +++ b/examples/lora/lorawan/atcmd/commands.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "strings" + "tinygo.org/x/drivers/examples/lora/lorawan/common" "tinygo.org/x/drivers/lora/lorawan" ) @@ -14,7 +15,7 @@ func quicktest() { // Check firmware 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. @@ -443,7 +444,7 @@ func sendhex(data string) error { func recv(setting string) error { cmd := "RECV" - data, err := lorarx() + data, err := common.Lorarx() if err != nil { writeCommandOutput(cmd, "ERROR "+err.Error()) return err @@ -456,7 +457,7 @@ func recv(setting string) error { func recvhex(setting string) error { cmd := "RECVHEX" - data, err := lorarx() + data, err := common.Lorarx() if err != nil { writeCommandOutput(cmd, "ERROR "+err.Error()) return err diff --git a/examples/lora/lorawan/atcmd/main.go b/examples/lora/lorawan/atcmd/main.go index cb0535e..1d8f12e 100644 --- a/examples/lora/lorawan/atcmd/main.go +++ b/examples/lora/lorawan/atcmd/main.go @@ -12,6 +12,7 @@ import ( "machine" "time" + "tinygo.org/x/drivers/examples/lora/lorawan/common" "tinygo.org/x/drivers/lora" "tinygo.org/x/drivers/lora/lorawan" ) @@ -34,7 +35,7 @@ func main() { uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) var err error - radio, err = setupLora() + radio, err = common.SetupLora() if err != nil { fail(err.Error()) } diff --git a/examples/lora/lorawan/atcmd/version.go b/examples/lora/lorawan/atcmd/version.go deleted file mode 100644 index d6c882f..0000000 --- a/examples/lora/lorawan/atcmd/version.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -const VERSION = "0.0.1" - -func currentVersion() string { - return VERSION -} diff --git a/examples/lora/lorawan/basic-demo/README.md b/examples/lora/lorawan/basic-demo/README.md new file mode 100644 index 0000000..0191d66 --- /dev/null +++ b/examples/lora/lorawan/basic-demo/README.md @@ -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 +``` + diff --git a/examples/lora/lorawan/basic-demo/keys-default.go b/examples/lora/lorawan/basic-demo/keys-default.go new file mode 100644 index 0000000..8728c85 --- /dev/null +++ b/examples/lora/lorawan/basic-demo/keys-default.go @@ -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}) +} diff --git a/examples/lora/lorawan/basic-demo/main.go b/examples/lora/lorawan/basic-demo/main.go new file mode 100644 index 0000000..1e755ec --- /dev/null +++ b/examples/lora/lorawan/basic-demo/main.go @@ -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++ + } +} diff --git a/examples/lora/lorawan/atcmd/radio.go b/examples/lora/lorawan/common/radio.go similarity index 89% rename from examples/lora/lorawan/atcmd/radio.go rename to examples/lora/lorawan/common/radio.go index 92b37eb..f970a27 100644 --- a/examples/lora/lorawan/atcmd/radio.go +++ b/examples/lora/lorawan/common/radio.go @@ -1,4 +1,4 @@ -package main +package common import ( "errors" diff --git a/examples/lora/lorawan/atcmd/sim.go b/examples/lora/lorawan/common/sim.go similarity index 77% rename from examples/lora/lorawan/atcmd/sim.go rename to examples/lora/lorawan/common/sim.go index 7006d97..43db446 100644 --- a/examples/lora/lorawan/atcmd/sim.go +++ b/examples/lora/lorawan/common/sim.go @@ -1,11 +1,11 @@ //go:build !featherwing && !gnse && !lorae5 && !nucleowl55jc -package main +package common import "tinygo.org/x/drivers/lora" // do simulator setup here -func setupLora() (lora.Radio, error) { +func SetupLora() (lora.Radio, error) { return &SimLoraRadio{}, nil } @@ -29,11 +29,12 @@ func (sr *SimLoraRadio) SetCodingRate(cr uint8) {} func (sr *SimLoraRadio) SetBandwidth(bw uint8) {} func (sr *SimLoraRadio) SetCrc(enable bool) {} func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {} +func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {} -func firmwareVersion() string { - return "simulator " + currentVersion() +func FirmwareVersion() string { + return "simulator " + CurrentVersion() } -func lorarx() ([]byte, error) { +func Lorarx() ([]byte, error) { return nil, nil } diff --git a/examples/lora/lorawan/atcmd/sx126x.go b/examples/lora/lorawan/common/sx126x.go similarity index 92% rename from examples/lora/lorawan/atcmd/sx126x.go rename to examples/lora/lorawan/common/sx126x.go index abccdd8..01c78c5 100644 --- a/examples/lora/lorawan/atcmd/sx126x.go +++ b/examples/lora/lorawan/common/sx126x.go @@ -1,6 +1,6 @@ //go:build gnse || lorae5 || nucleowl55jc -package main +package common import ( "device/stm32" @@ -24,7 +24,7 @@ var ( ) // do sx126x setup here -func setupLora() (lora.Radio, error) { +func SetupLora() (lora.Radio, error) { loraRadio = sx126x.New(machine.SPI3) loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262) @@ -64,10 +64,10 @@ func radioIntHandler(intr interrupt.Interrupt) { loraRadio.HandleInterrupt() } -func firmwareVersion() string { +func FirmwareVersion() string { return "sx126x" } -func lorarx() ([]byte, error) { +func Lorarx() ([]byte, error) { return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS) } diff --git a/examples/lora/lorawan/atcmd/sx127x.go b/examples/lora/lorawan/common/sx127x.go similarity index 94% rename from examples/lora/lorawan/atcmd/sx127x.go rename to examples/lora/lorawan/common/sx127x.go index 79018c6..322ee1c 100644 --- a/examples/lora/lorawan/atcmd/sx127x.go +++ b/examples/lora/lorawan/common/sx127x.go @@ -1,6 +1,6 @@ //go:build featherwing -package main +package common import ( "strconv" @@ -28,7 +28,7 @@ var ( ) // do sx127x setup here -func setupLora() (lora.Radio, error) { +func SetupLora() (lora.Radio, error) { rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) csPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) dio0Pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) @@ -75,11 +75,11 @@ func dioIrqHandler(machine.Pin) { loraRadio.HandleInterrupt() } -func firmwareVersion() string { +func FirmwareVersion() string { v := loraRadio.GetVersion() return "sx127x v" + strconv.Itoa(int(v)) } -func lorarx() ([]byte, error) { +func Lorarx() ([]byte, error) { return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS) } diff --git a/examples/lora/lorawan/common/version.go b/examples/lora/lorawan/common/version.go new file mode 100644 index 0000000..6dc9720 --- /dev/null +++ b/examples/lora/lorawan/common/version.go @@ -0,0 +1,7 @@ +package common + +const VERSION = "0.0.1" + +func CurrentVersion() string { + return VERSION +} diff --git a/examples/lora/lorawan/atcmd/wl55jc.go b/examples/lora/lorawan/common/wl55jc.go similarity index 98% rename from examples/lora/lorawan/atcmd/wl55jc.go rename to examples/lora/lorawan/common/wl55jc.go index 8b2738a..c4b32cd 100644 --- a/examples/lora/lorawan/atcmd/wl55jc.go +++ b/examples/lora/lorawan/common/wl55jc.go @@ -13,7 +13,7 @@ | RX | HIGH | LOW | HIGH | +-----------+----------+-----------+------------+ */ -package main +package common import ( "machine" diff --git a/lora/lorawan/adaptor.go b/lora/lorawan/adaptor.go index 7236e0e..97ef08f 100644 --- a/lora/lorawan/adaptor.go +++ b/lora/lorawan/adaptor.go @@ -71,7 +71,17 @@ func Join(otaa *Otaa, session *Session) error { 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 } diff --git a/lora/lorawan/otaa.go b/lora/lorawan/otaa.go index f3d5574..a851bde 100644 --- a/lora/lorawan/otaa.go +++ b/lora/lorawan/otaa.go @@ -87,7 +87,7 @@ func (o *Otaa) GenerateJoinRequest() ([]uint8, error) { o.buf = append(o.buf, 0x00) o.buf = append(o.buf, reverseBytes(o.AppEUI[:])...) 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) o.buf = append(o.buf, mic[:]...) diff --git a/lora/radio.go b/lora/radio.go index edf64e6..b23e352 100644 --- a/lora/radio.go +++ b/lora/radio.go @@ -10,4 +10,5 @@ type Radio interface { SetBandwidth(bw uint8) SetCrc(enable bool) SetSpreadingFactor(sf uint8) + LoraConfig(cnf Config) }