package sx127x import ( "bytes" "fmt" "github.com/soypat/lora" ) const ( // 32MHz frequency for crystal oscillator is typical. fXOSC = 32_000_000 // PLL uses a 19-bit sigma-delta modulator whose frequency resolution, constant over the whole frequency range, is given by fSTEP = fXOSC / (1 << 19) ) type irqFlagPos uint8 const ( irqPosCADDetected irqFlagPos = iota irqPosFHSSChange irqPosCADDone irqPosTxDone irqPosValidHeader irqPosPayloadCRC irqPosRxDone irqPosRxTimeout ) func (pos irqFlagPos) String() (str string) { switch pos { case irqPosCADDetected: str = "CADDetected" case irqPosFHSSChange: str = "FHSSChange" case irqPosCADDone: str = "CADDone" case irqPosTxDone: str = "TxDone" case irqPosValidHeader: str = "ValidHeader" case irqPosPayloadCRC: str = "CRCError" case irqPosRxDone: str = "RxDone" case irqPosRxTimeout: str = "RxTimeout" default: str = "UnknownIRQ" } return str } func irqFlagsString(irqFlags uint8) (str string) { if irqFlags == 0 { return "[]" } str = "[" for i := irqFlagPos(0); i < 8; i++ { if irqFlags&(1<= 0; i-- { if bandwidth >= bandwidths[i] { value = i break } } return value } func reg2Bw(bwByte byte) (value lora.Frequency) { if bwByte > byte(len(bandwidths)-1) { return 0 } return bandwidths[bwByte] } // Operation modes. const ( opmMASK uint8 = 0x07 opmSLEEP uint8 = 0x00 opmSTANDBY uint8 = 0x01 opmFSTX uint8 = 0x02 opmTX uint8 = 0x03 opmFSRX uint8 = 0x04 opmRX uint8 = 0x05 opmRX_SINGLE uint8 = 0x06 opmCAD uint8 = 0x07 opmLORA uint8 = 0x80 ) // OpMode represents the available operation modes of the SX127x devices. type OpMode uint8 // LoRa Operation modes. const ( // Sleep mode will sleep goroutine for 15ms on SetOpmode call. OpSleep OpMode = iota // Standby mode is the default mode when waiting to operate. OpStandby // Frequency synthesis TX (FSTX) OpFSTx // Transmit (TX) OpTx // Frequency synthesis RX (FSRX) OpFSRx // Receive continuous (RXCONTINUOUS) OpRx // receive single (RXSINGLE) OpRxSingle // Channel activity detection (CAD) OpCAD opLoRaBit = OpMode(1 << 7) ) func (op OpMode) String() (s string) { op = op &^ opLoRaBit switch op { case OpSleep: s = "sleep" case OpStandby: s = "standby" case OpFSTx: s = "fstx" case OpTx: s = "tx" case OpFSRx: s = "fsrx" case OpRx: s = "rx" case OpRxSingle: s = "rx-single" case OpCAD: s = "cad" default: s = "unknown" } return s } func (d *DeviceLoRa) statusString() string { irq, _ := d.read8(regIRQ_FLAGS) opmode, err := d.GetOpMode() return fmt.Sprintf("opmode: %s; operr=%v; irq: %08b=%s;%s", opmode.String(), err, irq, irqFlagsString(irq), d.debugRegString()) } func (d *DeviceLoRa) wrapErr(err error) error { if err == nil { return nil } return fmt.Errorf("stat=%s: %w", d.statusString(), err) } func (d *DeviceLoRa) debugForEachTouchedReg(fn func(addr, mask, read, write uint8)) { for addr := uint8(0); addr < debugBufSize; addr++ { mask := d.debugMask[addr] read := d.debugRead[addr] write := d.debugWrite[addr] fn(addr, mask, read, write) } } func (d *DeviceLoRa) debugRegString() string { var buf bytes.Buffer d.debugForEachTouchedReg(func(addr, mask, read, write uint8) { rm := read & mask wm := write & mask if rm == wm { return } regstr := regstr(addr).String() fmt.Fprintf(&buf, "0x%02X(%s): mask=%08b, read=0x%0x, write=0x%0x\n", addr, regstr, mask, read, write) }) return buf.String() }