Compare commits
5 Commits
5c0c9d0a93
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 76cf8af4a5 | |||
| f0f9262ba5 | |||
| c980d14d9f | |||
| 755ecf3829 | |||
| c24e49c0e1 |
@@ -1,3 +0,0 @@
|
|||||||
module esp32s3lockup
|
|
||||||
|
|
||||||
go 1.26.2
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
|
|
||||||
led := machine.GPIO37
|
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
|
|
||||||
txDone := true
|
|
||||||
count := 0
|
|
||||||
|
|
||||||
processingCount := 0
|
|
||||||
for {
|
|
||||||
if txDone {
|
|
||||||
txDone = false
|
|
||||||
led.Set(false)
|
|
||||||
time.Sleep(249 * time.Millisecond)
|
|
||||||
led.Set(true)
|
|
||||||
println("hello world", count)
|
|
||||||
count += 1
|
|
||||||
} else {
|
|
||||||
if processingCount > 100000000 {
|
|
||||||
txDone = true
|
|
||||||
println("stall done")
|
|
||||||
processingCount = 0
|
|
||||||
}
|
|
||||||
processingCount += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ module lilygot3s3
|
|||||||
go 1.26.2
|
go 1.26.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/jwetzell/osc-go v0.3.0
|
|
||||||
tinygo.org/x/drivers v0.35.0
|
tinygo.org/x/drivers v0.35.0
|
||||||
tinygo.org/x/espradio v0.1.0
|
tinygo.org/x/espradio v0.1.0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/jwetzell/osc-go v0.3.0 h1:z75TxuQSEmdcmZ56OAepkDa3m88SdZh//3m4nBb/XZI=
|
|
||||||
github.com/jwetzell/osc-go v0.3.0/go.mod h1:kCs329JxY6Qjga08tRQ/Gl0PqhgQzLIMpOhm6uszvIc=
|
|
||||||
github.com/soypat/lneto v0.1.1-0.20260425023453-aa77403a2b32 h1:4fNa4mcNPVTMJ3Kzn+cS/LqmpXhKM9SiZ9Vgu/Ucq3c=
|
github.com/soypat/lneto v0.1.1-0.20260425023453-aa77403a2b32 h1:4fNa4mcNPVTMJ3Kzn+cS/LqmpXhKM9SiZ9Vgu/Ucq3c=
|
||||||
github.com/soypat/lneto v0.1.1-0.20260425023453-aa77403a2b32/go.mod h1:Be5PjwoYukvHFiUXxpYi8+ppH2F/gw/vjGBvFdv+Ti8=
|
github.com/soypat/lneto v0.1.1-0.20260425023453-aa77403a2b32/go.mod h1:Be5PjwoYukvHFiUXxpYi8+ppH2F/gw/vjGBvFdv+Ti8=
|
||||||
|
|||||||
@@ -19,6 +19,21 @@ var (
|
|||||||
password string
|
password string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type LoRaConfig struct {
|
||||||
|
Frequency uint32
|
||||||
|
Power int8
|
||||||
|
RadioRamp sx128x.RadioRampTime
|
||||||
|
RegulatorMode sx128x.RegulatorMode
|
||||||
|
SpreadingFactor sx128x.LoRaSpreadingFactor
|
||||||
|
Bandwidth sx128x.LoRaBandwidth
|
||||||
|
CodingRate sx128x.LoRaCodingRate
|
||||||
|
PreambleLength uint32
|
||||||
|
HeaderType sx128x.LoRaHeaderType
|
||||||
|
CrcType sx128x.LoRaCrcType
|
||||||
|
IqType sx128x.LoRaIqType
|
||||||
|
SyncWord uint16
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
@@ -84,60 +99,73 @@ func main() {
|
|||||||
timeout := atomic.Bool{}
|
timeout := atomic.Bool{}
|
||||||
timeout.Store(true)
|
timeout.Store(true)
|
||||||
|
|
||||||
dio1Pin.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
dio1Interrupt := atomic.Bool{}
|
||||||
irqStatus, _ := radio.GetIrqStatus()
|
dio1Interrupt.Store(false)
|
||||||
println("irq status:", irqStatus)
|
|
||||||
|
|
||||||
if irqStatus&sx128x.IRQ_TX_DONE_MASK != 0 {
|
dio1Pin.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
||||||
txDone.Store(true)
|
dio1Interrupt.Store(true)
|
||||||
timeout.Store(false)
|
|
||||||
led.Set(false)
|
|
||||||
}
|
|
||||||
if irqStatus&sx128x.IRQ_RX_DONE_MASK != 0 {
|
|
||||||
rxDone.Store(true)
|
|
||||||
timeout.Store(false)
|
|
||||||
led.Set(true)
|
|
||||||
println("rx done")
|
|
||||||
}
|
|
||||||
if irqStatus&sx128x.IRQ_RX_TX_TIMEOUT_MASK != 0 {
|
|
||||||
timeout.Store(true)
|
|
||||||
txDone.Store(true)
|
|
||||||
rxDone.Store(true)
|
|
||||||
println("rx/tx timeout")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
loraConfig := lora.Config{
|
loraConfig := LoRaConfig{
|
||||||
Freq: 2400000000,
|
Frequency: 2400000000, // 2.4Ghz
|
||||||
Bw: lora.Bandwidth_1625_0,
|
Power: 13, // dBm
|
||||||
Sf: lora.SpreadingFactor9,
|
RadioRamp: sx128x.RADIO_RAMP_02_US, // 2 microsecond ramp time
|
||||||
Cr: lora.CodingRate4_7,
|
RegulatorMode: sx128x.REGULATOR_DC_DC,
|
||||||
HeaderType: sx128x.LORA_EXPLICIT_HEADER,
|
|
||||||
Preamble: 12,
|
SpreadingFactor: sx128x.LORA_SF_9,
|
||||||
Ldr: lora.LowDataRateOptimizeOff,
|
Bandwidth: sx128x.LORA_BW_1600,
|
||||||
Iq: sx128x.LORA_IQ_STD,
|
CodingRate: sx128x.LORA_CR_4_7,
|
||||||
Crc: sx128x.LORA_CRC_DISABLE,
|
PreambleLength: 12,
|
||||||
SyncWord: 0x1424,
|
HeaderType: sx128x.LORA_HEADER_EXPLICIT,
|
||||||
LoraTxPowerDBm: 13,
|
CrcType: sx128x.LORA_CRC_DISABLE,
|
||||||
|
IqType: sx128x.LORA_IQ_STD,
|
||||||
|
SyncWord: 0x1424, // the default private sync word
|
||||||
}
|
}
|
||||||
|
|
||||||
radio.WaitWhileBusy()
|
radio.WaitWhileBusy(time.Second)
|
||||||
SetupLora(radio, loraConfig)
|
SetupLora(radio, loraConfig)
|
||||||
println("radio initialized, waiting for messages...")
|
println("radio initialized, waiting for messages...")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
|
|
||||||
|
if dio1Interrupt.Load() {
|
||||||
|
// println("DIO1 interrupt triggered")
|
||||||
|
irqStatus, _ := radio.GetIrqStatus()
|
||||||
|
println("irq status:", irqStatus)
|
||||||
|
|
||||||
|
if irqStatus&sx128x.IRQ_TX_DONE_MASK != 0 {
|
||||||
|
txDone.Store(true)
|
||||||
|
timeout.Store(false)
|
||||||
|
led.Set(false)
|
||||||
|
}
|
||||||
|
if irqStatus&sx128x.IRQ_RX_DONE_MASK != 0 {
|
||||||
|
rxDone.Store(true)
|
||||||
|
timeout.Store(false)
|
||||||
|
led.Set(true)
|
||||||
|
println("rx done")
|
||||||
|
}
|
||||||
|
if irqStatus&sx128x.IRQ_RX_TX_TIMEOUT_MASK != 0 {
|
||||||
|
timeout.Store(true)
|
||||||
|
txDone.Store(true)
|
||||||
|
rxDone.Store(true)
|
||||||
|
println("rx/tx timeout")
|
||||||
|
}
|
||||||
|
dio1Interrupt.Store(false)
|
||||||
|
}
|
||||||
|
|
||||||
if rxDone.Load() {
|
if rxDone.Load() {
|
||||||
rxDone.Store(false)
|
rxDone.Store(false)
|
||||||
if !timeout.Load() {
|
if !timeout.Load() {
|
||||||
rxLength, rxPointer, _ := radio.GetRxBufferStatus()
|
rxLength, rxPointer, _ := radio.GetRxBufferStatus()
|
||||||
rxData, _ := radio.ReadBuffer(rxPointer, rxLength)
|
rxData, _ := radio.ReadBuffer(rxPointer, rxLength)
|
||||||
num, err := conn.Write(rxData)
|
// num, err := conn.Write(rxData)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
println("failed to send OSC message:", err)
|
// println("failed to send OSC message:", err)
|
||||||
} else {
|
// } else {
|
||||||
println("sent", num, "bytes to broker")
|
// println("sent", num, "bytes to broker")
|
||||||
}
|
// }
|
||||||
|
println("received message:", string(rxData))
|
||||||
|
|
||||||
led.Set(false)
|
led.Set(false)
|
||||||
}
|
}
|
||||||
@@ -167,7 +195,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupLora(radio *sx128x.Device, config lora.Config) {
|
func SetupLora(radio *sx128x.Device, config LoRaConfig) {
|
||||||
// Switch to standby prior to configuration changes
|
// Switch to standby prior to configuration changes
|
||||||
|
|
||||||
circuitMode, _, _ := radio.GetStatus()
|
circuitMode, _, _ := radio.GetStatus()
|
||||||
@@ -176,16 +204,16 @@ func SetupLora(radio *sx128x.Device, config lora.Config) {
|
|||||||
}
|
}
|
||||||
// Clear errors, disable radio interrupts for the moment
|
// Clear errors, disable radio interrupts for the moment
|
||||||
radio.SetPacketType(sx128x.PACKET_TYPE_LORA)
|
radio.SetPacketType(sx128x.PACKET_TYPE_LORA)
|
||||||
radio.SetCadParams(sx128x.LORA_CAD_08_SYMBOLS)
|
radio.SetCadParams(uint8(sx128x.LORA_CAD_08_SYMBOLS))
|
||||||
radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC)
|
radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC)
|
||||||
|
|
||||||
radio.SetRfFrequency(config.Freq)
|
radio.SetRfFrequency(config.Frequency)
|
||||||
radio.SetModulationParams(spreadingFactor(config.Sf), bandwidth(config.Bw), codingRate(config.Cr))
|
radio.SetModulationParamsLoRa(config.SpreadingFactor, config.Bandwidth, config.CodingRate)
|
||||||
|
|
||||||
data := [1]uint8{}
|
data := [1]uint8{}
|
||||||
if config.Sf == lora.SpreadingFactor5 || config.Sf == lora.SpreadingFactor6 {
|
if config.SpreadingFactor == lora.SpreadingFactor5 || config.SpreadingFactor == lora.SpreadingFactor6 {
|
||||||
data[0] = 0x1E
|
data[0] = 0x1E
|
||||||
} else if config.Sf == lora.SpreadingFactor7 || config.Sf == lora.SpreadingFactor8 {
|
} else if config.SpreadingFactor == lora.SpreadingFactor7 || config.SpreadingFactor == lora.SpreadingFactor8 {
|
||||||
data[0] = 0x37
|
data[0] = 0x37
|
||||||
} else {
|
} else {
|
||||||
data[0] = 0x32
|
data[0] = 0x32
|
||||||
@@ -195,8 +223,8 @@ func SetupLora(radio *sx128x.Device, config lora.Config) {
|
|||||||
data[0] = existing | 0x01
|
data[0] = existing | 0x01
|
||||||
radio.WriteRegister(0x93C, data[:])
|
radio.WriteRegister(0x93C, data[:])
|
||||||
|
|
||||||
radio.SetTxParams(config.LoraTxPowerDBm, sx128x.RADIO_RAMP_02_US)
|
radio.SetTxParams(config.Power, sx128x.RADIO_RAMP_02_US)
|
||||||
radio.SetPacketParamsLoRa(uint32(config.Preamble), config.HeaderType, 0xFF, config.Crc, config.Iq)
|
radio.SetPacketParamsLoRa(config.PreambleLength, config.HeaderType, 0xFF, config.CrcType, config.IqType)
|
||||||
var syncWord [2]uint8
|
var syncWord [2]uint8
|
||||||
syncWord[0] = uint8(config.SyncWord >> 8)
|
syncWord[0] = uint8(config.SyncWord >> 8)
|
||||||
syncWord[1] = uint8(config.SyncWord & 0x00FF)
|
syncWord[1] = uint8(config.SyncWord & 0x00FF)
|
||||||
@@ -214,7 +242,7 @@ func checkStatus(radio *sx128x.Device, operation string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Rx(radio *sx128x.Device, loraConfig lora.Config) {
|
func Rx(radio *sx128x.Device, loraConfig LoRaConfig) {
|
||||||
radio.SetStandby(sx128x.STANDBY_XOSC)
|
radio.SetStandby(sx128x.STANDBY_XOSC)
|
||||||
radio.SetBufferBaseAddress(0, 0)
|
radio.SetBufferBaseAddress(0, 0)
|
||||||
radio.SetDioIrqParams(sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
radio.SetDioIrqParams(sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
||||||
@@ -224,56 +252,3 @@ func Rx(radio *sx128x.Device, loraConfig lora.Config) {
|
|||||||
println("failed to set RX mode:", err)
|
println("failed to set RX mode:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func codingRate(cr uint8) uint8 {
|
|
||||||
switch cr {
|
|
||||||
case lora.CodingRate4_5:
|
|
||||||
return sx128x.LORA_CR_4_5
|
|
||||||
case lora.CodingRate4_6:
|
|
||||||
return sx128x.LORA_CR_4_6
|
|
||||||
case lora.CodingRate4_7:
|
|
||||||
return sx128x.LORA_CR_4_7
|
|
||||||
case lora.CodingRate4_8:
|
|
||||||
return sx128x.LORA_CR_4_8
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func spreadingFactor(sf uint8) uint8 {
|
|
||||||
switch sf {
|
|
||||||
case lora.SpreadingFactor5:
|
|
||||||
return sx128x.LORA_SF_5
|
|
||||||
case lora.SpreadingFactor6:
|
|
||||||
return sx128x.LORA_SF_6
|
|
||||||
case lora.SpreadingFactor7:
|
|
||||||
return sx128x.LORA_SF_7
|
|
||||||
case lora.SpreadingFactor8:
|
|
||||||
return sx128x.LORA_SF_8
|
|
||||||
case lora.SpreadingFactor9:
|
|
||||||
return sx128x.LORA_SF_9
|
|
||||||
case lora.SpreadingFactor10:
|
|
||||||
return sx128x.LORA_SF_10
|
|
||||||
case lora.SpreadingFactor11:
|
|
||||||
return sx128x.LORA_SF_11
|
|
||||||
case lora.SpreadingFactor12:
|
|
||||||
return sx128x.LORA_SF_12
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func bandwidth(bw uint8) uint8 {
|
|
||||||
switch bw {
|
|
||||||
case lora.Bandwidth_1625_0:
|
|
||||||
return sx128x.LORA_BW_1600
|
|
||||||
case lora.Bandwidth_812_5:
|
|
||||||
return sx128x.LORA_BW_800
|
|
||||||
case lora.Bandwidth_406_25:
|
|
||||||
return sx128x.LORA_BW_400
|
|
||||||
case lora.Bandwidth_203_125:
|
|
||||||
return sx128x.LORA_BW_200
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+67
-97
@@ -7,10 +7,24 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jwetzell/osc-go"
|
"github.com/jwetzell/osc-go"
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/sx128x"
|
"tinygo.org/x/drivers/sx128x"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type LoRaConfig struct {
|
||||||
|
Frequency uint32
|
||||||
|
Power int8
|
||||||
|
RadioRamp sx128x.RadioRampTime
|
||||||
|
RegulatorMode sx128x.RegulatorMode
|
||||||
|
SpreadingFactor sx128x.LoRaSpreadingFactor
|
||||||
|
Bandwidth sx128x.LoRaBandwidth
|
||||||
|
CodingRate sx128x.LoRaCodingRate
|
||||||
|
PreambleLength uint32
|
||||||
|
HeaderType sx128x.LoRaHeaderType
|
||||||
|
CrcType sx128x.LoRaCrcType
|
||||||
|
IqType sx128x.LoRaIqType
|
||||||
|
SyncWord uint16
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
@@ -65,42 +79,30 @@ func main() {
|
|||||||
timeout := atomic.Bool{}
|
timeout := atomic.Bool{}
|
||||||
timeout.Store(true)
|
timeout.Store(true)
|
||||||
|
|
||||||
dio1Pin.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
dio1Interrupt := atomic.Bool{}
|
||||||
irqStatus, _ := radio.GetIrqStatus()
|
dio1Interrupt.Store(false)
|
||||||
|
|
||||||
if irqStatus&sx128x.IRQ_TX_DONE_MASK != 0 {
|
dio1Pin.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
||||||
txDone.Store(true)
|
dio1Interrupt.Store(true)
|
||||||
timeout.Store(false)
|
|
||||||
led.Set(false)
|
|
||||||
println("tx done")
|
|
||||||
}
|
|
||||||
if irqStatus&sx128x.IRQ_RX_DONE_MASK != 0 {
|
|
||||||
rxDone.Store(true)
|
|
||||||
timeout.Store(false)
|
|
||||||
led.Set(true)
|
|
||||||
}
|
|
||||||
if irqStatus&sx128x.IRQ_RX_TX_TIMEOUT_MASK != 0 {
|
|
||||||
timeout.Store(true)
|
|
||||||
txDone.Store(true)
|
|
||||||
rxDone.Store(true)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
loraConfig := lora.Config{
|
loraConfig := LoRaConfig{
|
||||||
Freq: 2400000000,
|
Frequency: 2400000000, // 2.4Ghz
|
||||||
Bw: lora.Bandwidth_1625_0,
|
Power: 13, // dBm
|
||||||
Sf: lora.SpreadingFactor9,
|
RadioRamp: sx128x.RADIO_RAMP_02_US, // 2 microsecond ramp time
|
||||||
Cr: lora.CodingRate4_7,
|
RegulatorMode: sx128x.REGULATOR_DC_DC,
|
||||||
HeaderType: sx128x.LORA_EXPLICIT_HEADER,
|
|
||||||
Preamble: 12,
|
SpreadingFactor: sx128x.LORA_SF_9,
|
||||||
Ldr: lora.LowDataRateOptimizeOff,
|
Bandwidth: sx128x.LORA_BW_1600,
|
||||||
Iq: sx128x.LORA_IQ_STD,
|
CodingRate: sx128x.LORA_CR_4_7,
|
||||||
Crc: sx128x.LORA_CRC_DISABLE,
|
PreambleLength: 12,
|
||||||
SyncWord: 0x1424,
|
HeaderType: sx128x.LORA_HEADER_EXPLICIT,
|
||||||
LoraTxPowerDBm: 13,
|
CrcType: sx128x.LORA_CRC_DISABLE,
|
||||||
|
IqType: sx128x.LORA_IQ_STD,
|
||||||
|
SyncWord: 0x1424, // the default private sync word
|
||||||
}
|
}
|
||||||
|
|
||||||
radio.WaitWhileBusy()
|
radio.WaitWhileBusy(time.Second)
|
||||||
SetupLora(radio, loraConfig)
|
SetupLora(radio, loraConfig)
|
||||||
|
|
||||||
oscMessage := osc.OSCMessage{
|
oscMessage := osc.OSCMessage{
|
||||||
@@ -109,6 +111,27 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
if dio1Interrupt.Load() {
|
||||||
|
irqStatus, _ := radio.GetIrqStatus()
|
||||||
|
|
||||||
|
if irqStatus&sx128x.IRQ_TX_DONE_MASK != 0 {
|
||||||
|
txDone.Store(true)
|
||||||
|
timeout.Store(false)
|
||||||
|
led.Set(false)
|
||||||
|
println("tx done")
|
||||||
|
}
|
||||||
|
if irqStatus&sx128x.IRQ_RX_DONE_MASK != 0 {
|
||||||
|
rxDone.Store(true)
|
||||||
|
timeout.Store(false)
|
||||||
|
led.Set(true)
|
||||||
|
}
|
||||||
|
if irqStatus&sx128x.IRQ_RX_TX_TIMEOUT_MASK != 0 {
|
||||||
|
timeout.Store(true)
|
||||||
|
txDone.Store(true)
|
||||||
|
rxDone.Store(true)
|
||||||
|
}
|
||||||
|
dio1Interrupt.Store(false)
|
||||||
|
}
|
||||||
if txDone.Load() && buttonPressed.Load() {
|
if txDone.Load() && buttonPressed.Load() {
|
||||||
txDone.Store(false)
|
txDone.Store(false)
|
||||||
buttonPressed.Store(false)
|
buttonPressed.Store(false)
|
||||||
@@ -155,7 +178,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupLora(radio *sx128x.Device, config lora.Config) {
|
func SetupLora(radio *sx128x.Device, config LoRaConfig) {
|
||||||
// Switch to standby prior to configuration changes
|
// Switch to standby prior to configuration changes
|
||||||
|
|
||||||
circuitMode, _, _ := radio.GetStatus()
|
circuitMode, _, _ := radio.GetStatus()
|
||||||
@@ -164,16 +187,16 @@ func SetupLora(radio *sx128x.Device, config lora.Config) {
|
|||||||
}
|
}
|
||||||
// Clear errors, disable radio interrupts for the moment
|
// Clear errors, disable radio interrupts for the moment
|
||||||
radio.SetPacketType(sx128x.PACKET_TYPE_LORA)
|
radio.SetPacketType(sx128x.PACKET_TYPE_LORA)
|
||||||
radio.SetCadParams(sx128x.LORA_CAD_08_SYMBOLS)
|
radio.SetCadParams(uint8(sx128x.LORA_CAD_08_SYMBOLS))
|
||||||
radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC)
|
radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC)
|
||||||
|
|
||||||
radio.SetRfFrequency(config.Freq)
|
radio.SetRfFrequency(config.Frequency)
|
||||||
radio.SetModulationParams(spreadingFactor(config.Sf), bandwidth(config.Bw), codingRate(config.Cr))
|
radio.SetModulationParamsLoRa(config.SpreadingFactor, config.Bandwidth, config.CodingRate)
|
||||||
|
|
||||||
data := [1]uint8{}
|
data := [1]uint8{}
|
||||||
if config.Sf == lora.SpreadingFactor5 || config.Sf == lora.SpreadingFactor6 {
|
if config.SpreadingFactor == sx128x.LORA_SF_5 || config.SpreadingFactor == sx128x.LORA_SF_6 {
|
||||||
data[0] = 0x1E
|
data[0] = 0x1E
|
||||||
} else if config.Sf == lora.SpreadingFactor7 || config.Sf == lora.SpreadingFactor8 {
|
} else if config.SpreadingFactor == sx128x.LORA_SF_7 || config.SpreadingFactor == sx128x.LORA_SF_8 {
|
||||||
data[0] = 0x37
|
data[0] = 0x37
|
||||||
} else {
|
} else {
|
||||||
data[0] = 0x32
|
data[0] = 0x32
|
||||||
@@ -183,8 +206,8 @@ func SetupLora(radio *sx128x.Device, config lora.Config) {
|
|||||||
data[0] = existing | 0x01
|
data[0] = existing | 0x01
|
||||||
radio.WriteRegister(0x93C, data[:])
|
radio.WriteRegister(0x93C, data[:])
|
||||||
|
|
||||||
radio.SetTxParams(config.LoraTxPowerDBm, sx128x.RADIO_RAMP_02_US)
|
radio.SetTxParams(config.Power, sx128x.RADIO_RAMP_02_US)
|
||||||
radio.SetPacketParamsLoRa(uint32(config.Preamble), config.HeaderType, 0xFF, config.Crc, config.Iq)
|
radio.SetPacketParamsLoRa(config.PreambleLength, config.HeaderType, 0xFF, config.CrcType, config.IqType)
|
||||||
var syncWord [2]uint8
|
var syncWord [2]uint8
|
||||||
syncWord[0] = uint8(config.SyncWord >> 8)
|
syncWord[0] = uint8(config.SyncWord >> 8)
|
||||||
syncWord[1] = uint8(config.SyncWord & 0x00FF)
|
syncWord[1] = uint8(config.SyncWord & 0x00FF)
|
||||||
@@ -203,12 +226,12 @@ func checkStatus(radio *sx128x.Device, operation string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Tx(radio *sx128x.Device, loraConfig lora.Config, data []byte) error {
|
func Tx(radio *sx128x.Device, loraConfig LoRaConfig, data []byte) error {
|
||||||
if len(data) > 255 {
|
if len(data) > 255 {
|
||||||
return errors.New("data length exceeds maximum of 255 bytes")
|
return errors.New("data length exceeds maximum of 255 bytes")
|
||||||
}
|
}
|
||||||
radio.SetStandby(sx128x.STANDBY_RC)
|
radio.SetStandby(sx128x.STANDBY_RC)
|
||||||
radio.SetPacketParamsLoRa(uint32(loraConfig.Preamble), loraConfig.HeaderType, uint8(len(data)&0xFF), loraConfig.Crc, loraConfig.Iq)
|
radio.SetPacketParamsLoRa(loraConfig.PreambleLength, loraConfig.HeaderType, uint8(len(data)&0xFF), loraConfig.CrcType, loraConfig.IqType)
|
||||||
radio.SetBufferBaseAddress(0, 0)
|
radio.SetBufferBaseAddress(0, 0)
|
||||||
radio.WriteBuffer(0, data)
|
radio.WriteBuffer(0, data)
|
||||||
radio.SetDioIrqParams(sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
radio.SetDioIrqParams(sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
||||||
@@ -217,64 +240,11 @@ func Tx(radio *sx128x.Device, loraConfig lora.Config, data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Rx(radio *sx128x.Device, loraConfig lora.Config) {
|
func Rx(radio *sx128x.Device, loraConfig LoRaConfig) {
|
||||||
radio.SetStandby(sx128x.STANDBY_RC)
|
radio.SetStandby(sx128x.STANDBY_RC)
|
||||||
radio.SetDioIrqParams(sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
radio.SetDioIrqParams(sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00)
|
||||||
radio.SetBufferBaseAddress(0, 0)
|
radio.SetBufferBaseAddress(0, 0)
|
||||||
radio.ClearIrqStatus(sx128x.IRQ_ALL_MASK)
|
radio.ClearIrqStatus(sx128x.IRQ_ALL_MASK)
|
||||||
radio.SetRfFrequency(loraConfig.Freq)
|
radio.SetRfFrequency(loraConfig.Frequency)
|
||||||
radio.SetRx(sx128x.PERIOD_BASE_4_MS, 250)
|
radio.SetRx(sx128x.PERIOD_BASE_4_MS, 250)
|
||||||
}
|
}
|
||||||
|
|
||||||
func codingRate(cr uint8) uint8 {
|
|
||||||
switch cr {
|
|
||||||
case lora.CodingRate4_5:
|
|
||||||
return sx128x.LORA_CR_4_5
|
|
||||||
case lora.CodingRate4_6:
|
|
||||||
return sx128x.LORA_CR_4_6
|
|
||||||
case lora.CodingRate4_7:
|
|
||||||
return sx128x.LORA_CR_4_7
|
|
||||||
case lora.CodingRate4_8:
|
|
||||||
return sx128x.LORA_CR_4_8
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func spreadingFactor(sf uint8) uint8 {
|
|
||||||
switch sf {
|
|
||||||
case lora.SpreadingFactor5:
|
|
||||||
return sx128x.LORA_SF_5
|
|
||||||
case lora.SpreadingFactor6:
|
|
||||||
return sx128x.LORA_SF_6
|
|
||||||
case lora.SpreadingFactor7:
|
|
||||||
return sx128x.LORA_SF_7
|
|
||||||
case lora.SpreadingFactor8:
|
|
||||||
return sx128x.LORA_SF_8
|
|
||||||
case lora.SpreadingFactor9:
|
|
||||||
return sx128x.LORA_SF_9
|
|
||||||
case lora.SpreadingFactor10:
|
|
||||||
return sx128x.LORA_SF_10
|
|
||||||
case lora.SpreadingFactor11:
|
|
||||||
return sx128x.LORA_SF_11
|
|
||||||
case lora.SpreadingFactor12:
|
|
||||||
return sx128x.LORA_SF_12
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func bandwidth(bw uint8) uint8 {
|
|
||||||
switch bw {
|
|
||||||
case lora.Bandwidth_1625_0:
|
|
||||||
return sx128x.LORA_BW_1600
|
|
||||||
case lora.Bandwidth_812_5:
|
|
||||||
return sx128x.LORA_BW_800
|
|
||||||
case lora.Bandwidth_406_25:
|
|
||||||
return sx128x.LORA_BW_400
|
|
||||||
case lora.Bandwidth_203_125:
|
|
||||||
return sx128x.LORA_BW_200
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module node
|
||||||
|
|
||||||
|
go 1.26.2
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
id NodeId
|
||||||
|
transport Transport
|
||||||
|
sequenceNumber uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(id NodeId, transport Transport) *Node {
|
||||||
|
return &Node{
|
||||||
|
id: id,
|
||||||
|
transport: transport,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeId uint8
|
||||||
|
|
||||||
|
func (id NodeId) IsBroadcast() bool {
|
||||||
|
return id == 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) Receive(timeout uint32) (NodeId, uint32, []byte, error) {
|
||||||
|
data, err := b.transport.Rx(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
if len(data) < 6 {
|
||||||
|
return 0, 0, nil, errors.New("invalid message length")
|
||||||
|
}
|
||||||
|
sourceId := NodeId(data[0])
|
||||||
|
targetId := NodeId(data[1])
|
||||||
|
if targetId != b.id && !targetId.IsBroadcast() {
|
||||||
|
return 0, 0, nil, nil
|
||||||
|
}
|
||||||
|
seq := uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||||
|
payload := data[6:]
|
||||||
|
return sourceId, seq, payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) ReceiveWithAck(timeout uint32) (NodeId, uint32, []byte, error) {
|
||||||
|
data, err := b.transport.Rx(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
if len(data) < 6 {
|
||||||
|
return 0, 0, nil, errors.New("invalid message length")
|
||||||
|
}
|
||||||
|
sourceId := NodeId(data[0])
|
||||||
|
targetId := NodeId(data[1])
|
||||||
|
if targetId != b.id && !targetId.IsBroadcast() {
|
||||||
|
return 0, 0, nil, errors.New("message not intended for this node")
|
||||||
|
}
|
||||||
|
seq := uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||||
|
payload := data[6:]
|
||||||
|
ackMsg := make([]byte, 6)
|
||||||
|
ackMsg[0] = byte(b.id)
|
||||||
|
ackMsg[1] = byte(sourceId)
|
||||||
|
ackMsg[2] = byte(seq >> 24)
|
||||||
|
ackMsg[3] = byte(seq >> 16)
|
||||||
|
ackMsg[4] = byte(seq >> 8)
|
||||||
|
ackMsg[5] = byte(seq)
|
||||||
|
err = b.transport.Tx(ackMsg, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
return sourceId, seq, payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) SendWithAck(target NodeId, payload []byte, timeout uint32) error {
|
||||||
|
if target.IsBroadcast() {
|
||||||
|
return errors.New("cannot send with ack to broadcast address")
|
||||||
|
}
|
||||||
|
msg := make([]byte, 6)
|
||||||
|
msg[0] = byte(b.id)
|
||||||
|
msg[1] = byte(target)
|
||||||
|
sentSeq := b.sequenceNumber
|
||||||
|
msg[2] = byte(sentSeq >> 24)
|
||||||
|
msg[3] = byte(sentSeq >> 16)
|
||||||
|
msg[4] = byte(sentSeq >> 8)
|
||||||
|
msg[5] = byte(sentSeq)
|
||||||
|
b.sequenceNumber++
|
||||||
|
msg = append(msg, payload...)
|
||||||
|
b.transport.Tx(msg, timeout)
|
||||||
|
|
||||||
|
sender, receivedSeq, _, err := b.Receive(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sender != target {
|
||||||
|
return errors.New("received ACK from unexpected sender")
|
||||||
|
}
|
||||||
|
if receivedSeq != sentSeq {
|
||||||
|
return errors.New("received ACK with unexpected sequence number")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
type Transport interface {
|
||||||
|
Tx(payload []byte, timeout uint32) error
|
||||||
|
Rx(timeout uint32) ([]byte, error)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user