mirror of
https://github.com/soypat/lora.git
synced 2026-08-27 07:28:59 +00:00
attempt RxSingle routine
This commit is contained in:
@@ -51,20 +51,27 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
println("config success")
|
|
||||||
for {
|
|
||||||
rssiRead, err := dev.EstimateReadFromRSSIPeriod(time.Second)
|
|
||||||
if err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
println("rssiRead:", rssiRead.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
tstart := time.Now()
|
randomU32, _ := dev.RandomU32()
|
||||||
var rng [4]byte
|
myName := fmt.Sprintf("user-%x", randomU32%0xffff)
|
||||||
err = dev.RandomRead(rng[:], 0)
|
println("config success; sending messages as ", myName)
|
||||||
if err != nil {
|
var rx [256]byte
|
||||||
panic(err.Error())
|
packet := []byte(myName + " says hello!")
|
||||||
|
for {
|
||||||
|
err = dev.Tx(packet)
|
||||||
|
if err != nil {
|
||||||
|
println("got error transmitting:", err.Error())
|
||||||
|
} else {
|
||||||
|
print(".")
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
for i := 0; i < 6; i++ {
|
||||||
|
n, err := dev.RxSingle(rx[:])
|
||||||
|
if err != nil {
|
||||||
|
println("rx error:", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
println("got message: ", string(rx[:n]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("random bytes: %b\nelapsed:%s\n", rng, time.Since(tstart).String())
|
|
||||||
}
|
}
|
||||||
|
|||||||
+100
-13
@@ -84,6 +84,9 @@ var (
|
|||||||
errBadCodingRate = errors.New("bad coding rate")
|
errBadCodingRate = errors.New("bad coding rate")
|
||||||
errUnsupportedBandwidth = errors.New("bandwidth too high for frequency around 169MHz")
|
errUnsupportedBandwidth = errors.New("bandwidth too high for frequency around 169MHz")
|
||||||
errIRQNotCleared = errors.New("IRQs not cleared")
|
errIRQNotCleared = errors.New("IRQs not cleared")
|
||||||
|
ErrDeviceBusy = errors.New("device busy")
|
||||||
|
ErrCRC = errors.New("crc error")
|
||||||
|
ErrRxTimeout = errors.New("rx timeout")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
|
func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
|
||||||
@@ -250,6 +253,7 @@ func (d *DeviceLoRa) EnableAutoGainControl(b bool) error {
|
|||||||
return d.writeMasked8(regMODEM_CONFIG_3, agcMask, b2u8(b)<<2)
|
return d.writeMasked8(regMODEM_CONFIG_3, agcMask, b2u8(b)<<2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tx sends packet over LoRa network and blocks until packet is done sending.
|
||||||
func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
||||||
if len(packet) > 255 {
|
if len(packet) > 255 {
|
||||||
return errors.New("packet too long")
|
return errors.New("packet too long")
|
||||||
@@ -291,18 +295,19 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
counts := 0
|
var irq uint8
|
||||||
var reg uint8
|
for irq&irqTXDONE_MASK == 0 {
|
||||||
for {
|
|
||||||
counts++
|
|
||||||
reg, err = d.read8(regIRQ_FLAGS)
|
|
||||||
if reg&irqTXDONE_MASK != 0 || err != nil {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
runtime.Gosched() // Yield to scheduler.
|
runtime.Gosched() // Yield to scheduler.
|
||||||
|
irq, err = d.read8(regIRQ_FLAGS)
|
||||||
|
if err != nil {
|
||||||
|
d.SetOpMode(OpSleep) // Back to sleep in case of error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Go back to sleep to be able to write to static registers.
|
||||||
|
err = d.SetOpMode(OpSleep)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
err = d.clearIRQ(irqTXDONE_MASK)
|
err = d.clearIRQ(irqTXDONE_MASK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -311,6 +316,84 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DeviceLoRa) RxSingle(dst []byte) (uint8, error) {
|
||||||
|
op, err := d.GetOpMode()
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
// err already set
|
||||||
|
case len(dst) < 255:
|
||||||
|
err = io.ErrShortBuffer
|
||||||
|
case op == OpTx || op == OpRx || op == OpRxSingle:
|
||||||
|
err = ErrDeviceBusy // Device is currently transmitting or receiving.
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// Reset packet pointers.
|
||||||
|
const fifoAddr = 0
|
||||||
|
err = d.prepareForRx(fifoAddr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// Begin looking for packets immediately until first one found (RxSingle mode).
|
||||||
|
err = d.SetOpMode(OpRxSingle)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer d.SetOpMode(OpSleep) // Ensure Sleep Mode on exit.
|
||||||
|
|
||||||
|
// Loop until Rx received or timeout IRQ.
|
||||||
|
var irq uint8
|
||||||
|
for irq&(irqRXDONE_MASK|irqRXTOUT_MASK) == 0 {
|
||||||
|
runtime.Gosched() // Yield to scheduler.
|
||||||
|
irq, err = d.read8(regIRQ_FLAGS)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for payload integrity and timeout interrupt.
|
||||||
|
if irq&irqCRCERR_MASK != 0 {
|
||||||
|
return 0, ErrCRC
|
||||||
|
} else if irq&irqRXTOUT_MASK != 0 {
|
||||||
|
return 0, ErrRxTimeout
|
||||||
|
}
|
||||||
|
// TODO(soypat): This should already be in standby mode according to datasheet.
|
||||||
|
// remove once confirmed it does not affect behaviour. Needed to read FIFO addr.
|
||||||
|
err = d.SetOpMode(OpStandby)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// Ready to read packet! Rewrite FifoAddrPtr just in case...
|
||||||
|
d.write8(regFIFO_ADDR_PTR, fifoAddr)
|
||||||
|
nbBytes, err := d.read8(regRX_NB_BYTES)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for i := uint8(0); i < nbBytes; i++ {
|
||||||
|
dst[i], err = d.read8(regFIFO)
|
||||||
|
if err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nbBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeviceLoRa) prepareForRx(fifoAddr uint8) (err error) {
|
||||||
|
err = d.SetOpMode(OpStandby) // Standby mode needed so that FIFO can be written/read.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.clearIRQ(irqRXDONE_MASK | irqHEADER_MASK | irqCRCERR_MASK | irqRXTOUT_MASK)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.write8(regFIFO_RX_BASE_ADDR, fifoAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return d.write8(regFIFO_ADDR_PTR, fifoAddr)
|
||||||
|
}
|
||||||
|
|
||||||
// clearIRQ clears IRQ bits indicated by toClear:
|
// clearIRQ clears IRQ bits indicated by toClear:
|
||||||
// - bit 0: CAD detected interrupt
|
// - bit 0: CAD detected interrupt
|
||||||
// - bit 1: FHSS change channel interrupt
|
// - bit 1: FHSS change channel interrupt
|
||||||
@@ -325,8 +408,10 @@ func (d *DeviceLoRa) clearIRQ(toClear uint8) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
reg, _ := d.read8(regIRQ_FLAGS)
|
reg, _ := d.read8(regIRQ_FLAGS)
|
||||||
if reg&toClear != 0 {
|
if reg&toClear != 0 {
|
||||||
|
println(reg, toClear)
|
||||||
return errIRQNotCleared
|
return errIRQNotCleared
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -347,6 +432,8 @@ func (d *DeviceLoRa) RandomU32() (rnd uint32, err error) {
|
|||||||
// The period between RSSI reads is readFromRSSIPeriod. A higher readFromRSSIPeriod
|
// The period between RSSI reads is readFromRSSIPeriod. A higher readFromRSSIPeriod
|
||||||
// will typically result in higher entropy in the random data. 10ms is a reasonable period.
|
// will typically result in higher entropy in the random data. 10ms is a reasonable period.
|
||||||
// This method will take approximately readFromRSSIPeriod*len(dst)*8 + 50ms to complete.
|
// This method will take approximately readFromRSSIPeriod*len(dst)*8 + 50ms to complete.
|
||||||
|
//
|
||||||
|
// See EstimateReadFromRSSIPeriod method.
|
||||||
func (d *DeviceLoRa) RandomRead(dst []byte, readFromRSSIPeriod time.Duration) error {
|
func (d *DeviceLoRa) RandomRead(dst []byte, readFromRSSIPeriod time.Duration) error {
|
||||||
// Disable ALL irqs
|
// Disable ALL irqs
|
||||||
err := d.clearIRQ(0xff)
|
err := d.clearIRQ(0xff)
|
||||||
@@ -596,8 +683,8 @@ func (d *DeviceLoRa) enableCRC(b bool) error {
|
|||||||
//
|
//
|
||||||
// Timeout = timeoutSymbols * Ts (where Ts is the symbol period)
|
// Timeout = timeoutSymbols * Ts (where Ts is the symbol period)
|
||||||
func (d *DeviceLoRa) setTimeoutInSymbols(symbTimeout uint16) (err error) {
|
func (d *DeviceLoRa) setTimeoutInSymbols(symbTimeout uint16) (err error) {
|
||||||
if symbTimeout > 0x3FF {
|
if symbTimeout > 0x3FF || symbTimeout < 4 {
|
||||||
return errors.New("timeout value too large")
|
return errors.New("symbol timeout must be in range 4..1023")
|
||||||
}
|
}
|
||||||
err = d.writeMasked8(regMODEM_CONFIG_2, 0b11, byte(symbTimeout>>8))
|
err = d.writeMasked8(regMODEM_CONFIG_2, 0b11, byte(symbTimeout>>8))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user