mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-04 15:07:46 +00:00
sx127x: Major cleanup/rewrite, and tests pass with lorawan stack tests
This commit is contained in:
committed by
Ron Evans
parent
28ddb2681d
commit
dc4f0c974a
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
// This example code enable continuous Wave/Preamble
|
||||
// This example code demonstrates Lora RX/TX.
|
||||
// It has been tested with bluepill and SX1276 (RFM95W board)
|
||||
|
||||
import (
|
||||
"machine"
|
||||
@@ -10,7 +11,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
FREQ = 868100000
|
||||
FREQ = 868100000
|
||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -21,104 +24,76 @@ var (
|
||||
SX127X_PIN_CS = machine.PB8
|
||||
SX127X_PIN_DIO0 = machine.PA0
|
||||
SX127X_SPI = machine.SPI0
|
||||
|
||||
txmsg = []byte("Hello TinyGO")
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("\n# TinyGo Lora continuous Wave/Preamble test")
|
||||
println("# -----------------------------------------")
|
||||
|
||||
println("main: configuring LED/SPI/DIO/IRQ")
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
// SPI, RESET, CS configuration
|
||||
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.PinInputPulldown}) // Checkthat
|
||||
SX127X_PIN_DIO0.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
SX127X_SPI.Configure(machine.SPIConfig{Frequency: 500000, Mode: 0})
|
||||
|
||||
// Create the driver
|
||||
loraRadio = sx127x.New(SX127X_SPI, SX127X_PIN_CS, SX127X_PIN_RST)
|
||||
|
||||
err := SX127X_PIN_DIO0.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
||||
err := SX127X_PIN_DIO0.SetInterrupt(machine.PinRising, func(machine.Pin) { // Int handler
|
||||
loraRadio.HandleInterrupt()
|
||||
})
|
||||
if err != nil {
|
||||
panic("Can't configure DIO int handler")
|
||||
panic("main: Can't configure DIO int handler")
|
||||
}
|
||||
|
||||
// Reset the radio module
|
||||
println("main: create and start SX127x driver")
|
||||
loraRadio = sx127x.New(SX127X_SPI, SX127X_PIN_CS, SX127X_PIN_RST)
|
||||
loraRadio.Reset()
|
||||
|
||||
println("Try to detect sx127x radio")
|
||||
state := loraRadio.DetectDevice()
|
||||
if !state {
|
||||
panic("sx127x not detected. ")
|
||||
panic("main: sx127x NOT FOUND !!!")
|
||||
} else {
|
||||
println("sx127x detected")
|
||||
println("main: sx127x found")
|
||||
}
|
||||
|
||||
/*
|
||||
// Prepare for Lora operation
|
||||
loraConf := sx126x.LoraConfig{
|
||||
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,
|
||||
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,
|
||||
LoraTxPowerDBm: 14,
|
||||
}
|
||||
loraRadio.LoraConfig(loraConf)
|
||||
*/
|
||||
|
||||
println("Start Configure Lora")
|
||||
println("main: Configure lora modulation")
|
||||
loraRadio.SetOpModeLora()
|
||||
loraRadio.SetOpMode(sx127x.SX127X_OPMODE_SLEEP)
|
||||
loraRadio.SetTxPower(11, true)
|
||||
loraRadio.SetFrequency(FREQ)
|
||||
loraRadio.SetBandwidth(sx127x.SX127X_LORA_BW_125_0)
|
||||
loraRadio.SetCodingRate(sx127x.SX127X_LORA_CR_4_5)
|
||||
loraRadio.SetRxPayloadCrc(sx127x.SX127X_LORA_CRC_ON)
|
||||
loraRadio.SetHeaderMode(sx127x.SX127X_LORA_HEADER_EXPLICIT)
|
||||
loraRadio.SetLoraFrequency(FREQ)
|
||||
loraRadio.SetLoraBandwidth(sx127x.SX127X_LORA_BW_125_0)
|
||||
loraRadio.SetLoraSpreadingFactor(sx127x.SX127X_LORA_SF11)
|
||||
loraRadio.SetLoraCodingRate(sx127x.SX127X_LORA_CR_4_5)
|
||||
loraRadio.SetLoraIqMode(sx127x.SX127X_LORA_IQ_STANDARD)
|
||||
loraRadio.SetLoraCrc(true)
|
||||
loraRadio.SetLoraHeaderMode(sx127x.SX127X_LORA_HEADER_EXPLICIT)
|
||||
loraRadio.SetLowDataRateOptim(sx127x.SX127X_LOW_DATARATE_OPTIM_OFF)
|
||||
println("End Configure Lora")
|
||||
|
||||
// Get uint32 from RSSI
|
||||
rand32 := loraRadio.RandomU32()
|
||||
println("main: Get random 32bit from RSSI:", rand32)
|
||||
|
||||
var count uint
|
||||
for {
|
||||
loraRadio.TxLora([]byte("Hello"))
|
||||
tStart := time.Now()
|
||||
machine.LED.Set(!machine.LED.Get())
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
/*
|
||||
|
||||
|
||||
// Although LoraConfig has already configured most of Lora settings,
|
||||
// the following lines are still required to enable Continuous Preamble/Wave
|
||||
loraRadio.SetPacketType(sx126x.SX126X_PACKET_TYPE_LORA)
|
||||
loraRadio.SetRfFrequency(loraConf.Freq)
|
||||
loraRadio.SetModulationParams(loraConf.Sf, loraConf.Bw, loraConf.Cr, loraConf.Ldr)
|
||||
loraRadio.SetTxParams(loraConf.LoraTxPowerDBm, sx126x.SX126X_PA_RAMP_200U)
|
||||
|
||||
for {
|
||||
println("2 seconds in Continuous Preamble")
|
||||
loraRadio.SetStandby()
|
||||
loraRadio.SetTxContinuousPreamble()
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Continuous Preamble Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
println("2 seconds in Continuous Wave")
|
||||
loraRadio.SetTxContinuousWave()
|
||||
time.Sleep(2 * time.Second)
|
||||
println(" Continuous Wave Stopped")
|
||||
|
||||
loraRadio.SetStandby()
|
||||
time.Sleep(60 * time.Second)
|
||||
|
||||
println("main: Receiving Lora for 10 seconds")
|
||||
for int(time.Now().Sub(tStart).Seconds()) < 60 {
|
||||
buf, err := loraRadio.LoraRx(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.LoraTx(txmsg, LORA_DEFAULT_TXTIMEOUT_MS)
|
||||
if err != nil {
|
||||
println("TX Error:", err)
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+59
-60
@@ -2,74 +2,73 @@ package sx127x
|
||||
|
||||
const (
|
||||
// registers
|
||||
REG_FIFO = 0x00
|
||||
REG_OP_MODE = 0x01
|
||||
REG_FRF_MSB = 0x06
|
||||
REG_FRF_MID = 0x07
|
||||
REG_FRF_LSB = 0x08
|
||||
REG_PA_CONFIG = 0x09
|
||||
REG_PA_RAMP = 0x0a
|
||||
REG_OCP = 0x0b
|
||||
REG_LNA = 0x0c
|
||||
REG_FIFO_ADDR_PTR = 0x0d
|
||||
REG_FIFO_TX_BASE_ADDR = 0x0e
|
||||
REG_FIFO_RX_BASE_ADDR = 0x0f
|
||||
REG_FIFO_RX_CURRENT_ADDR = 0x10
|
||||
REG_IRQ_FLAGS_MASK = 0x11
|
||||
REG_IRQ_FLAGS = 0x12
|
||||
REG_RX_NB_BYTES = 0x13
|
||||
REG_PKT_SNR_VALUE = 0x19
|
||||
REG_PKT_RSSI_VALUE = 0x1a
|
||||
REG_RSSI_VALUE = 0x1b
|
||||
REG_MODEM_CONFIG_1 = 0x1d
|
||||
REG_MODEM_CONFIG_2 = 0x1e
|
||||
REG_SYMB_TIMEOUT_LSB = 0x1f
|
||||
REG_PREAMBLE_MSB = 0x20
|
||||
REG_PREAMBLE_LSB = 0x21
|
||||
REG_PAYLOAD_LENGTH = 0x22
|
||||
REG_MAX_PAYLOAD_LENGTH = 0x23
|
||||
REG_HOP_PERIOD = 0x24
|
||||
REG_MODEM_CONFIG_3 = 0x26
|
||||
REG_FREQ_ERROR_MSB = 0x28
|
||||
REG_FREQ_ERROR_MID = 0x29
|
||||
REG_FREQ_ERROR_LSB = 0x2a
|
||||
REG_RSSI_WIDEBAND = 0x2c
|
||||
REG_DETECTION_OPTIMIZE = 0x31
|
||||
REG_INVERTIQ = 0x33
|
||||
REG_DETECTION_THRESHOLD = 0x37
|
||||
REG_SYNC_WORD = 0x39
|
||||
REG_INVERTIQ2 = 0x3b
|
||||
REG_DIO_MAPPING_1 = 0x40
|
||||
REG_DIO_MAPPING_2 = 0x41
|
||||
REG_VERSION = 0x42
|
||||
REG_PA_DAC = 0x4d
|
||||
|
||||
SX127X_REG_FIFO = 0x00
|
||||
SX127X_REG_OP_MODE = 0x01
|
||||
SX127X_REG_FRF_MSB = 0x06
|
||||
SX127X_REG_FRF_MID = 0x07
|
||||
SX127X_REG_FRF_LSB = 0x08
|
||||
SX127X_REG_PA_CONFIG = 0x09
|
||||
SX127X_REG_PA_RAMP = 0x0a
|
||||
SX127X_REG_OCP = 0x0b
|
||||
SX127X_REG_LNA = 0x0c
|
||||
SX127X_REG_FIFO_ADDR_PTR = 0x0d
|
||||
SX127X_REG_FIFO_TX_BASE_ADDR = 0x0e
|
||||
SX127X_REG_FIFO_RX_BASE_ADDR = 0x0f
|
||||
SX127X_REG_FIFO_RX_CURRENT_ADDR = 0x10
|
||||
SX127X_REG_IRQ_FLAGS_MASK = 0x11
|
||||
SX127X_REG_IRQ_FLAGS = 0x12
|
||||
SX127X_REG_RX_NB_BYTES = 0x13
|
||||
SX127X_REG_PKT_SNR_VALUE = 0x19
|
||||
SX127X_REG_PKT_RSSI_VALUE = 0x1a
|
||||
SX127X_REG_RSSI_VALUE = 0x1b
|
||||
SX127X_REG_MODEM_CONFIG_1 = 0x1d
|
||||
SX127X_REG_MODEM_CONFIG_2 = 0x1e
|
||||
SX127X_REG_SYMB_TIMEOUT_LSB = 0x1f
|
||||
SX127X_REG_PREAMBLE_MSB = 0x20
|
||||
SX127X_REG_PREAMBLE_LSB = 0x21
|
||||
SX127X_REG_PAYLOAD_LENGTH = 0x22
|
||||
SX127X_REG_MAX_PAYLOAD_LENGTH = 0x23
|
||||
SX127X_REG_HOP_PERIOD = 0x24
|
||||
SX127X_REG_MODEM_CONFIG_3 = 0x26
|
||||
SX127X_REG_FREQ_ERROR_MSB = 0x28
|
||||
SX127X_REG_FREQ_ERROR_MID = 0x29
|
||||
SX127X_REG_FREQ_ERROR_LSB = 0x2a
|
||||
SX127X_REG_RSSI_WIDEBAND = 0x2c
|
||||
SX127X_REG_DETECTION_OPTIMIZE = 0x31
|
||||
SX127X_REG_INVERTIQ = 0x33
|
||||
SX127X_REG_DETECTION_THRESHOLD = 0x37
|
||||
SX127X_REG_SYNC_WORD = 0x39
|
||||
SX127X_REG_INVERTIQ2 = 0x3b
|
||||
SX127X_REG_DIO_MAPPING_1 = 0x40
|
||||
SX127X_REG_DIO_MAPPING_2 = 0x41
|
||||
SX127X_REG_VERSION = 0x42
|
||||
SX127X_REG_PA_DAC = 0x4d
|
||||
// PA config
|
||||
PA_BOOST = 0x80
|
||||
SX127X_PA_BOOST = 0x80
|
||||
|
||||
// Bits masking the corresponding IRQs from the radio
|
||||
IRQ_LORA_RXTOUT_MASK = uint8(0x80)
|
||||
IRQ_LORA_RXDONE_MASK = uint8(0x40)
|
||||
IRQ_LORA_CRCERR_MASK = uint8(0x20)
|
||||
IRQ_LORA_HEADER_MASK = uint8(0x10)
|
||||
IRQ_LORA_TXDONE_MASK = uint8(0x08)
|
||||
IRQ_LORA_CDDONE_MASK = uint8(0x04)
|
||||
IRQ_LORA_FHSSCH_MASK = uint8(0x02)
|
||||
IRQ_LORA_CDDETD_MASK = uint8(0x01)
|
||||
SX127X_IRQ_LORA_RXTOUT_MASK = uint8(0x80)
|
||||
SX127X_IRQ_LORA_RXDONE_MASK = uint8(0x40)
|
||||
SX127X_IRQ_LORA_CRCERR_MASK = uint8(0x20)
|
||||
SX127X_IRQ_LORA_HEADER_MASK = uint8(0x10)
|
||||
SX127X_IRQ_LORA_TXDONE_MASK = uint8(0x08)
|
||||
SX127X_IRQ_LORA_CDDONE_MASK = uint8(0x04)
|
||||
SX127X_IRQ_LORA_FHSSCH_MASK = uint8(0x02)
|
||||
SX127X_IRQ_LORA_CDDETD_MASK = uint8(0x01)
|
||||
|
||||
// DIO function mappings D0D1D2D3
|
||||
MAP_DIO0_LORA_RXDONE = uint8(0x00) // 00------
|
||||
MAP_DIO0_LORA_TXDONE = uint8(0x40) // 01------
|
||||
MAP_DIO1_LORA_RXTOUT = uint8(0x00) // --00----
|
||||
MAP_DIO1_LORA_NOP = uint8(0x30) // --11----
|
||||
MAP_DIO2_LORA_NOP = uint8(0xC0) // ----11--
|
||||
SX127X_MAP_DIO0_LORA_RXDONE = uint8(0x00) // 00------
|
||||
SX127X_MAP_DIO0_LORA_TXDONE = uint8(0x40) // 01------
|
||||
SX127X_MAP_DIO1_LORA_RXTOUT = uint8(0x00) // --00----
|
||||
SX127X_MAP_DIO1_LORA_NOP = uint8(0x30) // --11----
|
||||
SX127X_MAP_DIO2_LORA_NOP = uint8(0xC0) // ----11--
|
||||
|
||||
PAYLOAD_LENGTH = uint8(0x40)
|
||||
SX127X_PAYLOAD_LENGTH = uint8(0x40)
|
||||
|
||||
// Low Noise Amp
|
||||
LNA_MAX_GAIN = uint8(0x23)
|
||||
LNA_OFF_GAIN = uint8(0x00)
|
||||
LNA_LOW_GAIN = uint8(0x20)
|
||||
SX127X_LNA_MAX_GAIN = uint8(0x23)
|
||||
SX127X_LNA_OFF_GAIN = uint8(0x00)
|
||||
SX127X_LNA_LOW_GAIN = uint8(0x20)
|
||||
|
||||
// Header type
|
||||
SX127X_LORA_HEADER_EXPLICIT = uint8(0x00)
|
||||
|
||||
+286
-391
@@ -60,6 +60,10 @@ type LoraConfig struct {
|
||||
LoraTxPowerDBm int8 // Tx power in Dbm
|
||||
}
|
||||
|
||||
var (
|
||||
errUndefinedLoraConf = errors.New("Undefined Lora configuration")
|
||||
)
|
||||
|
||||
// --------------------------------------------------
|
||||
// Channel and events
|
||||
// --------------------------------------------------
|
||||
@@ -121,234 +125,24 @@ func (d *Device) WriteRegister(reg uint8, value uint8) uint8 {
|
||||
|
||||
// SetOpMode changes the sx1276 mode
|
||||
func (d *Device) SetOpMode(mode uint8) {
|
||||
cur := d.ReadRegister(REG_OP_MODE)
|
||||
cur := d.ReadRegister(SX127X_REG_OP_MODE)
|
||||
new := (cur & (^SX127X_OPMODE_MASK)) | mode
|
||||
d.WriteRegister(REG_OP_MODE, new)
|
||||
d.WriteRegister(SX127X_REG_OP_MODE, new)
|
||||
}
|
||||
|
||||
// SetOpMode changes the sx1276 mode
|
||||
func (d *Device) SetOpModeLora() {
|
||||
d.WriteRegister(REG_OP_MODE, SX127X_OPMODE_LORA)
|
||||
d.WriteRegister(SX127X_REG_OP_MODE, SX127X_OPMODE_LORA)
|
||||
}
|
||||
|
||||
// SetupLora configures sx127x Lora mode
|
||||
func (d *Device) SetupLora(config LoraConfig) error {
|
||||
|
||||
d.loraConf = config
|
||||
|
||||
// Reset the device first
|
||||
d.Reset()
|
||||
|
||||
// Switch to Lora mode
|
||||
d.SetOpModeLora()
|
||||
d.SetOpMode(SX127X_OPMODE_SLEEP)
|
||||
|
||||
// Access High Frequency Mode
|
||||
d.SetLowFrequencyModeOn(false)
|
||||
|
||||
// Set PA Ramp time 50 uS
|
||||
d.WriteRegister(REG_PA_RAMP, (d.ReadRegister(REG_PA_RAMP)&0xF0)|0x08) // set PA ramp-up time 50 uSec
|
||||
|
||||
// Enable power (manage Over Current, PA_Boost ... etc)
|
||||
d.SetTxPower(11, true)
|
||||
|
||||
// Set Low Noise Amplifier to MAX
|
||||
d.WriteRegister(REG_LNA, LNA_MAX_GAIN)
|
||||
|
||||
// Set Frequency
|
||||
d.SetFrequency(d.loraConf.Freq)
|
||||
|
||||
// Set Bandwidth
|
||||
d.SetBandwidth(d.loraConf.Bw)
|
||||
|
||||
//Set Coding Rate (TODO : Check)
|
||||
d.SetCodingRate(d.loraConf.Cr)
|
||||
|
||||
// Set explicit header
|
||||
d.SetHeaderMode(SX127X_LORA_HEADER_EXPLICIT)
|
||||
|
||||
// Enable CRC
|
||||
d.SetRxPayloadCrc(SX127X_LORA_CRC_ON)
|
||||
|
||||
// Disable IQ Polarization
|
||||
d.SetIQPolarity(SX127X_LORA_IQ_STANDARD)
|
||||
|
||||
// Disable HOP PERIOD
|
||||
d.SetHopPeriod(0x00)
|
||||
|
||||
// Continuous Mode
|
||||
d.SetTxContinuousMode(false)
|
||||
|
||||
// Set Lora Sync
|
||||
d.SetSyncWord(0x34)
|
||||
|
||||
//Set Max payload length (default value)
|
||||
d.WriteRegister(REG_MAX_PAYLOAD_LENGTH, 0xFF)
|
||||
// Mandatory in Implicit header Mode (default value)
|
||||
d.WriteRegister(REG_PAYLOAD_LENGTH, 0x01)
|
||||
|
||||
// AGC On
|
||||
d.SetAgcAuto(SX127X_AGC_AUTO_ON)
|
||||
|
||||
// set FIFO base addresses
|
||||
d.WriteRegister(REG_FIFO_TX_BASE_ADDR, 0)
|
||||
d.WriteRegister(REG_FIFO_RX_BASE_ADDR, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxLora sends a packet in Lora mode
|
||||
// Intmode will enable interrupt mode.
|
||||
// If disabled, function will probe registers for TXDone before
|
||||
// returning
|
||||
func (d *Device) TxLora(payload []byte) error {
|
||||
|
||||
// Are we already in Lora mode ?
|
||||
r := d.ReadRegister(REG_OP_MODE)
|
||||
if (r & SX127X_OPMODE_LORA) != SX127X_OPMODE_LORA {
|
||||
return errors.New("Not in Lora mode")
|
||||
}
|
||||
|
||||
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||
d.WriteRegister(REG_DIO_MAPPING_1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP)
|
||||
// Clear all radio IRQ Flags
|
||||
d.WriteRegister(REG_IRQ_FLAGS, 0xFF)
|
||||
// Mask all but TxDone
|
||||
d.WriteRegister(REG_IRQ_FLAGS_MASK, ^IRQ_LORA_TXDONE_MASK)
|
||||
|
||||
// initialize the payload size and address pointers
|
||||
d.WriteRegister(REG_FIFO_TX_BASE_ADDR, 0)
|
||||
d.WriteRegister(REG_FIFO_ADDR_PTR, 0)
|
||||
d.WriteRegister(REG_PAYLOAD_LENGTH, uint8(len(payload)))
|
||||
|
||||
// Copy payload to FIFO // TODO: Bulk
|
||||
for i := 0; i < len(payload); i++ {
|
||||
d.WriteRegister(REG_FIFO, payload[i])
|
||||
}
|
||||
|
||||
// Enable TX
|
||||
d.SetOpMode(SX127X_OPMODE_TX)
|
||||
|
||||
msg := <-d.GetRadioEventChan()
|
||||
if msg.EventType != RadioEventTxDone {
|
||||
return errors.New("Unexpected Radio Event while TX")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
//CheckIrq can be called periodicaly to check for RXDONE,TXDONE,RXTOUT
|
||||
//but It would be more efficient to call it on DIO0/1 pins rising edge
|
||||
func (d *Device) CheckIrq() {
|
||||
|
||||
irqFlags := d.ReadRegister(REG_IRQ_FLAGS)
|
||||
//println("sx21276: irq=", irqFlags)
|
||||
|
||||
// We have a packet
|
||||
if (irqFlags & IRQ_LORA_RXDONE_MASK) > 0 {
|
||||
//println("sx1276: RXDONE")
|
||||
// Read current packet
|
||||
buf := []byte{}
|
||||
packetLength := d.ReadRegister(REG_RX_NB_BYTES)
|
||||
d.WriteRegister(REG_FIFO_ADDR_PTR, d.ReadRegister(REG_FIFO_RX_CURRENT_ADDR)) // Reset FIFO Read Addr
|
||||
for i := uint8(0); i < packetLength; i++ {
|
||||
buf = append(buf, d.ReadRegister(REG_FIFO))
|
||||
}
|
||||
// Send RXDONE to the defined event channel
|
||||
d.radioEventChan <- RadioEvent{EventType: EventRxDone, EventData: buf}
|
||||
}
|
||||
if (irqFlags & IRQ_LORA_TXDONE_MASK) > 0 {
|
||||
//println("sx1276: TXDONE")
|
||||
d.radioEventChan <- RadioEvent{EventType: EventTxDone, EventData: nil}
|
||||
}
|
||||
if (irqFlags & IRQ_LORA_RXTOUT_MASK) > 0 {
|
||||
//println("sx1276: RXTOUT")
|
||||
d.radioEventChan <- RadioEvent{EventType: EventRxTimeout, EventData: nil}
|
||||
}
|
||||
|
||||
// Sigh: on some processors, for some unknown reason, doing this only once does not actually
|
||||
// clear the radio's interrupt flag. So we do it twice. Why?
|
||||
d.WriteRegister(REG_IRQ_FLAGS, irqFlags) // Clear all IRQ flags
|
||||
d.WriteRegister(REG_IRQ_FLAGS, irqFlags) // Clear all IRQ flags
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// SetRadioEventChan defines a channel so the driver can send its Radio Events
|
||||
func (d *Device) SetRadioEventChan(channel chan RadioEvent) {
|
||||
d.radioEventChan = channel
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// Init reboots the SX1276 module
|
||||
func (d *Device) Init(cfg LoraConfig) (err error) {
|
||||
d.loraConf = cfg
|
||||
d.csPin.High()
|
||||
d.Reset()
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
/*
|
||||
|
||||
// ConfigureLoraModem prepares for LORA communications
|
||||
func (d *Device) ConfigureLoraModem() {
|
||||
|
||||
// Sleep mode required to go LOra
|
||||
d.OpMode(OPMODE_SLEEP)
|
||||
// Set Lora mode (from sleep)
|
||||
d.OpModeLora()
|
||||
// Switch to standby mode
|
||||
d.OpMode(OPMODE_STANDBY)
|
||||
// Set Bandwidth
|
||||
d.SetBandwidth(d.cnf.Bandwidth)
|
||||
// Disable IQ Polarization
|
||||
d.SetInvertedIQ(false)
|
||||
// Set implicit header
|
||||
d.SetImplicitHeaderModeOn(false)
|
||||
// We want CRC
|
||||
d.SetRxPayloadCrc(true)
|
||||
d.SetAgcAutoOn(true)
|
||||
if d.GetBandwidth() == 125000 && (d.GetSpreadingFactor() == 11 || d.GetSpreadingFactor() == 12) {
|
||||
d.SetLowDataRateOptimOn(true)
|
||||
}
|
||||
|
||||
// Configure Output Power
|
||||
d.WriteRegister(REG_PA_RAMP, (d.ReadRegister(REG_PA_RAMP)&0xF0)|0x08) // set PA ramp-up time 50 uSec
|
||||
d.WriteRegister(REG_PA_CONFIG, 0xFF) //PA_BOOST MAX
|
||||
d.SetOCP(140) // Over Current protection
|
||||
|
||||
// RX and premamble
|
||||
d.WriteRegister(REG_PREAMBLE_MSB, 0x00) // Preamble set to 8 symp
|
||||
d.WriteRegister(REG_PREAMBLE_LSB, 0x08) // -> 0x0008 + 4 = 12
|
||||
d.WriteRegister(REG_SYMB_TIMEOUT_LSB, 0x25) //Rx Timeout 37 symbol
|
||||
|
||||
// set FIFO base addresses
|
||||
d.WriteRegister(REG_FIFO_TX_BASE_ADDR, 0)
|
||||
d.WriteRegister(REG_FIFO_RX_BASE_ADDR, 0)
|
||||
}
|
||||
*/
|
||||
//GetVersion returns hardware version of sx1276 chipset
|
||||
func (d *Device) GetVersion() uint8 {
|
||||
return (d.ReadRegister(REG_VERSION))
|
||||
return (d.ReadRegister(SX127X_REG_VERSION))
|
||||
}
|
||||
|
||||
// IsTransmitting tests if a packet transmission is in progress
|
||||
func (d *Device) IsTransmitting() bool {
|
||||
return (d.ReadRegister(REG_OP_MODE) & SX127X_OPMODE_TX) == SX127X_OPMODE_TX
|
||||
}
|
||||
|
||||
// ReadPacket reads a received packet into a byte array
|
||||
func (d *Device) ReadPacket(packet []byte) int {
|
||||
available := int(d.ReadRegister(REG_RX_NB_BYTES) - d.packetIndex)
|
||||
if available > len(packet) {
|
||||
available = len(packet)
|
||||
}
|
||||
|
||||
for i := 0; i < available; i++ {
|
||||
d.packetIndex++
|
||||
packet[i] = d.ReadRegister(REG_FIFO)
|
||||
}
|
||||
|
||||
return available
|
||||
return (d.ReadRegister(SX127X_REG_OP_MODE) & SX127X_OPMODE_TX) == SX127X_OPMODE_TX
|
||||
}
|
||||
|
||||
// LastPacketRSSI gives the RSSI of the last packet received
|
||||
@@ -358,41 +152,17 @@ func (d *Device) LastPacketRSSI() uint8 {
|
||||
if d.loraConf.Freq < 868000000 {
|
||||
adjustValue = 164
|
||||
}
|
||||
return d.ReadRegister(REG_PKT_RSSI_VALUE) - adjustValue
|
||||
return d.ReadRegister(SX127X_REG_PKT_RSSI_VALUE) - adjustValue
|
||||
}
|
||||
|
||||
// LastPacketSNR gives the SNR of the last packet received
|
||||
func (d *Device) LastPacketSNR() uint8 {
|
||||
return uint8(d.ReadRegister(REG_PKT_SNR_VALUE) / 4)
|
||||
}
|
||||
|
||||
/*
|
||||
// GetFrequency returns the frequency the LoRa module is using
|
||||
func (d *Device) GetFrequency() uint32 {
|
||||
f := uint64(d.ReadRegister(REG_FRF_LSB))
|
||||
f += uint64(d.ReadRegister(REG_FRF_MID)) << 8
|
||||
f += uint64(d.ReadRegister(REG_FRF_MSB)) << 16
|
||||
f = (f * 32000000) >> 19 //FSTEP = FXOSC/2^19
|
||||
return uint32(f)
|
||||
}
|
||||
*/
|
||||
// SetFrequency updates the frequency the LoRa module is using
|
||||
func (d *Device) SetFrequency(frequency uint32) {
|
||||
d.loraConf.Freq = frequency
|
||||
var frf = (uint64(frequency) << 19) / 32000000
|
||||
d.WriteRegister(REG_FRF_MSB, uint8(frf>>16))
|
||||
d.WriteRegister(REG_FRF_MID, uint8(frf>>8))
|
||||
d.WriteRegister(REG_FRF_LSB, uint8(frf>>0))
|
||||
}
|
||||
|
||||
// GetSpreadingFactor returns the spreading factor the LoRa module is using
|
||||
func (d *Device) GetSpreadingFactor() uint8 {
|
||||
return d.ReadRegister(REG_MODEM_CONFIG_2) >> 4
|
||||
return uint8(d.ReadRegister(SX127X_REG_PKT_SNR_VALUE) / 4)
|
||||
}
|
||||
|
||||
// GetRSSI returns current RSSI
|
||||
func (d *Device) GetRSSI() uint8 {
|
||||
return d.ReadRegister(REG_RSSI_VALUE)
|
||||
return d.ReadRegister(SX127X_REG_RSSI_VALUE)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -402,56 +172,6 @@ func (d *Device) GetBandwidth() int32 {
|
||||
}
|
||||
*/
|
||||
|
||||
//SetSyncWord defines sync word
|
||||
func (d *Device) SetSyncWord(syncWord uint8) {
|
||||
d.WriteRegister(REG_SYNC_WORD, syncWord)
|
||||
}
|
||||
|
||||
// SetIQPolarity Sets I/Q polarity configuration
|
||||
func (d *Device) SetIQPolarity(val uint8) {
|
||||
if val == SX127X_LORA_IQ_INVERTED {
|
||||
//Invert IQ Back
|
||||
d.WriteRegister(0x33, 0x67)
|
||||
d.WriteRegister(0x3B, 0x19)
|
||||
} else {
|
||||
//Set IQ to normal values
|
||||
d.WriteRegister(0x33, 0x27)
|
||||
d.WriteRegister(0x3B, 0x1D)
|
||||
}
|
||||
}
|
||||
|
||||
// RxLora sets device in receive mode
|
||||
func (d *Device) RxLora() {
|
||||
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||
d.WriteRegister(REG_DIO_MAPPING_1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP)
|
||||
// Clear all radio IRQ Flags
|
||||
d.WriteRegister(REG_IRQ_FLAGS, 0xFF)
|
||||
// Mask all but TxDone
|
||||
d.WriteRegister(REG_IRQ_FLAGS_MASK, ^IRQ_LORA_RXDONE_MASK)
|
||||
|
||||
d.SetOpMode(SX127X_OPMODE_RX) // RX Mode
|
||||
}
|
||||
|
||||
/*
|
||||
// setLdoFlag() enables LowDataRateOptimize bit (mandated when symbol length >16ms)
|
||||
// LGTM
|
||||
func (d *Device) setLdoFlag() {
|
||||
// Section 4.1.1.5
|
||||
var symbolDuration = 1000 / (d.GetBandwidth() / (1 << d.GetSpreadingFactor()))
|
||||
|
||||
var config3 = d.ReadRegister(REG_MODEM_CONFIG_3)
|
||||
|
||||
// Section 4.1.1.6
|
||||
if symbolDuration > 16 {
|
||||
config3 = config3 | 0x08
|
||||
} else {
|
||||
config3 = config3 & 0xF7
|
||||
}
|
||||
|
||||
d.WriteRegister(REG_MODEM_CONFIG_3, config3)
|
||||
}
|
||||
*/
|
||||
|
||||
// SetTxPower sets the transmitter output power
|
||||
func (d *Device) SetTxPower(txPower int8, paBoost bool) {
|
||||
if !paBoost {
|
||||
@@ -461,7 +181,7 @@ func (d *Device) SetTxPower(txPower int8, paBoost bool) {
|
||||
} else if txPower > 14 {
|
||||
txPower = 14
|
||||
}
|
||||
d.WriteRegister(REG_PA_CONFIG, uint8(0x70)|uint8(txPower))
|
||||
d.WriteRegister(SX127X_REG_PA_CONFIG, uint8(0x70)|uint8(txPower))
|
||||
|
||||
} else {
|
||||
//PA_BOOST
|
||||
@@ -473,33 +193,36 @@ func (d *Device) SetTxPower(txPower int8, paBoost bool) {
|
||||
txPower -= 3
|
||||
|
||||
// High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.)
|
||||
d.WriteRegister(REG_PA_DAC, 0x87)
|
||||
d.WriteRegister(SX127X_REG_PA_DAC, 0x87)
|
||||
d.SetOCP(140)
|
||||
} else {
|
||||
if txPower < 2 {
|
||||
txPower = 2
|
||||
}
|
||||
|
||||
d.WriteRegister(REG_PA_DAC, 0x84)
|
||||
d.WriteRegister(SX127X_REG_PA_DAC, 0x84)
|
||||
d.SetOCP(100)
|
||||
|
||||
}
|
||||
|
||||
d.WriteRegister(REG_PA_CONFIG, uint8(PA_BOOST)|uint8(txPower-2))
|
||||
d.WriteRegister(SX127X_REG_PA_CONFIG, uint8(SX127X_PA_BOOST)|uint8(txPower-2))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// Internal functions
|
||||
// ---------------
|
||||
|
||||
// SetRxTimeout defines RX Timeout expressed as number of symbols
|
||||
// Default timeout is 64 * Ts
|
||||
func (d *Device) SetRxTimeout(tmoutSymb uint8) {
|
||||
d.WriteRegister(REG_SYMB_TIMEOUT_LSB, tmoutSymb)
|
||||
d.WriteRegister(SX127X_REG_SYMB_TIMEOUT_LSB, tmoutSymb)
|
||||
}
|
||||
|
||||
// SetOCP defines Overload Current Protection configuration
|
||||
func (d *Device) SetOCP(mA uint8) {
|
||||
|
||||
ocpTrim := uint8(27)
|
||||
|
||||
if mA < 45 {
|
||||
mA = 45
|
||||
}
|
||||
@@ -508,133 +231,263 @@ func (d *Device) SetOCP(mA uint8) {
|
||||
} else if mA <= 240 {
|
||||
ocpTrim = (mA + 30) / 10
|
||||
}
|
||||
|
||||
d.WriteRegister(REG_OCP, 0x20|(0x1F&ocpTrim))
|
||||
d.WriteRegister(SX127X_REG_OCP, 0x20|(0x1F&ocpTrim))
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// RegModemConfig1
|
||||
// ---------------
|
||||
|
||||
// SetBandwidth updates the bandwidth the LoRa module is using
|
||||
func (d *Device) SetBandwidth(bw uint8) {
|
||||
d.loraConf.Bw = bw
|
||||
d.WriteRegister(REG_MODEM_CONFIG_1, (d.ReadRegister(REG_MODEM_CONFIG_1)&0x0f)|(bw<<4))
|
||||
}
|
||||
|
||||
// SetCodingRate updates the coding rate the LoRa module is using
|
||||
func (d *Device) SetCodingRate(cr uint8) {
|
||||
d.loraConf.Cr = cr
|
||||
d.WriteRegister(REG_MODEM_CONFIG_1, (d.ReadRegister(REG_MODEM_CONFIG_1)&0xf1)|(cr<<1))
|
||||
}
|
||||
|
||||
// SetImplicitHeaderModeOn Enables implicit header mode ***
|
||||
func (d *Device) SetHeaderMode(headerType uint8) {
|
||||
d.loraConf.HeaderType = headerType
|
||||
if headerType == SX127X_LORA_HEADER_IMPLICIT {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_1, d.ReadRegister(REG_MODEM_CONFIG_1)|0x01)
|
||||
} else {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_1, d.ReadRegister(REG_MODEM_CONFIG_1)&0xfe)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// RegModemConfig2
|
||||
// ---------------
|
||||
|
||||
// SetSpreadingFactor updates the spreading factor the LoRa module is using
|
||||
func (d *Device) SetSpreadingFactor(sf uint8) {
|
||||
d.loraConf.Sf = sf
|
||||
if sf == SX127X_LORA_SF6 {
|
||||
d.WriteRegister(REG_DETECTION_OPTIMIZE, 0xc5)
|
||||
d.WriteRegister(REG_DETECTION_THRESHOLD, 0x0c)
|
||||
} else {
|
||||
d.WriteRegister(REG_DETECTION_OPTIMIZE, 0xc3)
|
||||
d.WriteRegister(REG_DETECTION_THRESHOLD, 0x0a)
|
||||
}
|
||||
var newValue = (d.ReadRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)
|
||||
d.WriteRegister(REG_MODEM_CONFIG_2, newValue)
|
||||
}
|
||||
|
||||
// SetTxContinuousMode enable Continuous Tx mode
|
||||
func (d *Device) SetTxContinuousMode(val bool) {
|
||||
if val {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_2, d.ReadRegister(REG_MODEM_CONFIG_2)|0x08)
|
||||
} else {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_2, d.ReadRegister(REG_MODEM_CONFIG_2)&0xf7)
|
||||
}
|
||||
}
|
||||
|
||||
// SetRxPayloadCrc Enable CRC generation and check on payload
|
||||
func (d *Device) SetRxPayloadCrc(val uint8) {
|
||||
if val == SX127X_LORA_CRC_ON {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_2, d.ReadRegister(REG_MODEM_CONFIG_2)|0x04)
|
||||
} else {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_2, d.ReadRegister(REG_MODEM_CONFIG_2)&0xfb)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// RegModemConfig3
|
||||
// ---------------
|
||||
|
||||
// SetAgcAutoOn enables Automatic Gain Control
|
||||
func (d *Device) SetAgcAuto(val uint8) {
|
||||
if val == SX127X_AGC_AUTO_ON {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_3, d.ReadRegister(REG_MODEM_CONFIG_3)|0x04)
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_3, d.ReadRegister(SX127X_REG_MODEM_CONFIG_3)|0x04)
|
||||
} else {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_3, d.ReadRegister(REG_MODEM_CONFIG_3)&0xfb)
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_3, d.ReadRegister(SX127X_REG_MODEM_CONFIG_3)&0xfb)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLowDataRateOptimize enables Low Data Rate Optimization
|
||||
func (d *Device) SetLowDataRateOptim(val uint8) {
|
||||
if val == SX127X_LOW_DATARATE_OPTIM_ON {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_3, d.ReadRegister(REG_MODEM_CONFIG_3)|0x08)
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_3, d.ReadRegister(SX127X_REG_MODEM_CONFIG_3)|0x08)
|
||||
} else {
|
||||
d.WriteRegister(REG_MODEM_CONFIG_3, d.ReadRegister(REG_MODEM_CONFIG_3)&0xf7)
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_3, d.ReadRegister(SX127X_REG_MODEM_CONFIG_3)&0xf7)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLowFrequencyModeOn enables Low Data Rate Optimization
|
||||
func (d *Device) SetLowFrequencyModeOn(val bool) {
|
||||
if val {
|
||||
d.WriteRegister(REG_OP_MODE, d.ReadRegister(REG_OP_MODE)|0x04)
|
||||
d.WriteRegister(SX127X_REG_OP_MODE, d.ReadRegister(SX127X_REG_OP_MODE)|0x04)
|
||||
} else {
|
||||
d.WriteRegister(REG_OP_MODE, d.ReadRegister(REG_OP_MODE)&0xfb)
|
||||
d.WriteRegister(SX127X_REG_OP_MODE, d.ReadRegister(SX127X_REG_OP_MODE)&0xfb)
|
||||
}
|
||||
}
|
||||
|
||||
// SetHopPeriod sets number of symbol periods between frequency hops. (0 = disabled).
|
||||
func (d *Device) SetHopPeriod(val uint8) {
|
||||
d.WriteRegister(REG_HOP_PERIOD, val)
|
||||
d.WriteRegister(SX127X_REG_HOP_PERIOD, val)
|
||||
}
|
||||
|
||||
// HandleInterrupt must be called by main code on DIO state change.
|
||||
func (d *Device) HandleInterrupt() {
|
||||
// Get IRQ and clear
|
||||
st := d.ReadRegister(REG_IRQ_FLAGS)
|
||||
d.WriteRegister(REG_IRQ_FLAGS, 0xFF)
|
||||
//
|
||||
// LORA FUNCTIONS
|
||||
//
|
||||
|
||||
rChan := d.GetRadioEventChan()
|
||||
// LoraConfig() defines Lora configuration for next Lora operations
|
||||
func (d *Device) LoraConfig(cnf LoraConfig) {
|
||||
// Save given configuration
|
||||
d.loraConf = cnf
|
||||
}
|
||||
|
||||
if (st & IRQ_LORA_RXDONE_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventRxDone, st, nil)
|
||||
}
|
||||
// SetLoraFrequency updates the frequency the LoRa module is using
|
||||
func (d *Device) SetLoraFrequency(frequency uint32) {
|
||||
d.loraConf.Freq = frequency
|
||||
var frf = (uint64(frequency) << 19) / 32000000
|
||||
d.WriteRegister(SX127X_REG_FRF_MSB, uint8(frf>>16))
|
||||
d.WriteRegister(SX127X_REG_FRF_MID, uint8(frf>>8))
|
||||
d.WriteRegister(SX127X_REG_FRF_LSB, uint8(frf>>0))
|
||||
}
|
||||
|
||||
if (st & IRQ_LORA_TXDONE_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTxDone, st, nil)
|
||||
}
|
||||
// SetBandwidth updates the bandwidth the LoRa module is using
|
||||
func (d *Device) SetLoraBandwidth(bw uint8) {
|
||||
d.loraConf.Bw = bw
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_1, (d.ReadRegister(SX127X_REG_MODEM_CONFIG_1)&0x0f)|(bw<<4))
|
||||
}
|
||||
|
||||
if (st & IRQ_LORA_RXTOUT_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTimeout, st, nil)
|
||||
}
|
||||
// SetCodingRate updates the coding rate the LoRa module is using
|
||||
func (d *Device) SetLoraCodingRate(cr uint8) {
|
||||
d.loraConf.Cr = cr
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_1, (d.ReadRegister(SX127X_REG_MODEM_CONFIG_1)&0xf1)|(cr<<1))
|
||||
}
|
||||
|
||||
if (st & IRQ_LORA_CRCERR_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventCrcError, st, nil)
|
||||
// SetImplicitHeaderModeOn Enables implicit header mode ***
|
||||
func (d *Device) SetLoraHeaderMode(headerType uint8) {
|
||||
d.loraConf.HeaderType = headerType
|
||||
if headerType == SX127X_LORA_HEADER_IMPLICIT {
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_1, d.ReadRegister(SX127X_REG_MODEM_CONFIG_1)|0x01)
|
||||
} else {
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_1, d.ReadRegister(SX127X_REG_MODEM_CONFIG_1)&0xfe)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLoraSpreadingFactor changes spreading factor
|
||||
func (d *Device) SetLoraSpreadingFactor(sf uint8) {
|
||||
d.loraConf.Sf = sf
|
||||
if sf == SX127X_LORA_SF6 {
|
||||
d.WriteRegister(SX127X_REG_DETECTION_OPTIMIZE, 0xc5)
|
||||
d.WriteRegister(SX127X_REG_DETECTION_THRESHOLD, 0x0c)
|
||||
} else {
|
||||
d.WriteRegister(SX127X_REG_DETECTION_OPTIMIZE, 0xc3)
|
||||
d.WriteRegister(SX127X_REG_DETECTION_THRESHOLD, 0x0a)
|
||||
}
|
||||
var newValue = (d.ReadRegister(SX127X_REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_2, newValue)
|
||||
}
|
||||
|
||||
// SetTxContinuousMode enable Continuous Tx mode
|
||||
func (d *Device) SetTxContinuousMode(val bool) {
|
||||
if val {
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_2, d.ReadRegister(SX127X_REG_MODEM_CONFIG_2)|0x08)
|
||||
} else {
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_2, d.ReadRegister(SX127X_REG_MODEM_CONFIG_2)&0xf7)
|
||||
}
|
||||
}
|
||||
|
||||
// SetLoraCrc Enable CRC generation and check on payload
|
||||
func (d *Device) SetLoraCrc(enable bool) {
|
||||
if enable {
|
||||
d.loraConf.Crc = SX127X_LORA_CRC_ON
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_2, d.ReadRegister(SX127X_REG_MODEM_CONFIG_2)|0x04)
|
||||
} else {
|
||||
d.loraConf.Crc = SX127X_LORA_CRC_OFF
|
||||
d.WriteRegister(SX127X_REG_MODEM_CONFIG_2, d.ReadRegister(SX127X_REG_MODEM_CONFIG_2)&0xfb)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) SetLoraPreamble(pLen uint16) {
|
||||
// Sets preamble length
|
||||
d.WriteRegister(SX127X_REG_PREAMBLE_MSB, uint8((pLen>>8)&0xFF))
|
||||
d.WriteRegister(SX127X_REG_PREAMBLE_LSB, uint8(pLen&0xFF))
|
||||
}
|
||||
|
||||
//SetLoraSyncWord defines sync word
|
||||
func (d *Device) SetLoraSyncWord(syncWord uint16) {
|
||||
d.loraConf.SyncWord = syncWord
|
||||
sw := uint8(syncWord & 0xFF)
|
||||
d.WriteRegister(SX127X_REG_SYNC_WORD, sw)
|
||||
}
|
||||
|
||||
// SetLoraIQMode Sets I/Q polarity configuration
|
||||
func (d *Device) SetLoraIqMode(val uint8) {
|
||||
d.loraConf.Iq = val
|
||||
if val == SX127X_LORA_IQ_STANDARD {
|
||||
//Set IQ to normal values
|
||||
d.WriteRegister(SX127X_REG_INVERTIQ, 0x27)
|
||||
d.WriteRegister(SX127X_REG_INVERTIQ2, 0x1D)
|
||||
} else {
|
||||
//Invert IQ Back
|
||||
d.WriteRegister(SX127X_REG_INVERTIQ, 0x66)
|
||||
d.WriteRegister(SX127X_REG_INVERTIQ2, 0x19)
|
||||
}
|
||||
}
|
||||
|
||||
// LoraTx sends a lora packet, (with timeout)
|
||||
func (d *Device) LoraTx(pkt []uint8, timeoutMs uint32) error {
|
||||
|
||||
//println("sx127x: LoraTx:", len(pkt), " bytes", hex.EncodeToString(pkt))
|
||||
d.SetOpModeLora()
|
||||
d.SetOpMode(SX127X_OPMODE_SLEEP)
|
||||
|
||||
d.SetHopPeriod(0x00)
|
||||
d.SetLowFrequencyModeOn(false) // High freq mode
|
||||
d.WriteRegister(SX127X_REG_PA_RAMP, (d.ReadRegister(SX127X_REG_PA_RAMP)&0xF0)|0x08) // set PA ramp-up time 50 uSec
|
||||
d.WriteRegister(SX127X_REG_LNA, SX127X_LNA_MAX_GAIN) // Set Low Noise Amplifier to MAX
|
||||
|
||||
d.SetLoraFrequency(d.loraConf.Freq)
|
||||
d.SetLoraPreamble(d.loraConf.Preamble) //OK
|
||||
d.SetLoraSyncWord(d.loraConf.SyncWord) // Should be ok
|
||||
d.SetLoraBandwidth(d.loraConf.Bw) // OK
|
||||
d.SetLoraSpreadingFactor(d.loraConf.Sf) // OK
|
||||
d.SetLoraIqMode(d.loraConf.Iq) //OK
|
||||
d.SetLoraCodingRate(d.loraConf.Cr)
|
||||
d.SetLoraCrc(d.loraConf.Crc == SX127X_LORA_CRC_ON)
|
||||
d.SetTxPower(10, true)
|
||||
d.SetLoraHeaderMode(d.loraConf.HeaderType)
|
||||
d.SetAgcAuto(SX127X_AGC_AUTO_ON)
|
||||
|
||||
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||
d.WriteRegister(SX127X_REG_DIO_MAPPING_1, SX127X_MAP_DIO0_LORA_TXDONE|SX127X_MAP_DIO1_LORA_NOP|SX127X_MAP_DIO2_LORA_NOP)
|
||||
// Clear all radio IRQ Flags
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS, 0xFF)
|
||||
// Mask all but TxDone
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS_MASK, ^SX127X_IRQ_LORA_TXDONE_MASK)
|
||||
|
||||
// initialize the payload size and address pointers
|
||||
d.WriteRegister(SX127X_REG_PAYLOAD_LENGTH, uint8(len(pkt)))
|
||||
d.WriteRegister(SX127X_REG_FIFO_TX_BASE_ADDR, 0)
|
||||
d.WriteRegister(SX127X_REG_FIFO_ADDR_PTR, 0)
|
||||
|
||||
// FIFO OPs cannot take place in Sleep mode !!!
|
||||
d.SetOpMode(SX127X_OPMODE_STANDBY)
|
||||
time.Sleep(time.Millisecond)
|
||||
// Copy payload to FIFO // TODO: Bulk
|
||||
for i := 0; i < len(pkt); i++ {
|
||||
d.WriteRegister(SX127X_REG_FIFO, pkt[i])
|
||||
}
|
||||
|
||||
// Enable TX
|
||||
d.SetOpMode(SX127X_OPMODE_TX)
|
||||
|
||||
msg := <-d.GetRadioEventChan()
|
||||
if msg.EventType != 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) {
|
||||
|
||||
if d.loraConf.Freq == 0 {
|
||||
return nil, errUndefinedLoraConf
|
||||
}
|
||||
|
||||
d.SetOpModeLora()
|
||||
d.SetOpMode(SX127X_OPMODE_SLEEP)
|
||||
|
||||
d.SetHopPeriod(0x00)
|
||||
d.SetLowFrequencyModeOn(false) // High freq mode
|
||||
d.WriteRegister(SX127X_REG_PA_RAMP, (d.ReadRegister(SX127X_REG_PA_RAMP)&0xF0)|0x08) // set PA ramp-up time 50 uSec
|
||||
d.WriteRegister(SX127X_REG_LNA, SX127X_LNA_MAX_GAIN) // Set Low Noise Amplifier to MAX
|
||||
|
||||
d.SetLoraFrequency(d.loraConf.Freq)
|
||||
d.SetLoraPreamble(d.loraConf.Preamble) //OK
|
||||
d.SetLoraSyncWord(d.loraConf.SyncWord) // Should be ok
|
||||
d.SetLoraBandwidth(d.loraConf.Bw) // OK
|
||||
d.SetLoraSpreadingFactor(d.loraConf.Sf) // OK
|
||||
d.SetLoraIqMode(d.loraConf.Iq) //OK
|
||||
d.SetLoraCodingRate(d.loraConf.Cr)
|
||||
d.SetLoraCrc(d.loraConf.Crc == SX127X_LORA_CRC_ON)
|
||||
d.SetTxPower(10, true)
|
||||
d.SetLoraHeaderMode(d.loraConf.HeaderType)
|
||||
d.SetAgcAuto(SX127X_AGC_AUTO_ON)
|
||||
|
||||
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||
d.WriteRegister(SX127X_REG_DIO_MAPPING_1, SX127X_MAP_DIO0_LORA_RXDONE|SX127X_MAP_DIO1_LORA_NOP|SX127X_MAP_DIO2_LORA_NOP)
|
||||
// Clear all radio IRQ Flags
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS, 0xFF)
|
||||
// Mask all but TxDone
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS_MASK, ^SX127X_IRQ_LORA_RXDONE_MASK)
|
||||
// Switch to RX Mode
|
||||
d.SetOpMode(SX127X_OPMODE_RX)
|
||||
// Wait for Radio Event
|
||||
|
||||
radioCh := d.GetRadioEventChan()
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * time.Duration(timeoutMs))
|
||||
radioCh <- NewRadioEvent(RadioEventTimeout, SX127X_IRQ_LORA_RXTOUT_MASK, nil)
|
||||
}()
|
||||
|
||||
msg := <-radioCh
|
||||
if msg.EventType == RadioEventTimeout {
|
||||
return nil, nil
|
||||
} else if msg.EventType != RadioEventRxDone {
|
||||
return nil, errors.New("Unexpected Radio Event while RX")
|
||||
}
|
||||
|
||||
d.WriteRegister(SX127X_REG_FIFO_RX_BASE_ADDR, 0)
|
||||
d.WriteRegister(SX127X_REG_FIFO_ADDR_PTR, 0)
|
||||
|
||||
pLen := d.ReadRegister(SX127X_REG_RX_NB_BYTES)
|
||||
d.WriteRegister(SX127X_REG_FIFO_ADDR_PTR, d.ReadRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR))
|
||||
|
||||
for i := uint8(0); i < pLen; i++ {
|
||||
d.spiBuffer[i] = d.ReadRegister(SX127X_REG_FIFO)
|
||||
}
|
||||
return d.spiBuffer[:pLen], nil
|
||||
}
|
||||
|
||||
//
|
||||
// HELPER FUNCTIONS
|
||||
//
|
||||
|
||||
// PrintRegisters outputs the sx127x transceiver registers
|
||||
func (d *Device) PrintRegisters(compact bool) {
|
||||
for i := uint8(0); i < 128; i++ {
|
||||
@@ -643,3 +496,45 @@ func (d *Device) PrintRegisters(compact bool) {
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
// PrintRegisters outputs the sx127x transceiver registers
|
||||
func (d *Device) RandomU32() uint32 {
|
||||
// Disable ALL irqs
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS, 0xFF)
|
||||
d.SetOpModeLora()
|
||||
d.SetOpMode(SX127X_OPMODE_SLEEP)
|
||||
d.SetLoraFrequency(d.loraConf.Freq)
|
||||
d.SetOpMode(SX127X_OPMODE_RX)
|
||||
rnd := uint32(0)
|
||||
for i := 0; i < 32; i++ {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
// Unfiltered RSSI value reading. Only takes the LSB value
|
||||
rnd |= (uint32(d.ReadRegister(SX127X_REG_RSSI_WIDEBAND)) & 0x01) << i
|
||||
}
|
||||
return rnd
|
||||
}
|
||||
|
||||
// HandleInterrupt must be called by main code on DIO state change.
|
||||
func (d *Device) HandleInterrupt() {
|
||||
// Get IRQ and clear
|
||||
st := d.ReadRegister(SX127X_REG_IRQ_FLAGS)
|
||||
d.WriteRegister(SX127X_REG_IRQ_FLAGS, 0xFF)
|
||||
|
||||
rChan := d.GetRadioEventChan()
|
||||
|
||||
if (st & SX127X_IRQ_LORA_RXDONE_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventRxDone, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX127X_IRQ_LORA_TXDONE_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTxDone, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX127X_IRQ_LORA_RXTOUT_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventTimeout, st, nil)
|
||||
}
|
||||
|
||||
if (st & SX127X_IRQ_LORA_CRCERR_MASK) > 0 {
|
||||
rChan <- NewRadioEvent(RadioEventCrcError, st, nil)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user