diff --git a/sx126x/sx126x.go b/sx126x/sx126x.go index 653c715..db814a0 100644 --- a/sx126x/sx126x.go +++ b/sx126x/sx126x.go @@ -34,8 +34,9 @@ const ( ) const ( - PERIOD_PER_SEC = (uint32)(1000000 / 15.625) // SX1261 DS 13.1.4 - SPI_BUFFER_SIZE = 256 + PERIOD_PER_SEC = (uint32)(1000000 / 15.625) // SX1261 DS 13.1.4 + SPI_BUFFER_SIZE = 256 + RADIOEVENTCHAN_SIZE = 1 ) // Device wraps an SPI connection to a SX126x device. @@ -47,14 +48,18 @@ type Device struct { controller RadioController // to manage interactions with the radio deepSleep bool // Internal Sleep state deviceType int // sx1261,sx1262,sx1268 (defaults sx1261) - spiBuffer [SPI_BUFFER_SIZE]uint8 + spiTxBuf []byte // global Tx buffer to avoid heap allocations in interrupt + spiRxBuf []byte // global Rx buffer to avoid heap allocations in interrupt + } // New creates a new SX126x connection. func New(spi drivers.SPI) *Device { return &Device{ spi: spi, - radioEventChan: make(chan lora.RadioEvent, 10), + radioEventChan: make(chan lora.RadioEvent, RADIOEVENTCHAN_SIZE), + spiTxBuf: make([]byte, SPI_BUFFER_SIZE), + spiRxBuf: make([]byte, SPI_BUFFER_SIZE), } } @@ -250,21 +255,25 @@ func (d *Device) ReadRegister(addr, size uint16) ([]uint8, error) { d.CheckDeviceReady() d.controller.SetNss(false) // Send command - cmd := []uint8{SX126X_CMD_READ_REGISTER, uint8((addr & 0xFF00) >> 8), uint8(addr & 0x00FF), 0x00} - d.spi.Tx(cmd, nil) - ret := d.spiBuffer[0:size] - d.spi.Tx(nil, ret) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, SX126X_CMD_READ_REGISTER, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF), 0x00) + d.spi.Tx(d.spiTxBuf, nil) + // Read registers + d.spiRxBuf = d.spiRxBuf[0:size] + d.spi.Tx(nil, d.spiRxBuf) d.controller.SetNss(true) d.controller.WaitWhileBusy() - return ret, nil + return d.spiRxBuf, nil } // WriteRegister writes value to register func (d *Device) WriteRegister(addr uint16, data []uint8) { d.CheckDeviceReady() d.controller.SetNss(false) - cmd := []uint8{SX126X_CMD_WRITE_REGISTER, uint8((addr & 0xFF00) >> 8), uint8(addr & 0x00FF)} - d.spi.Tx(append(cmd, data...), nil) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, SX126X_CMD_WRITE_REGISTER, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, data...) + d.spi.Tx(d.spiTxBuf, nil) d.controller.SetNss(true) d.controller.WaitWhileBusy() } @@ -497,7 +506,10 @@ func (d *Device) ExecSetCommand(cmd uint8, buf []uint8) { } d.controller.SetNss(false) // Send command and params - d.spi.Tx(append([]uint8{cmd}, buf...), nil) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, cmd) + d.spiTxBuf = append(d.spiTxBuf, buf...) + d.spi.Tx(d.spiTxBuf, nil) d.controller.SetNss(true) if cmd != SX126X_CMD_SET_SLEEP { d.controller.WaitWhileBusy() @@ -509,11 +521,15 @@ func (d *Device) ExecGetCommand(cmd uint8, size uint8) []uint8 { d.CheckDeviceReady() d.controller.SetNss(false) // Send the command and flush first status byte (as not used) - d.spi.Tx([]uint8{cmd, 0x00}, nil) - d.spi.Tx(nil, d.spiBuffer[:size]) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, cmd, 0x00) + d.spi.Tx(d.spiTxBuf, nil) + // Read resp + d.spiRxBuf = d.spiRxBuf[:size] + d.spi.Tx(nil, d.spiRxBuf) d.controller.SetNss(true) d.controller.WaitWhileBusy() - return d.spiBuffer[:size] + return d.spiRxBuf } // @@ -685,22 +701,26 @@ func (d *Device) HandleInterrupt() { st := d.GetIrqStatus() d.ClearIrqStatus(SX126X_IRQ_ALL) - rChan := d.GetRadioEventChan() - if (st & SX126X_IRQ_RX_DONE) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventRxDone, st, nil) + e := lora.RadioEvent{lora.RadioEventRxDone, uint16(st), nil} + d.radioEventChan <- e } if (st & SX126X_IRQ_TX_DONE) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventTxDone, st, nil) + e := lora.RadioEvent{lora.RadioEventTxDone, uint16(st), nil} + d.radioEventChan <- e } if (st & SX126X_IRQ_TIMEOUT) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventTimeout, st, nil) + e := lora.RadioEvent{lora.RadioEventTimeout, uint16(st), nil} + d.radioEventChan <- e + } if (st & SX126X_IRQ_CRC_ERR) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventCrcError, st, nil) + e := lora.RadioEvent{lora.RadioEventCrcError, uint16(st), nil} + d.radioEventChan <- e + } } diff --git a/sx127x/sx127x.go b/sx127x/sx127x.go index 1753149..60d5b44 100644 --- a/sx127x/sx127x.go +++ b/sx127x/sx127x.go @@ -15,7 +15,8 @@ import ( // So we can keep track of the origin of interruption const ( - SPI_BUFFER_SIZE = 256 + RADIOEVENTCHAN_SIZE = 1 + SPI_BUFFER_SIZE = 256 ) // Device wraps an SPI connection to a SX127x device. @@ -27,8 +28,8 @@ type Device struct { controller RadioController // to manage interactions with the radio deepSleep bool // Internal Sleep state deviceType int // sx1261,sx1262,sx1268 (defaults sx1261) - spiBuffer [SPI_BUFFER_SIZE]uint8 - packetIndex uint8 // FIXME ... useless ? + spiTxBuf []byte // global Tx buffer to avoid heap allocations in interrupt + spiRxBuf []byte // global Rx buffer to avoid heap allocations in interrupt } // -------------------------------------------------- @@ -46,7 +47,9 @@ func New(spi machine.SPI, rstPin machine.Pin) *Device { k := Device{ spi: spi, rstPin: rstPin, - radioEventChan: make(chan lora.RadioEvent, 10), + radioEventChan: make(chan lora.RadioEvent, RADIOEVENTCHAN_SIZE), + spiTxBuf: make([]byte, SPI_BUFFER_SIZE), + spiRxBuf: make([]byte, SPI_BUFFER_SIZE), } return &k } @@ -79,21 +82,37 @@ func (d *Device) DetectDevice() bool { // ReadRegister reads register value func (d *Device) ReadRegister(reg uint8) uint8 { d.controller.SetNss(false) - d.spi.Tx([]byte{reg & 0x7f}, nil) - var value [1]byte - d.spi.Tx(nil, value[:]) + // Send register + //d.spiTxBuf = []byte{reg & 0x7f} + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, byte(reg&0x7f)) + //println("R1 : ", len(d.spiTxBuf)) + d.spi.Tx(d.spiTxBuf, nil) + // Read value + //d.spiRxBuf = []byte{reg & 0x00} + d.spiRxBuf = d.spiRxBuf[:0] + d.spiRxBuf = append(d.spiRxBuf, 0) + //println("R2 : ", len(d.spiTxBuf)) + d.spi.Tx(nil, d.spiRxBuf) d.controller.SetNss(true) - return value[0] + return d.spiRxBuf[0] } // WriteRegister writes value to register func (d *Device) WriteRegister(reg uint8, value uint8) uint8 { - var response [1]byte d.controller.SetNss(false) - d.spi.Tx([]byte{reg | 0x80}, nil) - d.spi.Tx([]byte{value}, response[:]) + // Send register + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, byte(reg|0x80)) + d.spi.Tx(d.spiTxBuf, nil) + // Send value + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, byte(value)) + d.spiRxBuf = d.spiRxBuf[:0] + d.spiRxBuf = append(d.spiRxBuf, 0) + d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.controller.SetNss(true) - return response[0] + return d.spiRxBuf[0] } // SetOpMode changes the sx1276 mode @@ -434,16 +453,13 @@ func (d *Device) Rx(timeoutMs uint32) ([]uint8, error) { // Mask all but RxDone d.WriteRegister(SX127X_REG_IRQ_FLAGS_MASK, ^(SX127X_IRQ_LORA_RXDONE_MASK | SX127X_IRQ_LORA_RXTOUT_MASK)) - // Get Radio Event Channel - radioCh := d.GetRadioEventChan() - // Single RX mode don't properly handle Timeouts on sx127x, so we use Continuous RX // Go routine is a workaround to stop the Continuous RX and fire a timeout Event d.SetOpMode(SX127X_OPMODE_RX) var msg lora.RadioEvent select { - case msg = <-radioCh: + case msg = <-d.radioEventChan: if msg.EventType != lora.RadioEventRxDone { return nil, errors.New("Unexpected Radio Event while RX " + string(0x30+msg.EventType)) } @@ -459,10 +475,11 @@ func (d *Device) Rx(timeoutMs uint32) ([]uint8, error) { pLen := d.ReadRegister(SX127X_REG_RX_NB_BYTES) d.WriteRegister(SX127X_REG_FIFO_ADDR_PTR, d.ReadRegister(SX127X_REG_FIFO_RX_CURRENT_ADDR)) + rxData := []uint8{} for i := uint8(0); i < pLen; i++ { - d.spiBuffer[i] = d.ReadRegister(SX127X_REG_FIFO) + rxData = append(rxData, d.ReadRegister(SX127X_REG_FIFO)) } - return d.spiBuffer[:pLen], nil + return rxData, nil } // SetTxContinuousMode enable Continuous Tx mode @@ -506,26 +523,35 @@ func (d *Device) RandomU32() uint32 { // 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 <- lora.NewRadioEvent(lora.RadioEventRxDone, uint16(st), nil) + e := lora.RadioEvent{lora.RadioEventRxDone, uint16(st), nil} + d.radioEventChan <- e } if (st & SX127X_IRQ_LORA_TXDONE_MASK) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventTxDone, uint16(st), nil) + e := lora.RadioEvent{lora.RadioEventTxDone, uint16(st), nil} + d.radioEventChan <- e } if (st & SX127X_IRQ_LORA_RXTOUT_MASK) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventTimeout, uint16(st), nil) + e := lora.RadioEvent{lora.RadioEventTimeout, uint16(st), nil} + select { + case d.radioEventChan <- e: + default: + } } if (st & SX127X_IRQ_LORA_CRCERR_MASK) > 0 { - rChan <- lora.NewRadioEvent(lora.RadioEventCrcError, uint16(st), nil) + e := lora.RadioEvent{lora.RadioEventCrcError, uint16(st), nil} + select { + case d.radioEventChan <- e: + default: + } } }