diff --git a/examples/sx127x/lora_rxtx/lora_rxtx.go b/examples/sx127x/lora_rxtx/lora_rxtx.go index 55a1edf..dcc45d5 100644 --- a/examples/sx127x/lora_rxtx/lora_rxtx.go +++ b/examples/sx127x/lora_rxtx/lora_rxtx.go @@ -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++ + } + } diff --git a/sx127x/registers.go b/sx127x/registers.go index d025077..4df39b5 100644 --- a/sx127x/registers.go +++ b/sx127x/registers.go @@ -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) diff --git a/sx127x/sx127x.go b/sx127x/sx127x.go index 0946050..361d56e 100644 --- a/sx127x/sx127x.go +++ b/sx127x/sx127x.go @@ -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) + } +}