diff --git a/examples/lora/lorawan/atcmd/README.md b/examples/lora/lorawan/atcmd/README.md index af028c196..31f936e70 100644 --- a/examples/lora/lorawan/atcmd/README.md +++ b/examples/lora/lorawan/atcmd/README.md @@ -23,20 +23,20 @@ Builds/flashes atcmd console application with simulator instead of actual LoRa r tinygo flash -target pico ./examples/lora/lorawan/atcmd/ ``` -## PyBadge with LoRa Featherwing +## PyBadge with LoRa Featherwing for EU868 region Builds/flashes atcmd console application on PyBadge using LoRa Featherwing (RFM95/SX1276). ``` -tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/atcmd/ +tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/atcmd/ ``` -## LoRa-E5 +## LoRa-E5 for US915 region Builds/flashes atcmd console application on Lora-E5 using onboard SX126x. ``` -tinygo flash -target lorae5 ./examples/lora/lorawan/atcmd/ +tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/atcmd/ ``` ## Joining a Public Lorawan Network diff --git a/examples/lora/lorawan/atcmd/main.go b/examples/lora/lorawan/atcmd/main.go index 5b013de52..2b84ff599 100644 --- a/examples/lora/lorawan/atcmd/main.go +++ b/examples/lora/lorawan/atcmd/main.go @@ -32,6 +32,8 @@ var ( defaultTimeout uint32 = 1000 ) +var reg string + func main() { uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) @@ -45,7 +47,16 @@ func main() { otaa = &lorawan.Otaa{} lorawan.UseRadio(radio) - lorawan.UseRegionSettings(region.EU868()) + switch reg { + case "AU915": + lorawan.UseRegionSettings(region.AU915()) + case "EU868": + lorawan.UseRegionSettings(region.EU868()) + case "US915": + lorawan.UseRegionSettings(region.US915()) + default: + lorawan.UseRegionSettings(region.EU868()) + } for { if uart.Buffered() > 0 { diff --git a/examples/lora/lorawan/basic-demo/README.md b/examples/lora/lorawan/basic-demo/README.md index 866f9c8bb..3bf62e455 100644 --- a/examples/lora/lorawan/basic-demo/README.md +++ b/examples/lora/lorawan/basic-demo/README.md @@ -21,16 +21,16 @@ loraConnect: Connected ! tinygo flash -target pico ./examples/lora/lorawan/basic-demo ``` -## PyBadge with LoRa Featherwing +## PyBadge with LoRa Featherwing for EU868 region ``` -tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/basic-demo +tinygo flash -target pybadge -tags featherwing -ldflags="-X main.reg=EU868" ./examples/lora/lorawan/basic-demo ``` -## LoRa-E5 +## LoRa-E5 for US915 region ``` -tinygo flash -target lorae5 ./examples/lora/lorawan/basic-demo +tinygo flash -target lorae5 -ldflags="-X main.reg=US915" ./examples/lora/lorawan/basic-demo ``` diff --git a/examples/lora/lorawan/basic-demo/main.go b/examples/lora/lorawan/basic-demo/main.go index b42a16ac2..e845f50b9 100644 --- a/examples/lora/lorawan/basic-demo/main.go +++ b/examples/lora/lorawan/basic-demo/main.go @@ -12,7 +12,10 @@ import ( "tinygo.org/x/drivers/lora/lorawan/region" ) -var debug string +var ( + reg string + debug string +) const ( LORAWAN_JOIN_TIMEOUT_SEC = 180 @@ -67,8 +70,16 @@ func main() { // Connect the lorawan with the Lora Radio device. lorawan.UseRadio(radio) - - lorawan.UseRegionSettings(region.EU868()) + switch reg { + case "AU915": + lorawan.UseRegionSettings(region.AU915()) + case "EU868": + lorawan.UseRegionSettings(region.EU868()) + case "US915": + lorawan.UseRegionSettings(region.US915()) + default: + lorawan.UseRegionSettings(region.EU868()) + } // Configure AppEUI, DevEUI, APPKey, and public/private Lorawan Network setLorawanKeys() diff --git a/examples/lora/lorawan/common/sim.go b/examples/lora/lorawan/common/sim.go index 14c919fdc..7f70f5cde 100644 --- a/examples/lora/lorawan/common/sim.go +++ b/examples/lora/lorawan/common/sim.go @@ -23,13 +23,18 @@ func (sr *SimLoraRadio) Rx(timeoutMs uint32) ([]uint8, error) { return nil, nil } -func (sr *SimLoraRadio) SetFrequency(freq uint32) {} -func (sr *SimLoraRadio) SetIqMode(mode uint8) {} -func (sr *SimLoraRadio) SetCodingRate(cr uint8) {} -func (sr *SimLoraRadio) SetBandwidth(bw uint8) {} -func (sr *SimLoraRadio) SetCrc(enable bool) {} -func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {} -func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {} +func (sr *SimLoraRadio) SetFrequency(freq uint32) {} +func (sr *SimLoraRadio) SetIqMode(mode uint8) {} +func (sr *SimLoraRadio) SetCodingRate(cr uint8) {} +func (sr *SimLoraRadio) SetBandwidth(bw uint8) {} +func (sr *SimLoraRadio) SetCrc(enable bool) {} +func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {} +func (sr *SimLoraRadio) SetHeaderType(headerType uint8) {} +func (sr *SimLoraRadio) SetPreambleLength(pLen uint16) {} +func (sr *SimLoraRadio) SetPublicNetwork(enabled bool) {} +func (sr *SimLoraRadio) SetSyncWord(syncWord uint16) {} +func (sr *SimLoraRadio) SetTxPower(txPower int8) {} +func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {} func FirmwareVersion() string { return "simulator " + CurrentVersion() diff --git a/lora/config.go b/lora/config.go index 84e77bb69..dd61dc1d7 100644 --- a/lora/config.go +++ b/lora/config.go @@ -80,6 +80,9 @@ const ( const ( MHz_868_1 = 868100000 MHz_868_5 = 868500000 + MHz_902_3 = 902300000 + Mhz_903_0 = 903000000 + MHZ_915_0 = 915000000 MHz_916_8 = 916800000 MHz_923_3 = 923300000 ) diff --git a/lora/lorawan/adaptor.go b/lora/lorawan/adaptor.go index 803b403fd..382a559c4 100644 --- a/lora/lorawan/adaptor.go +++ b/lora/lorawan/adaptor.go @@ -30,11 +30,11 @@ const ( var ( ActiveRadio lora.Radio Retries = 15 - regionSettings region.RegionSettings + regionSettings region.Settings ) // UseRegionSettings sets current Lorawan Regional parameters -func UseRegionSettings(rs region.RegionSettings) { +func UseRegionSettings(rs region.Settings) { regionSettings = rs } @@ -52,13 +52,13 @@ func SetPublicNetwork(enabled bool) { } // ApplyChannelConfig sets current Lora modulation according to current regional settings -func applyChannelConfig(ch *region.Channel) { - ActiveRadio.SetFrequency(ch.Frequency) - ActiveRadio.SetBandwidth(ch.Bandwidth) - ActiveRadio.SetCodingRate(ch.CodingRate) - ActiveRadio.SetSpreadingFactor(ch.SpreadingFactor) - ActiveRadio.SetPreambleLength(ch.PreambleLength) - ActiveRadio.SetTxPower(ch.TxPowerDBm) +func applyChannelConfig(ch region.Channel) { + ActiveRadio.SetFrequency(ch.Frequency()) + ActiveRadio.SetBandwidth(ch.Bandwidth()) + ActiveRadio.SetCodingRate(ch.CodingRate()) + ActiveRadio.SetSpreadingFactor(ch.SpreadingFactor()) + ActiveRadio.SetPreambleLength(ch.PreambleLength()) + ActiveRadio.SetTxPower(ch.TxPowerDBm()) // Lorawan defaults to explicit headers ActiveRadio.SetHeaderType(lora.HeaderExplicit) ActiveRadio.SetCrc(true) @@ -84,24 +84,30 @@ func Join(otaa *Otaa, session *Session) error { return err } - // Prepare radio for Join Tx - applyChannelConfig(regionSettings.JoinRequestChannel()) - ActiveRadio.SetIqMode(lora.IQStandard) - ActiveRadio.Tx(payload, LORA_TX_TIMEOUT) - if err != nil { - return err - } - - // Wait for JoinAccept - applyChannelConfig(regionSettings.JoinAcceptChannel()) - ActiveRadio.SetIqMode(lora.IQInverted) - resp, err = ActiveRadio.Rx(LORA_RX_TIMEOUT) - if err != nil { - return err - } - - if resp == nil { - return ErrNoJoinAcceptReceived + for { + joinRequestChannel := regionSettings.JoinRequestChannel() + joinAcceptChannel := regionSettings.JoinAcceptChannel() + + // Prepare radio for Join Tx + applyChannelConfig(joinRequestChannel) + ActiveRadio.SetIqMode(lora.IQStandard) + ActiveRadio.Tx(payload, LORA_TX_TIMEOUT) + if err != nil { + return err + } + + // Wait for JoinAccept + if joinAcceptChannel.Frequency() != 0 { + applyChannelConfig(joinAcceptChannel) + } + ActiveRadio.SetIqMode(lora.IQInverted) + resp, err = ActiveRadio.Rx(LORA_RX_TIMEOUT) + if err == nil && resp != nil { + break + } + if !joinAcceptChannel.Next() { + return ErrNoJoinAcceptReceived + } } err = otaa.DecodeJoinAccept(resp, session) diff --git a/lora/lorawan/region/au915.go b/lora/lorawan/region/au915.go index 7a4a4c158..03c41494b 100644 --- a/lora/lorawan/region/au915.go +++ b/lora/lorawan/region/au915.go @@ -7,43 +7,41 @@ const ( AU915_DEFAULT_TX_POWER_DBM = 20 ) -type RegionSettingsAU915 struct { - joinRequestChannel *Channel - joinAcceptChannel *Channel - uplinkChannel *Channel +type ChannelAU struct { + channel } -func AU915() *RegionSettingsAU915 { - return &RegionSettingsAU915{ - joinRequestChannel: &Channel{lora.MHz_916_8, +func (c *ChannelAU) Next() bool { + return false +} + +type SettingsAU915 struct { + settings +} + +func AU915() *SettingsAU915 { + return &SettingsAU915{settings: settings{ + joinRequestChannel: &ChannelAU{channel: channel{lora.MHz_916_8, lora.Bandwidth_125_0, lora.SpreadingFactor9, lora.CodingRate4_5, AU915_DEFAULT_PREAMBLE_LEN, - AU915_DEFAULT_TX_POWER_DBM}, - joinAcceptChannel: &Channel{lora.MHz_923_3, + AU915_DEFAULT_TX_POWER_DBM}}, + joinAcceptChannel: &ChannelAU{channel: channel{lora.MHz_923_3, lora.Bandwidth_500_0, lora.SpreadingFactor9, lora.CodingRate4_5, AU915_DEFAULT_PREAMBLE_LEN, - AU915_DEFAULT_TX_POWER_DBM}, - uplinkChannel: &Channel{lora.MHz_916_8, + AU915_DEFAULT_TX_POWER_DBM}}, + uplinkChannel: &ChannelAU{channel: channel{lora.MHz_916_8, lora.Bandwidth_125_0, lora.SpreadingFactor9, lora.CodingRate4_5, AU915_DEFAULT_PREAMBLE_LEN, - AU915_DEFAULT_TX_POWER_DBM}, - } -} - -func (r *RegionSettingsAU915) JoinRequestChannel() *Channel { - return r.joinRequestChannel -} - -func (r *RegionSettingsAU915) JoinAcceptChannel() *Channel { - return r.joinAcceptChannel + AU915_DEFAULT_TX_POWER_DBM}}, + }} } -func (r *RegionSettingsAU915) UplinkChannel() *Channel { - return r.uplinkChannel +func Next(c *ChannelAU) bool { + return false } diff --git a/lora/lorawan/region/channel.go b/lora/lorawan/region/channel.go new file mode 100644 index 000000000..b0e65262a --- /dev/null +++ b/lora/lorawan/region/channel.go @@ -0,0 +1,42 @@ +package region + +type Channel interface { + Next() bool + Frequency() uint32 + Bandwidth() uint8 + SpreadingFactor() uint8 + CodingRate() uint8 + PreambleLength() uint16 + TxPowerDBm() int8 + SetFrequency(v uint32) + SetBandwidth(v uint8) + SetSpreadingFactor(v uint8) + SetCodingRate(v uint8) + SetPreambleLength(v uint16) + SetTxPowerDBm(v int8) +} + +type channel struct { + frequency uint32 + bandwidth uint8 + spreadingFactor uint8 + codingRate uint8 + preambleLength uint16 + txPowerDBm int8 +} + +// Getter functions +func (c *channel) Frequency() uint32 { return c.frequency } +func (c *channel) Bandwidth() uint8 { return c.bandwidth } +func (c *channel) SpreadingFactor() uint8 { return c.spreadingFactor } +func (c *channel) CodingRate() uint8 { return c.codingRate } +func (c *channel) PreambleLength() uint16 { return c.preambleLength } +func (c *channel) TxPowerDBm() int8 { return c.txPowerDBm } + +// Set functions +func (c *channel) SetFrequency(v uint32) { c.frequency = v } +func (c *channel) SetBandwidth(v uint8) { c.bandwidth = v } +func (c *channel) SetSpreadingFactor(v uint8) { c.spreadingFactor = v } +func (c *channel) SetCodingRate(v uint8) { c.codingRate = v } +func (c *channel) SetPreambleLength(v uint16) { c.preambleLength = v } +func (c *channel) SetTxPowerDBm(v int8) { c.txPowerDBm = v } diff --git a/lora/lorawan/region/eu868.go b/lora/lorawan/region/eu868.go index f4790806e..7eed1f44d 100644 --- a/lora/lorawan/region/eu868.go +++ b/lora/lorawan/region/eu868.go @@ -7,43 +7,37 @@ const ( EU868_DEFAULT_TX_POWER_DBM = 20 ) -type RegionSettingsEU868 struct { - joinRequestChannel *Channel - joinAcceptChannel *Channel - uplinkChannel *Channel +type ChannelEU struct { + channel } -func EU868() *RegionSettingsEU868 { - return &RegionSettingsEU868{ - joinRequestChannel: &Channel{lora.MHz_868_1, +func (c *ChannelEU) Next() bool { + return false +} + +type SettingsEU868 struct { + settings +} + +func EU868() *SettingsEU868 { + return &SettingsEU868{settings: settings{ + joinRequestChannel: &ChannelEU{channel: channel{lora.MHz_868_1, lora.Bandwidth_125_0, lora.SpreadingFactor9, lora.CodingRate4_7, EU868_DEFAULT_PREAMBLE_LEN, - EU868_DEFAULT_TX_POWER_DBM}, - joinAcceptChannel: &Channel{lora.MHz_868_1, + EU868_DEFAULT_TX_POWER_DBM}}, + joinAcceptChannel: &ChannelEU{channel: channel{lora.MHz_868_1, lora.Bandwidth_125_0, lora.SpreadingFactor9, lora.CodingRate4_7, EU868_DEFAULT_PREAMBLE_LEN, - EU868_DEFAULT_TX_POWER_DBM}, - uplinkChannel: &Channel{lora.MHz_868_1, + EU868_DEFAULT_TX_POWER_DBM}}, + uplinkChannel: &ChannelEU{channel: channel{lora.MHz_868_1, lora.Bandwidth_125_0, lora.SpreadingFactor9, lora.CodingRate4_7, EU868_DEFAULT_PREAMBLE_LEN, - EU868_DEFAULT_TX_POWER_DBM}, - } -} - -func (r *RegionSettingsEU868) JoinRequestChannel() *Channel { - return r.joinRequestChannel -} - -func (r *RegionSettingsEU868) JoinAcceptChannel() *Channel { - return r.joinAcceptChannel -} - -func (r *RegionSettingsEU868) UplinkChannel() *Channel { - return r.uplinkChannel + EU868_DEFAULT_TX_POWER_DBM}}, + }} } diff --git a/lora/lorawan/region/regionset.go b/lora/lorawan/region/regionset.go deleted file mode 100644 index 981d63ece..000000000 --- a/lora/lorawan/region/regionset.go +++ /dev/null @@ -1,16 +0,0 @@ -package region - -type Channel struct { - Frequency uint32 - Bandwidth uint8 - SpreadingFactor uint8 - CodingRate uint8 - PreambleLength uint16 - TxPowerDBm int8 -} - -type RegionSettings interface { - JoinRequestChannel() *Channel - JoinAcceptChannel() *Channel - UplinkChannel() *Channel -} diff --git a/lora/lorawan/region/settings.go b/lora/lorawan/region/settings.go new file mode 100644 index 000000000..e015c0014 --- /dev/null +++ b/lora/lorawan/region/settings.go @@ -0,0 +1,25 @@ +package region + +type Settings interface { + JoinRequestChannel() Channel + JoinAcceptChannel() Channel + UplinkChannel() Channel +} + +type settings struct { + joinRequestChannel Channel + joinAcceptChannel Channel + uplinkChannel Channel +} + +func (r *settings) JoinRequestChannel() Channel { + return r.joinRequestChannel +} + +func (r *settings) JoinAcceptChannel() Channel { + return r.joinAcceptChannel +} + +func (r *settings) UplinkChannel() Channel { + return r.uplinkChannel +} diff --git a/lora/lorawan/region/us915.go b/lora/lorawan/region/us915.go new file mode 100644 index 000000000..4149b5b46 --- /dev/null +++ b/lora/lorawan/region/us915.go @@ -0,0 +1,82 @@ +package region + +import "tinygo.org/x/drivers/lora" + +const ( + US915_DEFAULT_PREAMBLE_LEN = 8 + US915_DEFAULT_TX_POWER_DBM = 20 + US915_FREQUENCY_INCREMENT_DR_0 = 200000 // only for 125 kHz Bandwidth + US915_FREQUENCY_INCREMENT_DR_4 = 1600000 // only for 500 kHz Bandwidth +) + +type ChannelUS struct { + channel +} + +func (c *ChannelUS) Next() bool { + switch c.Bandwidth() { + case lora.Bandwidth_125_0: + freq, ok := stepFrequency125(c.frequency) + if ok { + c.frequency = freq + } else { + c.frequency = lora.Mhz_903_0 + c.bandwidth = lora.Bandwidth_500_0 + } + case lora.Bandwidth_500_0: + freq, ok := stepFrequency500(c.frequency) + if ok { + c.frequency = freq + } else { + // there are no more frequencies to check after sweeping all 8 500 kHz channels + return false + } + } + + return true +} + +func stepFrequency125(freq uint32) (uint32, bool) { + f := freq + US915_FREQUENCY_INCREMENT_DR_0 + if f >= lora.MHZ_915_0 { + return 0, false + } + + return f, true +} + +func stepFrequency500(freq uint32) (uint32, bool) { + f := freq + US915_FREQUENCY_INCREMENT_DR_4 + if f >= lora.MHZ_915_0 { + return 0, false + } + + return f, true +} + +type SettingsUS915 struct { + settings +} + +func US915() *SettingsUS915 { + return &SettingsUS915{settings: settings{ + joinRequestChannel: &ChannelUS{channel: channel{lora.MHz_902_3, + lora.Bandwidth_125_0, + lora.SpreadingFactor10, + lora.CodingRate4_5, + US915_DEFAULT_PREAMBLE_LEN, + US915_DEFAULT_TX_POWER_DBM}}, + joinAcceptChannel: &ChannelUS{channel: channel{0, + lora.Bandwidth_500_0, + lora.SpreadingFactor9, + lora.CodingRate4_5, + US915_DEFAULT_PREAMBLE_LEN, + US915_DEFAULT_TX_POWER_DBM}}, + uplinkChannel: &ChannelUS{channel: channel{lora.Mhz_903_0, + lora.Bandwidth_500_0, + lora.SpreadingFactor9, + lora.CodingRate4_5, + US915_DEFAULT_PREAMBLE_LEN, + US915_DEFAULT_TX_POWER_DBM}}, + }} +}