From 20b0985bc2716d79422367189e95f3c1312f5e17 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sat, 25 Apr 2026 11:01:05 -0500 Subject: [PATCH 01/11] add SPI driver for semtech sx128x chips Co-authored-by: Copilot --- sx128x/README.md | 7 + sx128x/registers.go | 244 ++++++++++++++++++++ sx128x/sx128x.go | 533 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 784 insertions(+) create mode 100644 sx128x/README.md create mode 100644 sx128x/registers.go create mode 100644 sx128x/sx128x.go diff --git a/sx128x/README.md b/sx128x/README.md new file mode 100644 index 000000000..1dd0198f2 --- /dev/null +++ b/sx128x/README.md @@ -0,0 +1,7 @@ +# SX128x Radio +Radio from Semtech in the 2.4 GHz band. This driver uses SPI to communicate with the radio instead of the alternative UART interface. + +## Supported Chips +- [SX1280](https://www.semtech.com/products/wireless-rf/lora-connect/sx1280) +- [SX1281](https://www.semtech.com/products/wireless-rf/lora-connect/sx1281) + diff --git a/sx128x/registers.go b/sx128x/registers.go new file mode 100644 index 000000000..eaa7b58fb --- /dev/null +++ b/sx128x/registers.go @@ -0,0 +1,244 @@ +package sx128x + +const ( + // SX128X SPI commands + CMD_NOP = uint8(0x00) + + CMD_SET_UART_SPEED = uint8(0x9D) + CMD_GET_STATUS = uint8(0xC0) + + // Register Access Operations + CMD_WRITE_REGISTER = uint8(0x18) + CMD_READ_REGISTER = uint8(0x19) + + // Data Buffer Operations + CMD_WRITE_BUFFER = uint8(0x1A) + CMD_READ_BUFFER = uint8(0x1B) + + // Radio Operation Modes + CMD_SET_SLEEP = uint8(0x84) + CMD_SET_STANDBY = uint8(0x80) + CMD_SET_FS = uint8(0xC1) + CMD_SET_TX = uint8(0x83) + CMD_SET_RX = uint8(0x82) + CMD_SET_RX_DUTY_CYCLE = uint8(0x94) + CMD_SET_LONG_PREAMBLE = uint8(0x9B) + CMD_SET_CAD = uint8(0xC5) + CMD_SET_TX_CONTINUOUS_WAVE = uint8(0xD1) + CMD_SET_TX_CONTINUOUS_PREAMBLE = uint8(0xD2) + CMD_SET_AUTO_TX = uint8(0x98) + CMD_SET_AUTO_FS = uint8(0x9E) + + // Radio Configuration + CMD_SET_PACKET_TYPE = uint8(0x8A) + CMD_GET_PACKET_TYPE = uint8(0x03) + CMD_SET_RF_FREQUENCY = uint8(0x86) + CMD_SET_TX_PARAMS = uint8(0x8E) + CMD_SET_CAD_PARAMS = uint8(0x88) + CMD_SET_BUFFER_BASE_ADDRESS = uint8(0x8F) + CMD_SET_MODULATION_PARAMS = uint8(0x8B) + CMD_SET_PACKET_PARAMS = uint8(0x8C) + + // Communication Status Information + CMD_GET_RX_BUFFER_STATUS = uint8(0x17) + CMD_GET_PACKET_STATUS = uint8(0x1D) + CMD_GET_RSSI_INST = uint8(0x1F) + + // IRQ Handling + CMD_SET_DIO_IRQ_PARAMS = uint8(0x8D) + CMD_GET_IRQ_STATUS = uint8(0x15) + CMD_CLEAR_IRQ_STATUS = uint8(0x97) + + // Miscellaneous + CMD_SET_REGULATOR_MODE = uint8(0x96) + CMD_SET_SAVE_CONTEXT = uint8(0xD5) + + // GetStatus + CIRCUIT_MODE_MASK = uint8(0b11100000) + CIRCUIT_MODE_STDBY_RC = uint8(0x2) + CIRCUIT_MODE_STDBY_XOSC = uint8(0x3) + CIRCUIT_MODE_FS = uint8(0x4) + CIRCUIT_MODE_RX = uint8(0x5) + CIRCUIT_MODE_TX = uint8(0x6) + + COMMAND_STATUS_MASK = uint8(0b00011100) + COMMAND_STATUS_SUCCESS = uint8(0x1) + COMMAND_STATUS_DATA_AVAILABLE = uint8(0x2) + COMMAND_STATUS_TIMEOUT = uint8(0x3) + COMMAND_STATUS_PROCESSING_ERROR = uint8(0x4) + COMMAND_STATUS_EXECUTION_ERROR = uint8(0x5) + COMMAND_STATUS_TX_DONE = uint8(0x6) + + // SleepConfig + SLEEP_DATA_BUFFER_RETAIN = uint8(2) + SLEEP_DATA_RAM_RETAIN = uint8(1) + + // StandbyConfig + STANDBY_RC = uint8(0) + STANDBY_XOSC = uint8(1) + + // PeriodBase + PERIOD_BASE_15_625_US = uint8(0) + PERIOD_BASE_62_5_US = uint8(1) + PERIOD_BASE_1_MS = uint8(2) + PERIOD_BASE_4_MS = uint8(3) + + RX_CONTINUOUS_MODE = uint16(0xFFFF) + + // LongPreamble + LONG_PREAMBLE_ENABLE = uint8(1) + LONG_PREAMBLE_DISABLE = uint8(0) + + // AutoFs + AUTO_FS_ENABLE = uint8(1) + AUTO_FS_DISABLE = uint8(0) + + // PacketType + PACKET_TYPE_GFSK = uint8(0x00) // default + PACKET_TYPE_LORA = uint8(0x01) + PACKET_TYPE_RANGING = uint8(0x02) + PACKET_TYPE_FLRC = uint8(0x03) + PACKET_TYPE_BLE = uint8(0x04) + + // RampTime + RADIO_RAMP_02_US = uint8(0x00) + RADIO_RAMP_04_US = uint8(0x20) + RADIO_RAMP_06_US = uint8(0x40) + RADIO_RAMP_08_US = uint8(0x60) + RADIO_RAMP_10_US = uint8(0x80) + RADIO_RAMP_12_US = uint8(0xA0) + RADIO_RAMP_16_US = uint8(0xC0) + RADIO_RAMP_20_US = uint8(0xE0) + + // CadSymbolNum + LORA_CAD_01_SYMBOL = uint8(0x00) + LORA_CAD_02_SYMBOLS = uint8(0x20) + LORA_CAD_04_SYMBOLS = uint8(0x40) + LORA_CAD_08_SYMBOLS = uint8(0x60) + LORA_CAD_16_SYMBOLS = uint8(0x80) + + // SpreadingFactor + LORA_SF_5 = uint8(0x50) + LORA_SF_6 = uint8(0x60) + LORA_SF_7 = uint8(0x70) + LORA_SF_8 = uint8(0x80) + LORA_SF_9 = uint8(0x90) + LORA_SF_10 = uint8(0xA0) + LORA_SF_11 = uint8(0xB0) + LORA_SF_12 = uint8(0xC0) + + // Bandwidth + LORA_BW_1600 = uint8(0x0A) + LORA_BW_800 = uint8(0x18) + LORA_BW_400 = uint8(0x26) + LORA_BW_200 = uint8(0x34) + + // CodingRate + LORA_CR_4_5 = uint8(0x01) + LORA_CR_4_6 = uint8(0x02) + LORA_CR_4_7 = uint8(0x03) + LORA_CR_4_8 = uint8(0x04) + LORA_CR_LI_4_5 = uint8(0x05) + LORA_CR_LI_4_6 = uint8(0x06) + LORA_CR_LI_4_8 = uint8(0x07) + + // LoraPacketParams + LORA_EXPLICIT_HEADER = uint8(0x00) + LORA_IMPLICIT_HEADER = uint8(0x80) + + LORA_CRC_ENABLE = uint8(0x20) + LORA_CRC_DISABLE = uint8(0x00) + + LORA_IQ_INVERTED = uint8(0x00) + LORA_IQ_STD = uint8(0x40) + + // RegulatorMode + REGULATOR_LDO = uint8(0) + REGULATOR_DC_DC = uint8(1) + + // IRQ masks + IRQ_ALL_MASK = uint16(0xFFFF) + IRQ_NONE_MASK = uint16(0x0000) + IRQ_TX_DONE_MASK = uint16(0b0000000000000001) + IRQ_RX_DONE_MASK = uint16(0b0000000000000010) + IRQ_SYNC_WORD_VALID_MASK = uint16(0b0000000000000100) + IRQ_SYNC_WORD_ERROR_MASK = uint16(0b0000000000001000) + IRQ_HEADER_VALID_MASK = uint16(0b0000000000010000) + IRQ_HEADER_ERROR_MASK = uint16(0b0000000000100000) + IRQ_CRC_ERROR_MASK = uint16(0b0000000001000000) + IRQ_RANGING_SLAVE_RESPONSE_DONE_MASK = uint16(0b0000000010000000) + IRQ_RANGING_SLAVE_RESPONSE_DISCARD_MASK = uint16(0b0000000100000000) + IRQ_RANGING_MASTER_RESULT_VALID_MASK = uint16(0b0000001000000000) + IRQ_RANGING_MASTER_TIMEOUT_MASK = uint16(0b0000010000000000) + IRQ_RANGING_SLAVE_REQUEST_VALID_MASK = uint16(0b0000100000000000) + IRQ_CAD_DONE_MASK = uint16(0b0001000000000000) + IRQ_CAD_DETECTED_MASK = uint16(0b0010000000000000) + IRQ_RX_TX_TIMEOUT_MASK = uint16(0b0100000000000000) + IRQ_PREAMBLE_DETECTED_MASK = uint16(0b1000000000000000) + IRQ_ADVANCED_RANGING_DONE_MASK = uint16(0b1000000000000000) + + // SX128X register map + REG_FIRMWARE_VERSIONS = uint16(0x153) + REG_RX_GAIN = uint16(0x891) + REG_MANUAL_GAIN_SETTING = uint16(0x895) + REG_LNA_GAIN_VALUE = uint16(0x89E) + REG_LNA_GAIN_CONTROL = uint16(0x89F) + REG_SYNCH_PEAK_ATTENUATION = uint16(0x8C2) + REG_PAYLOAD_LENGTH = uint16(0x901) + REG_LORA_HEADER_MODE = uint16(0x903) + REG_RANGING_REQUEST_ADDRESS_BYTE_3 = uint16(0x912) + REG_RANGING_REQUEST_ADDRESS_BYTE_2 = uint16(0x913) + REG_RANGING_REQUEST_ADDRESS_BYTE_1 = uint16(0x914) + REG_RANGING_REQUEST_ADDRESS_BYTE_0 = uint16(0x915) + REG_RANGING_DEVICE_ADDRESS_BYTE_3 = uint16(0x916) + REG_RANGING_DEVICE_ADDRESS_BYTE_2 = uint16(0x917) + REG_RANGING_DEVICE_ADDRESS_BYTE_1 = uint16(0x918) + REG_RANGING_DEVICE_ADDRESS_BYTE_0 = uint16(0x919) + REG_RANGING_FILTER_WINDOW_SIZE = uint16(0x91E) + REG_RESET_RANGING_FILTER = uint16(0x923) + REG_RANGING_RESULT_MUX = uint16(0x924) + REG_SF_ADDITIONAL_CONFIGURATION = uint16(0x925) + REG_RANGING_CALIBRATION_BYTE_2 = uint16(0x92B) + REG_RANGING_CALIBRATION_BYTE_1 = uint16(0x92C) + REG_RANGING_CALIBRATION_BYTE_0 = uint16(0x92D) + REG_RANGING_ID_CHECK_LENGTH = uint16(0x931) + REG_FREQUENCY_ERROR_CORRECTION = uint16(0x93C) + REG_CAD_DETECT_PEAK = uint16(0x942) + REG_LORA_SYNC_WORD_MSB = uint16(0x944) + REG_LORA_SYNC_WORD_LSB = uint16(0x945) + REG_HEADER_CRC = uint16(0x954) + REG_CODING_RATE = uint16(0x950) + REG_FEI_BYTE_2 = uint16(0x954) + REG_FEI_BYTE_1 = uint16(0x955) + REG_FEI_BYTE_0 = uint16(0x956) + REG_RANGING_RESULT_BYTE_2 = uint16(0x961) + REG_RANGING_RESULT_BYTE_1 = uint16(0x962) + REG_RANGING_RESULT_BYTE_0 = uint16(0x963) + REG_RANGING_RSSI = uint16(0x964) + REG_FREEZE_RANGING_RESULT = uint16(0x97F) + REG_PACKET_PREAMBLE_SETTINGS = uint16(0x9C1) + REG_WHITENING_INITIAL_VALUE = uint16(0x9C5) + REG_CRC_POLYNOMIAL_DEFINITION_MSB = uint16(0x9C6) + REG_CRC_POLYNOMIAL_DEFINITION_LSB = uint16(0x9C7) + REG_CRC_POLYNOMIAL_SEED_BYTE_2 = uint16(0x9C7) + REG_CRC_POLYNOMIAL_SEED_BYTE_1 = uint16(0x9C8) + REG_CRC_POLYNOMIAL_SEED_BYTE_0 = uint16(0x9C9) + REG_CRC_MSB_INITIAL_VALUE = uint16(0x9C8) + REG_CRC_LSB_INITIAL_VALUE = uint16(0x9C9) + REG_SYNC_ADDRESS_CONTROL = uint16(0x9CD) + REG_SYNC_ADDRESS_1_BYTE_4 = uint16(0x9CE) + REG_SYNC_ADDRESS_1_BYTE_3 = uint16(0x9CF) + REG_SYNC_ADDRESS_1_BYTE_2 = uint16(0x9D0) + REG_SYNC_ADDRESS_1_BYTE_1 = uint16(0x9D1) + REG_SYNC_ADDRESS_1_BYTE_0 = uint16(0x9D2) + REG_SYNC_ADDRESS_2_BYTE_4 = uint16(0x9D3) + REG_SYNC_ADDRESS_2_BYTE_3 = uint16(0x9D4) + REG_SYNC_ADDRESS_2_BYTE_2 = uint16(0x9D5) + REG_SYNC_ADDRESS_2_BYTE_1 = uint16(0x9D6) + REG_SYNC_ADDRESS_2_BYTE_0 = uint16(0x9D7) + REG_SYNC_ADDRESS_3_BYTE_4 = uint16(0x9D8) + REG_SYNC_ADDRESS_3_BYTE_3 = uint16(0x9D9) + REG_SYNC_ADDRESS_3_BYTE_2 = uint16(0x9DA) + REG_SYNC_ADDRESS_3_BYTE_1 = uint16(0x9DB) + REG_SYNC_ADDRESS_3_BYTE_0 = uint16(0x9DC) +) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go new file mode 100644 index 000000000..35b306b4e --- /dev/null +++ b/sx128x/sx128x.go @@ -0,0 +1,533 @@ +package sx128x + +import ( + "errors" + "time" + + "tinygo.org/x/drivers" + "tinygo.org/x/drivers/internal/pin" +) + +type Device struct { + spi drivers.SPI + nssPin pin.Output + resetPin pin.Output + busyPin pin.Input + spiTxBuf []byte + spiRxBuf []byte +} + +func New(spi drivers.SPI, nssPin pin.Output, resetPin pin.Output, busyPin pin.Input) *Device { + return &Device{ + spi: spi, + nssPin: nssPin, + resetPin: resetPin, + busyPin: busyPin, + spiTxBuf: make([]byte, 255), // TODO: optimize buffer size + spiRxBuf: make([]byte, 255), + } +} + +func (d *Device) Reset() { + d.resetPin.Set(false) + time.Sleep(10 * time.Millisecond) + d.resetPin.Set(true) + time.Sleep(10 * time.Millisecond) +} + +func (d *Device) WaitWhileBusy() { + // TODO(jwetzell): better way to do this? + for d.busyPin.Get() { + } +} + +func (d *Device) GetStatus() (uint8, uint8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + status, err := d.spi.Transfer(CMD_GET_STATUS) + d.nssPin.Set(true) + + if err != nil { + return 0, 0, err + } + + circuitMode := (status & CIRCUIT_MODE_MASK) >> 5 + commandStatus := (status & COMMAND_STATUS_MASK) >> 2 + return circuitMode, commandStatus, nil +} + +func (d *Device) WriteRegister(addr uint16, data []byte) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_REGISTER, uint8((addr>>8)&0xFF), uint8(addr&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, data...) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) ReadRegister(addr uint16) (uint8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_READ_REGISTER, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF), 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:5] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, err + } + return d.spiRxBuf[4], nil +} + +func (d *Device) WriteBuffer(offset uint8, data []byte) error { + if len(data) > 255 { + return errors.New("length of data over max length of 255") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_BUFFER, offset) + d.spiTxBuf = append(d.spiTxBuf, data...) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { + if length > 255 { + return nil, errors.New("read length over max length of 255") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_READ_BUFFER, offset, 0x00) + for i := uint8(0); i < length; i++ { + d.spiTxBuf = append(d.spiTxBuf, 0x00) + } + d.spiRxBuf = d.spiRxBuf[:len(d.spiTxBuf)] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return nil, err + } + return d.spiRxBuf[3:], nil +} + +func (d *Device) SetSleep(sleepConfig uint8) error { + if sleepConfig > 3 { + return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SLEEP, sleepConfig) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetStandby(standbyConfig uint8) error { + if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { + return errors.New("standby config must be 0 (RC) or 1 (XOSC)") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_STANDBY, standbyConfig) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetFs() error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_FS) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func checkPeriodBase(periodBase uint8) error { + if periodBase != PERIOD_BASE_15_625_US && periodBase != PERIOD_BASE_62_5_US && periodBase != PERIOD_BASE_1_MS && periodBase != PERIOD_BASE_4_MS { + return errors.New("period base must be 0, 1, 2 or 4") + } + return nil +} + +func (d *Device) SetTx(periodBase uint8, periodBaseCount uint16) error { + err := checkPeriodBase(periodBase) + if err != nil { + return err + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + err = d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetRx(periodBase uint8, periodBaseCount uint16) error { + err := checkPeriodBase(periodBase) + if err != nil { + return err + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + err = d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, sleepPeriodBaseCount uint16) error { + err := checkPeriodBase(periodBase) + if err != nil { + return err + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX_DUTY_CYCLE, periodBase, uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, uint8((sleepPeriodBaseCount&0xFF00)>>8), uint8(sleepPeriodBaseCount&0x00FF)) + err = d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetLongPreamble(enable bool) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_LONG_PREAMBLE) + if enable { + d.spiTxBuf = append(d.spiTxBuf, LONG_PREAMBLE_ENABLE) + } else { + d.spiTxBuf = append(d.spiTxBuf, LONG_PREAMBLE_DISABLE) + } + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetCAD() error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetTxContinuousWave() error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_WAVE) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetTxContinuousPreamble() error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_PREAMBLE) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetAutoTx(time uint16) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_TX, uint8((time&0xFF00)>>8), uint8(time&0x00FF)) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetAutoFs(enable bool) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_FS) + if enable { + d.spiTxBuf = append(d.spiTxBuf, AUTO_FS_ENABLE) + } else { + d.spiTxBuf = append(d.spiTxBuf, AUTO_FS_DISABLE) + } + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetPacketType(packetType uint8) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_TYPE, packetType) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) GetPacketType() (uint8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_TYPE, 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:3] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, err + } + return d.spiRxBuf[2], nil +} + +func (d *Device) SetRfFrequency(frequency uint32) error { + if frequency < 2400000000 { + return errors.New("frequency must be greater than or equal to 2.4 GHz") + } + if frequency > 2500000000 { + return errors.New("frequency must be less than or equal to 2.5 GHz") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + freq := uint32((uint64(frequency) << 18) / 52000000) + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((freq>>16)&0xFF), uint8((freq>>8)&0xFF), uint8(freq&0xFF)) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { + if powerdBm < -18 { + return errors.New("power in dBm must be greater than or equal to -18") + } + if powerdBm > 13 { + return errors.New("power in dBm must be less than or equal to 13") + } + + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + adjustedPower := uint8(powerdBm + 18) + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_PARAMS, adjustedPower, rampTime) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetCadParams(cadSymbolNum uint8) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD_PARAMS, cadSymbolNum) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_BUFFER_BASE_ADDRESS, txBase, rxBase) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +// BLE & GFSK: BitrateBandwidth, ModulationIndex, ModulationShaping +// FLRC: BitrateBandwidth, CodingRate, ModulationShaping +// LoRa & Ranging: SpreadingFactor, Bandwidth, CodingRate +func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_MODULATION_PARAMS, modParam1, modParam2, modParam3) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetModulationParamsBLE(bitrateBandwidth uint8, modulationIndex uint8, modulationShaping uint8) error { + return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) +} + +func (d *Device) SetModulationParamsGFSK(bitrateBandwidth uint8, modulationIndex uint8, modulationShaping uint8) error { + return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) +} + +func (d *Device) SetModulationParamsFLRC(bitrateBandwidth uint8, codingRate uint8, modulationShaping uint8) error { + return d.SetModulationParams(bitrateBandwidth, codingRate, modulationShaping) +} + +func (d *Device) SetModulationParamsLoRa(spreadingFactor uint8, bandwidth uint8, codingRate uint8) error { + return d.SetModulationParams(spreadingFactor, bandwidth, codingRate) +} + +// GFSK & FLRC: PreambleLength, SyncWordLength, SyncWordMatch, HeaderType, PayloadLength, CrcLength, Whitening +// BLE: ConnectionState, CrcLength, BleTestPayload, Whitening +// LoRa & Ranging: PreambleLength, HeaderType, PayloadLength, CRC, InvertIQ/chirp invert +func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, param7 uint8) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_PARAMS, param1, param2, param3, param4, param5, param6, param7) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetPacketParamsGFSK(preambleLength uint8, syncWordLength uint8, syncWordMatch uint8, headerType uint8, payloadLength uint8, crcLength uint8, whitening uint8) error { + return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whitening) +} + +func (d *Device) SetPacketParamsFLRC(preambleLength uint8, syncWordLength uint8, syncWordMatch uint8, headerType uint8, payloadLength uint8, crcLength uint8, whitening uint8) error { + return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whitening) +} + +func (d *Device) SetPacketParamsBLE(connectionState uint8, crcLength uint8, bleTestPayload uint8, whitening uint8) error { + return d.SetPacketParams(connectionState, crcLength, bleTestPayload, whitening, 0, 0, 0) +} + +func (d *Device) SetPacketParamsLoRa(preambleLength uint32, headerType uint8, payloadLength uint8, crcType uint8, iqType uint8) error { + exponent, mantissa := getExponentAndMantissa(preambleLength) + return d.SetPacketParams(uint8(exponent<<4)|mantissa, headerType, payloadLength, crcType, iqType, 0, 0) +} + +func getExponentAndMantissa(value uint32) (uint8, uint8) { + // pulled from RadioLib https://github.com/jgromes/RadioLib/blob/master/src/modules/SX128x/SX128x.cpp + e := uint8(1) + m := uint8(1) + len := uint32(0) + for e = uint8(1); e <= 15; e++ { + for m = uint8(1); m <= 15; m++ { + len = uint32(m) * (uint32(1 << e)) + if len >= value { + break + } + } + if len >= value { + break + } + } + + return e, m +} + +// RxBufferStatus: payloadLength, bufferStartPointer +func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RX_BUFFER_STATUS, 0x00, 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:4] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, 0, err + } + return d.spiRxBuf[2], d.spiRxBuf[3], nil +} + +func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:7] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, 0, 0, 0, 0, err + } + return d.spiRxBuf[2], d.spiRxBuf[3], d.spiRxBuf[4], d.spiRxBuf[5], d.spiRxBuf[6], nil +} + +func (d *Device) GetRssiInst() (int8, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RSSI_INST, 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:3] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, err + } + return int8(d.spiRxBuf[2]/2) * -1, nil +} + +func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint16, dio3Mask uint16) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_DIO_IRQ_PARAMS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, uint8((dio1Mask&0xFF00)>>8), uint8(dio1Mask&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, uint8((dio2Mask&0xFF00)>>8), uint8(dio2Mask&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, uint8((dio3Mask&0xFF00)>>8), uint8(dio3Mask&0x00FF)) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) GetIrqStatus() (uint16, error) { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_GET_IRQ_STATUS, 0x00, 0x00, 0x00) + d.spiRxBuf = d.spiRxBuf[:4] + err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + d.nssPin.Set(true) + if err != nil { + return 0, err + } + return uint16(d.spiRxBuf[2])<<8 | uint16(d.spiRxBuf[3]), err +} + +func (d *Device) ClearIrqStatus(irqMask uint16) error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_CLEAR_IRQ_STATUS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetRegulatorMode(mode uint8) error { + if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { + return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") + } + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_REGULATOR_MODE, mode) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} + +func (d *Device) SetSaveContext() error { + d.WaitWhileBusy() + d.nssPin.Set(false) + d.spiTxBuf = d.spiTxBuf[:0] + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SAVE_CONTEXT) + err := d.spi.Tx(d.spiTxBuf, nil) + d.nssPin.Set(true) + return err +} From 67f3860e6164be267fa18bd3c0164ba7a77477b8 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 27 Apr 2026 19:48:11 -0500 Subject: [PATCH 02/11] handle busy loop better --- sx128x/sx128x.go | 238 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 171 insertions(+), 67 deletions(-) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 35b306b4e..d2bb4cdf7 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -2,6 +2,7 @@ package sx128x import ( "errors" + "runtime" "time" "tinygo.org/x/drivers" @@ -35,14 +36,24 @@ func (d *Device) Reset() { time.Sleep(10 * time.Millisecond) } -func (d *Device) WaitWhileBusy() { - // TODO(jwetzell): better way to do this? - for d.busyPin.Get() { +func (d *Device) WaitWhileBusy() error { + // largest busy period is on boot with around ~400ish this should be more than enough + retries := 1000 + for retries > 0 && d.busyPin.Get() { + runtime.Gosched() + retries-- } + if retries == 0 { + return errors.New("busy pin timeout") + } + return nil } func (d *Device) GetStatus() (uint8, uint8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, 0, err + } d.nssPin.Set(false) status, err := d.spi.Transfer(CMD_GET_STATUS) d.nssPin.Set(true) @@ -57,23 +68,29 @@ func (d *Device) GetStatus() (uint8, uint8, error) { } func (d *Device) WriteRegister(addr uint16, data []byte) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_REGISTER, uint8((addr>>8)&0xFF), uint8(addr&0xFF)) d.spiTxBuf = append(d.spiTxBuf, data...) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) ReadRegister(addr uint16) (uint8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_READ_REGISTER, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF), 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:5] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, err @@ -85,21 +102,24 @@ func (d *Device) WriteBuffer(offset uint8, data []byte) error { if len(data) > 255 { return errors.New("length of data over max length of 255") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_BUFFER, offset) d.spiTxBuf = append(d.spiTxBuf, data...) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { - if length > 255 { - return nil, errors.New("read length over max length of 255") + err := d.WaitWhileBusy() + if err != nil { + return nil, err } - d.WaitWhileBusy() d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_READ_BUFFER, offset, 0x00) @@ -107,7 +127,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { d.spiTxBuf = append(d.spiTxBuf, 0x00) } d.spiRxBuf = d.spiRxBuf[:len(d.spiTxBuf)] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return nil, err @@ -119,11 +139,14 @@ func (d *Device) SetSleep(sleepConfig uint8) error { if sleepConfig > 3 { return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SLEEP, sleepConfig) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -132,21 +155,27 @@ func (d *Device) SetStandby(standbyConfig uint8) error { if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { return errors.New("standby config must be 0 (RC) or 1 (XOSC)") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_STANDBY, standbyConfig) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetFs() error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_FS) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -163,7 +192,10 @@ func (d *Device) SetTx(periodBase uint8, periodBaseCount uint16) error { if err != nil { return err } - d.WaitWhileBusy() + err = d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) @@ -177,7 +209,10 @@ func (d *Device) SetRx(periodBase uint8, periodBaseCount uint16) error { if err != nil { return err } - d.WaitWhileBusy() + err = d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) @@ -191,7 +226,10 @@ func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, slee if err != nil { return err } - d.WaitWhileBusy() + err = d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX_DUTY_CYCLE, periodBase, uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) @@ -202,7 +240,10 @@ func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, slee } func (d *Device) SetLongPreamble(enable bool) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_LONG_PREAMBLE) @@ -211,53 +252,68 @@ func (d *Device) SetLongPreamble(enable bool) error { } else { d.spiTxBuf = append(d.spiTxBuf, LONG_PREAMBLE_DISABLE) } - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetCAD() error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetTxContinuousWave() error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_WAVE) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetTxContinuousPreamble() error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_PREAMBLE) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetAutoTx(time uint16) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_TX, uint8((time&0xFF00)>>8), uint8(time&0x00FF)) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetAutoFs(enable bool) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_FS) @@ -266,28 +322,34 @@ func (d *Device) SetAutoFs(enable bool) error { } else { d.spiTxBuf = append(d.spiTxBuf, AUTO_FS_DISABLE) } - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetPacketType(packetType uint8) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_TYPE, packetType) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) GetPacketType() (uint8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_TYPE, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:3] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, err @@ -302,12 +364,15 @@ func (d *Device) SetRfFrequency(frequency uint32) error { if frequency > 2500000000 { return errors.New("frequency must be less than or equal to 2.5 GHz") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] freq := uint32((uint64(frequency) << 18) / 52000000) d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((freq>>16)&0xFF), uint8((freq>>8)&0xFF), uint8(freq&0xFF)) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -320,32 +385,41 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { return errors.New("power in dBm must be less than or equal to 13") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] adjustedPower := uint8(powerdBm + 18) d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_PARAMS, adjustedPower, rampTime) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetCadParams(cadSymbolNum uint8) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD_PARAMS, cadSymbolNum) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_BUFFER_BASE_ADDRESS, txBase, rxBase) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -354,11 +428,14 @@ func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { // FLRC: BitrateBandwidth, CodingRate, ModulationShaping // LoRa & Ranging: SpreadingFactor, Bandwidth, CodingRate func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_MODULATION_PARAMS, modParam1, modParam2, modParam3) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -383,11 +460,14 @@ func (d *Device) SetModulationParamsLoRa(spreadingFactor uint8, bandwidth uint8, // BLE: ConnectionState, CrcLength, BleTestPayload, Whitening // LoRa & Ranging: PreambleLength, HeaderType, PayloadLength, CRC, InvertIQ/chirp invert func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, param7 uint8) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_PARAMS, param1, param2, param3, param4, param5, param6, param7) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -431,12 +511,15 @@ func getExponentAndMantissa(value uint32) (uint8, uint8) { // RxBufferStatus: payloadLength, bufferStartPointer func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RX_BUFFER_STATUS, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:4] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, 0, err @@ -445,12 +528,15 @@ func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { } func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, 0, 0, 0, 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:7] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, 0, 0, 0, 0, err @@ -459,12 +545,15 @@ func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { } func (d *Device) GetRssiInst() (int8, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RSSI_INST, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:3] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, err @@ -473,25 +562,31 @@ func (d *Device) GetRssiInst() (int8, error) { } func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint16, dio3Mask uint16) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_DIO_IRQ_PARAMS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio1Mask&0xFF00)>>8), uint8(dio1Mask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio2Mask&0xFF00)>>8), uint8(dio2Mask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio3Mask&0xFF00)>>8), uint8(dio3Mask&0x00FF)) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) GetIrqStatus() (uint16, error) { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return 0, err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_GET_IRQ_STATUS, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:4] - err := d.spi.Tx(d.spiTxBuf, d.spiRxBuf) + err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) if err != nil { return 0, err @@ -500,11 +595,14 @@ func (d *Device) GetIrqStatus() (uint16, error) { } func (d *Device) ClearIrqStatus(irqMask uint16) error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_CLEAR_IRQ_STATUS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } @@ -513,21 +611,27 @@ func (d *Device) SetRegulatorMode(mode uint8) error { if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") } - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_REGULATOR_MODE, mode) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } func (d *Device) SetSaveContext() error { - d.WaitWhileBusy() + err := d.WaitWhileBusy() + if err != nil { + return err + } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SAVE_CONTEXT) - err := d.spi.Tx(d.spiTxBuf, nil) + err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err } From ffe510627c49e7e4e87951be71a6a515cd8a00cf Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Wed, 29 Apr 2026 07:35:38 -0500 Subject: [PATCH 03/11] switch to time based busy timeout Co-authored-by: Copilot --- sx128x/sx128x.go | 83 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index d2bb4cdf7..03c64f920 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -36,21 +36,19 @@ func (d *Device) Reset() { time.Sleep(10 * time.Millisecond) } -func (d *Device) WaitWhileBusy() error { +func (d *Device) WaitWhileBusy(timeout time.Duration) error { // largest busy period is on boot with around ~400ish this should be more than enough - retries := 1000 - for retries > 0 && d.busyPin.Get() { + now := time.Now() + for d.busyPin.Get() { + if time.Since(now) > timeout { + return errors.New("busy pin timeout") + } runtime.Gosched() - retries-- - } - if retries == 0 { - return errors.New("busy pin timeout") } return nil } -func (d *Device) GetStatus() (uint8, uint8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, 0, err } @@ -68,7 +66,7 @@ func (d *Device) GetStatus() (uint8, uint8, error) { } func (d *Device) WriteRegister(addr uint16, data []byte) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -82,7 +80,7 @@ func (d *Device) WriteRegister(addr uint16, data []byte) error { } func (d *Device) ReadRegister(addr uint16) (uint8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err } @@ -102,7 +100,7 @@ func (d *Device) WriteBuffer(offset uint8, data []byte) error { if len(data) > 255 { return errors.New("length of data over max length of 255") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -116,7 +114,7 @@ func (d *Device) WriteBuffer(offset uint8, data []byte) error { } func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return nil, err } @@ -139,7 +137,7 @@ func (d *Device) SetSleep(sleepConfig uint8) error { if sleepConfig > 3 { return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -155,7 +153,7 @@ func (d *Device) SetStandby(standbyConfig uint8) error { if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { return errors.New("standby config must be 0 (RC) or 1 (XOSC)") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -168,7 +166,7 @@ func (d *Device) SetStandby(standbyConfig uint8) error { } func (d *Device) SetFs() error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -192,7 +190,7 @@ func (d *Device) SetTx(periodBase uint8, periodBaseCount uint16) error { if err != nil { return err } - err = d.WaitWhileBusy() + err = d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -209,7 +207,7 @@ func (d *Device) SetRx(periodBase uint8, periodBaseCount uint16) error { if err != nil { return err } - err = d.WaitWhileBusy() + err = d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -226,7 +224,7 @@ func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, slee if err != nil { return err } - err = d.WaitWhileBusy() + err = d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -240,7 +238,7 @@ func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, slee } func (d *Device) SetLongPreamble(enable bool) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -258,7 +256,7 @@ func (d *Device) SetLongPreamble(enable bool) error { } func (d *Device) SetCAD() error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -271,7 +269,7 @@ func (d *Device) SetCAD() error { } func (d *Device) SetTxContinuousWave() error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -284,7 +282,7 @@ func (d *Device) SetTxContinuousWave() error { } func (d *Device) SetTxContinuousPreamble() error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -296,8 +294,7 @@ func (d *Device) SetTxContinuousPreamble() error { return err } -func (d *Device) SetAutoTx(time uint16) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -310,7 +307,7 @@ func (d *Device) SetAutoTx(time uint16) error { } func (d *Device) SetAutoFs(enable bool) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -327,8 +324,7 @@ func (d *Device) SetAutoFs(enable bool) error { return err } -func (d *Device) SetPacketType(packetType uint8) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -340,8 +336,7 @@ func (d *Device) SetPacketType(packetType uint8) error { return err } -func (d *Device) GetPacketType() (uint8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err } @@ -364,7 +359,7 @@ func (d *Device) SetRfFrequency(frequency uint32) error { if frequency > 2500000000 { return errors.New("frequency must be less than or equal to 2.5 GHz") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -385,7 +380,7 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { return errors.New("power in dBm must be less than or equal to 13") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -399,7 +394,7 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { } func (d *Device) SetCadParams(cadSymbolNum uint8) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -412,7 +407,7 @@ func (d *Device) SetCadParams(cadSymbolNum uint8) error { } func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -428,7 +423,7 @@ func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { // FLRC: BitrateBandwidth, CodingRate, ModulationShaping // LoRa & Ranging: SpreadingFactor, Bandwidth, CodingRate func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -460,7 +455,7 @@ func (d *Device) SetModulationParamsLoRa(spreadingFactor uint8, bandwidth uint8, // BLE: ConnectionState, CrcLength, BleTestPayload, Whitening // LoRa & Ranging: PreambleLength, HeaderType, PayloadLength, CRC, InvertIQ/chirp invert func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, param7 uint8) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -511,7 +506,7 @@ func getExponentAndMantissa(value uint32) (uint8, uint8) { // RxBufferStatus: payloadLength, bufferStartPointer func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, 0, err } @@ -528,7 +523,7 @@ func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { } func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, 0, 0, 0, 0, err } @@ -545,7 +540,7 @@ func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { } func (d *Device) GetRssiInst() (int8, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err } @@ -562,7 +557,7 @@ func (d *Device) GetRssiInst() (int8, error) { } func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint16, dio3Mask uint16) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -578,7 +573,7 @@ func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint1 } func (d *Device) GetIrqStatus() (uint16, error) { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err } @@ -595,7 +590,7 @@ func (d *Device) GetIrqStatus() (uint16, error) { } func (d *Device) ClearIrqStatus(irqMask uint16) error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -611,7 +606,7 @@ func (d *Device) SetRegulatorMode(mode uint8) error { if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") } - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } @@ -624,7 +619,7 @@ func (d *Device) SetRegulatorMode(mode uint8) error { } func (d *Device) SetSaveContext() error { - err := d.WaitWhileBusy() + err := d.WaitWhileBusy(time.Second) if err != nil { return err } From aedbc3e2f201f782522e337c686ad03c5bef9b2d Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Wed, 29 Apr 2026 07:39:54 -0500 Subject: [PATCH 04/11] comment functions --- sx128x/sx128x.go | 49 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 03c64f920..15ab33639 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -48,6 +48,7 @@ func (d *Device) WaitWhileBusy(timeout time.Duration) error { return nil } +// Get tranceiver status, returns circuit mode and command status err := d.WaitWhileBusy(time.Second) if err != nil { return 0, 0, err @@ -113,6 +114,7 @@ func (d *Device) WriteBuffer(offset uint8, data []byte) error { return err } +// Read data from the payload buffer starting at the given offset with the given length func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -133,7 +135,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { return d.spiRxBuf[3:], nil } -func (d *Device) SetSleep(sleepConfig uint8) error { +// Set the device into sleep mode with the given configuration: 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention) if sleepConfig > 3 { return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") } @@ -149,7 +151,7 @@ func (d *Device) SetSleep(sleepConfig uint8) error { return err } -func (d *Device) SetStandby(standbyConfig uint8) error { +// Put device into standby mode, 0 (RC) or 1 (XOSC) if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { return errors.New("standby config must be 0 (RC) or 1 (XOSC)") } @@ -165,6 +167,7 @@ func (d *Device) SetStandby(standbyConfig uint8) error { return err } +// Set the device into Frequency Synthesizer mode func (d *Device) SetFs() error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -185,7 +188,8 @@ func checkPeriodBase(periodBase uint8) error { return nil } -func (d *Device) SetTx(periodBase uint8, periodBaseCount uint16) error { +// Sets the device in transmit mode, the IRQ status should be cleared before using this command +// timout is determined by periodBase * periodBaseCount err := checkPeriodBase(periodBase) if err != nil { return err @@ -202,7 +206,8 @@ func (d *Device) SetTx(periodBase uint8, periodBaseCount uint16) error { return err } -func (d *Device) SetRx(periodBase uint8, periodBaseCount uint16) error { +// Sets the device in receive mode, the IRQ status should be cleared before using this command +// timeout is determined by periodBase * periodBaseCount err := checkPeriodBase(periodBase) if err != nil { return err @@ -219,7 +224,9 @@ func (d *Device) SetRx(periodBase uint8, periodBaseCount uint16) error { return err } -func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, sleepPeriodBaseCount uint16) error { +// Sets the device in a continuous receive mode, it enters receive mode with a timeout of periodBase * rxPeriodBaseCount. +// If no packet is received it will enter sleep mode for periodBase * sleepPeriodBaseCount before re-entering receive mode. +// The loop is exited when a packet is received or the device is put into standby mode. err := checkPeriodBase(periodBase) if err != nil { return err @@ -237,6 +244,7 @@ func (d *Device) SetRxDutyCycle(periodBase uint8, rxPeriodBaseCount uint16, slee return err } +// Sets the transceiver into Long Preamble mode, and can only be used with either the LoRa mode and GFSK mode func (d *Device) SetLongPreamble(enable bool) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -255,6 +263,8 @@ func (d *Device) SetLongPreamble(enable bool) error { return err } +// Channel activity detection (CAD) is a LoRa specific mode of operation where the device searches for a LoRa signal. +// After search has completed, the device returns to STDBY_RC mode. The length of the search is configured via the SetCadParams() command. func (d *Device) SetCAD() error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -268,6 +278,8 @@ func (d *Device) SetCAD() error { return err } +// Test command to generate a Continuous Wave (RF tone) at a selected frequency and output power +// The device remains in Tx Continuous Wave until the host sends a mode configuration command. func (d *Device) SetTxContinuousWave() error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -281,6 +293,8 @@ func (d *Device) SetTxContinuousWave() error { return err } +// Test command to generate an infinite sequence of alternating ‘0’s and ‘1’s in +// GFSK modulation and symbol 0 in LoRa. The device remains in transmit until the host sends a mode configuration command. func (d *Device) SetTxContinuousPreamble() error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -294,6 +308,8 @@ func (d *Device) SetTxContinuousPreamble() error { return err } +// This command allows the transceiver to send a packet at a user programmable time after the end of a packet reception. +// This is useful for Bluetooth Low Energy (BLE) compatibility which requires the transceiver to be able to send back a response 150µs after a packet reception. err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -306,6 +322,8 @@ func (d *Device) SetTxContinuousPreamble() error { return err } +// Modifies the chip behavior so that the state following a Rx or Tx operation is FS and not standby. +// This allows for faster transitions between Rx and/or Tx. func (d *Device) SetAutoFs(enable bool) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -324,6 +342,7 @@ func (d *Device) SetAutoFs(enable bool) error { return err } +// Choose between GFSK, LoRa, Ranging, FLRC or BLE packet types, this will affect the available configuration parameters and the structure of the packet err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -336,6 +355,7 @@ func (d *Device) SetAutoFs(enable bool) error { return err } +// Get the currently configured packet type, this will be 0 (GFSK), 1 (LoRa), 2 (Ranging), 3 (FLRC) or 4 (BLE) err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err @@ -352,8 +372,7 @@ func (d *Device) SetAutoFs(enable bool) error { return d.spiRxBuf[2], nil } -func (d *Device) SetRfFrequency(frequency uint32) error { - if frequency < 2400000000 { +// Set the RF frequency in Hz, must be between 2.4 GHz and 2.5 GHz return errors.New("frequency must be greater than or equal to 2.4 GHz") } if frequency > 2500000000 { @@ -372,7 +391,7 @@ func (d *Device) SetRfFrequency(frequency uint32) error { return err } -func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { +// Set the output power in dBm, must be between -18 and 13 dBm, and the ramp time if powerdBm < -18 { return errors.New("power in dBm must be greater than or equal to -18") } @@ -393,6 +412,8 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime uint8) error { return err } +// Set the number of symbols used for channel activity detection which determines the sensitivity of the detection. +// This is only applicable in LoRa mode. func (d *Device) SetCadParams(cadSymbolNum uint8) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -406,6 +427,8 @@ func (d *Device) SetCadParams(cadSymbolNum uint8) error { return err } +// Set the base address for the internal buffer for Tx and Rx operations. +// When transmitting or receiving data is read from or written to the buffer starting at the given offset. func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -504,7 +527,8 @@ func getExponentAndMantissa(value uint32) (uint8, uint8) { return e, m } -// RxBufferStatus: payloadLength, bufferStartPointer +// Get information about the most recent packet received. +// Return the payload length, the offset in the buffer where the payload starts. func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -539,6 +563,7 @@ func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { return d.spiRxBuf[2], d.spiRxBuf[3], d.spiRxBuf[4], d.spiRxBuf[5], d.spiRxBuf[6], nil } +// Get the instantaneous RSSI value during reception of the packet func (d *Device) GetRssiInst() (int8, error) { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -556,6 +581,7 @@ func (d *Device) GetRssiInst() (int8, error) { return int8(d.spiRxBuf[2]/2) * -1, nil } +// Configure the overall IRQ mask and the mapping of individual IRQs to the DIO1, DIO2 and DIO3 pins func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint16, dio3Mask uint16) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -572,6 +598,7 @@ func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint1 return err } +// Get the current IRQ status. func (d *Device) GetIrqStatus() (uint16, error) { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -589,6 +616,7 @@ func (d *Device) GetIrqStatus() (uint16, error) { return uint16(d.spiRxBuf[2])<<8 | uint16(d.spiRxBuf[3]), err } +// Clear the IRQ bits specified in the irqMask. func (d *Device) ClearIrqStatus(irqMask uint16) error { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -602,7 +630,7 @@ func (d *Device) ClearIrqStatus(irqMask uint16) error { return err } -func (d *Device) SetRegulatorMode(mode uint8) error { +// Switch between the low-dropout regulator (LDO) and the DC-DC converter for internal power regulation. if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") } @@ -618,6 +646,7 @@ func (d *Device) SetRegulatorMode(mode uint8) error { return err } +// Stores the present context of the radio register values to the Data RAM which will be restored when the device wakes up from sleep mode. func (d *Device) SetSaveContext() error { err := d.WaitWhileBusy(time.Second) if err != nil { From 8481077ca9238a3d7e93e94e5116dae4e25bedd1 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Wed, 29 Apr 2026 07:40:08 -0500 Subject: [PATCH 05/11] start on using types for function inputs --- sx128x/registers.go | 130 ++++++++++++++++++++++++-------------------- sx128x/sx128x.go | 23 ++++++-- 2 files changed, 90 insertions(+), 63 deletions(-) diff --git a/sx128x/registers.go b/sx128x/registers.go index eaa7b58fb..edba774c8 100644 --- a/sx128x/registers.go +++ b/sx128x/registers.go @@ -1,5 +1,19 @@ package sx128x +type SleepConfig = uint8 +type StandbyConfig = uint8 +type PeriodBase = uint8 +type PacketType = uint8 +type RadioRampTime = uint8 +type CadSymbolNum = uint8 +type SpreadingFactor = uint8 +type Bandwidth = uint8 +type CodingRate = uint8 +type RegulatorMode = uint8 + +type CircuitMode = uint8 +type CommandStatus = uint8 + const ( // SX128X SPI commands CMD_NOP = uint8(0x00) @@ -55,33 +69,33 @@ const ( // GetStatus CIRCUIT_MODE_MASK = uint8(0b11100000) - CIRCUIT_MODE_STDBY_RC = uint8(0x2) - CIRCUIT_MODE_STDBY_XOSC = uint8(0x3) - CIRCUIT_MODE_FS = uint8(0x4) - CIRCUIT_MODE_RX = uint8(0x5) - CIRCUIT_MODE_TX = uint8(0x6) + CIRCUIT_MODE_STDBY_RC = CircuitMode(0x2) + CIRCUIT_MODE_STDBY_XOSC = CircuitMode(0x3) + CIRCUIT_MODE_FS = CircuitMode(0x4) + CIRCUIT_MODE_RX = CircuitMode(0x5) + CIRCUIT_MODE_TX = CircuitMode(0x6) COMMAND_STATUS_MASK = uint8(0b00011100) - COMMAND_STATUS_SUCCESS = uint8(0x1) - COMMAND_STATUS_DATA_AVAILABLE = uint8(0x2) - COMMAND_STATUS_TIMEOUT = uint8(0x3) - COMMAND_STATUS_PROCESSING_ERROR = uint8(0x4) - COMMAND_STATUS_EXECUTION_ERROR = uint8(0x5) - COMMAND_STATUS_TX_DONE = uint8(0x6) + COMMAND_STATUS_SUCCESS = CommandStatus(0x1) + COMMAND_STATUS_DATA_AVAILABLE = CommandStatus(0x2) + COMMAND_STATUS_TIMEOUT = CommandStatus(0x3) + COMMAND_STATUS_PROCESSING_ERROR = CommandStatus(0x4) + COMMAND_STATUS_EXECUTION_ERROR = CommandStatus(0x5) + COMMAND_STATUS_TX_DONE = CommandStatus(0x6) // SleepConfig - SLEEP_DATA_BUFFER_RETAIN = uint8(2) - SLEEP_DATA_RAM_RETAIN = uint8(1) + SLEEP_DATA_BUFFER_RETAIN = SleepConfig(2) + SLEEP_DATA_RAM_RETAIN = SleepConfig(1) // StandbyConfig - STANDBY_RC = uint8(0) - STANDBY_XOSC = uint8(1) + STANDBY_RC = StandbyConfig(0) + STANDBY_XOSC = StandbyConfig(1) // PeriodBase - PERIOD_BASE_15_625_US = uint8(0) - PERIOD_BASE_62_5_US = uint8(1) - PERIOD_BASE_1_MS = uint8(2) - PERIOD_BASE_4_MS = uint8(3) + PERIOD_BASE_15_625_US = PeriodBase(0) + PERIOD_BASE_62_5_US = PeriodBase(1) + PERIOD_BASE_1_MS = PeriodBase(2) + PERIOD_BASE_4_MS = PeriodBase(3) RX_CONTINUOUS_MODE = uint16(0xFFFF) @@ -94,53 +108,53 @@ const ( AUTO_FS_DISABLE = uint8(0) // PacketType - PACKET_TYPE_GFSK = uint8(0x00) // default - PACKET_TYPE_LORA = uint8(0x01) - PACKET_TYPE_RANGING = uint8(0x02) - PACKET_TYPE_FLRC = uint8(0x03) - PACKET_TYPE_BLE = uint8(0x04) + PACKET_TYPE_GFSK = PacketType(0x00) // default + PACKET_TYPE_LORA = PacketType(0x01) + PACKET_TYPE_RANGING = PacketType(0x02) + PACKET_TYPE_FLRC = PacketType(0x03) + PACKET_TYPE_BLE = PacketType(0x04) // RampTime - RADIO_RAMP_02_US = uint8(0x00) - RADIO_RAMP_04_US = uint8(0x20) - RADIO_RAMP_06_US = uint8(0x40) - RADIO_RAMP_08_US = uint8(0x60) - RADIO_RAMP_10_US = uint8(0x80) - RADIO_RAMP_12_US = uint8(0xA0) - RADIO_RAMP_16_US = uint8(0xC0) - RADIO_RAMP_20_US = uint8(0xE0) + RADIO_RAMP_02_US = RadioRampTime(0x00) + RADIO_RAMP_04_US = RadioRampTime(0x20) + RADIO_RAMP_06_US = RadioRampTime(0x40) + RADIO_RAMP_08_US = RadioRampTime(0x60) + RADIO_RAMP_10_US = RadioRampTime(0x80) + RADIO_RAMP_12_US = RadioRampTime(0xA0) + RADIO_RAMP_16_US = RadioRampTime(0xC0) + RADIO_RAMP_20_US = RadioRampTime(0xE0) // CadSymbolNum - LORA_CAD_01_SYMBOL = uint8(0x00) - LORA_CAD_02_SYMBOLS = uint8(0x20) - LORA_CAD_04_SYMBOLS = uint8(0x40) - LORA_CAD_08_SYMBOLS = uint8(0x60) - LORA_CAD_16_SYMBOLS = uint8(0x80) + LORA_CAD_01_SYMBOL = CadSymbolNum(0x00) + LORA_CAD_02_SYMBOLS = CadSymbolNum(0x20) + LORA_CAD_04_SYMBOLS = CadSymbolNum(0x40) + LORA_CAD_08_SYMBOLS = CadSymbolNum(0x60) + LORA_CAD_16_SYMBOLS = CadSymbolNum(0x80) // SpreadingFactor - LORA_SF_5 = uint8(0x50) - LORA_SF_6 = uint8(0x60) - LORA_SF_7 = uint8(0x70) - LORA_SF_8 = uint8(0x80) - LORA_SF_9 = uint8(0x90) - LORA_SF_10 = uint8(0xA0) - LORA_SF_11 = uint8(0xB0) - LORA_SF_12 = uint8(0xC0) + LORA_SF_5 = SpreadingFactor(0x50) + LORA_SF_6 = SpreadingFactor(0x60) + LORA_SF_7 = SpreadingFactor(0x70) + LORA_SF_8 = SpreadingFactor(0x80) + LORA_SF_9 = SpreadingFactor(0x90) + LORA_SF_10 = SpreadingFactor(0xA0) + LORA_SF_11 = SpreadingFactor(0xB0) + LORA_SF_12 = SpreadingFactor(0xC0) // Bandwidth - LORA_BW_1600 = uint8(0x0A) - LORA_BW_800 = uint8(0x18) - LORA_BW_400 = uint8(0x26) - LORA_BW_200 = uint8(0x34) + LORA_BW_1600 = Bandwidth(0x0A) + LORA_BW_800 = Bandwidth(0x18) + LORA_BW_400 = Bandwidth(0x26) + LORA_BW_200 = Bandwidth(0x34) // CodingRate - LORA_CR_4_5 = uint8(0x01) - LORA_CR_4_6 = uint8(0x02) - LORA_CR_4_7 = uint8(0x03) - LORA_CR_4_8 = uint8(0x04) - LORA_CR_LI_4_5 = uint8(0x05) - LORA_CR_LI_4_6 = uint8(0x06) - LORA_CR_LI_4_8 = uint8(0x07) + LORA_CR_4_5 = CodingRate(0x01) + LORA_CR_4_6 = CodingRate(0x02) + LORA_CR_4_7 = CodingRate(0x03) + LORA_CR_4_8 = CodingRate(0x04) + LORA_CR_LI_4_5 = CodingRate(0x05) + LORA_CR_LI_4_6 = CodingRate(0x06) + LORA_CR_LI_4_8 = CodingRate(0x07) // LoraPacketParams LORA_EXPLICIT_HEADER = uint8(0x00) @@ -153,8 +167,8 @@ const ( LORA_IQ_STD = uint8(0x40) // RegulatorMode - REGULATOR_LDO = uint8(0) - REGULATOR_DC_DC = uint8(1) + REGULATOR_LDO = RegulatorMode(0) + REGULATOR_DC_DC = RegulatorMode(1) // IRQ masks IRQ_ALL_MASK = uint16(0xFFFF) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 15ab33639..7540d6b80 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -49,6 +49,7 @@ func (d *Device) WaitWhileBusy(timeout time.Duration) error { } // Get tranceiver status, returns circuit mode and command status +func (d *Device) GetStatus() (CircuitMode, CommandStatus, error) { err := d.WaitWhileBusy(time.Second) if err != nil { return 0, 0, err @@ -136,6 +137,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { } // Set the device into sleep mode with the given configuration: 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention) +func (d *Device) SetSleep(sleepConfig SleepConfig) error { if sleepConfig > 3 { return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") } @@ -152,6 +154,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { } // Put device into standby mode, 0 (RC) or 1 (XOSC) +func (d *Device) SetStandby(standbyConfig StandbyConfig) error { if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { return errors.New("standby config must be 0 (RC) or 1 (XOSC)") } @@ -181,7 +184,7 @@ func (d *Device) SetFs() error { return err } -func checkPeriodBase(periodBase uint8) error { +func checkPeriodBase(periodBase PeriodBase) error { if periodBase != PERIOD_BASE_15_625_US && periodBase != PERIOD_BASE_62_5_US && periodBase != PERIOD_BASE_1_MS && periodBase != PERIOD_BASE_4_MS { return errors.New("period base must be 0, 1, 2 or 4") } @@ -190,6 +193,7 @@ func checkPeriodBase(periodBase uint8) error { // Sets the device in transmit mode, the IRQ status should be cleared before using this command // timout is determined by periodBase * periodBaseCount +func (d *Device) SetTx(periodBase PeriodBase, periodBaseCount uint16) error { err := checkPeriodBase(periodBase) if err != nil { return err @@ -208,6 +212,7 @@ func checkPeriodBase(periodBase uint8) error { // Sets the device in receive mode, the IRQ status should be cleared before using this command // timeout is determined by periodBase * periodBaseCount +func (d *Device) SetRx(periodBase PeriodBase, periodBaseCount uint16) error { err := checkPeriodBase(periodBase) if err != nil { return err @@ -227,6 +232,7 @@ func checkPeriodBase(periodBase uint8) error { // Sets the device in a continuous receive mode, it enters receive mode with a timeout of periodBase * rxPeriodBaseCount. // If no packet is received it will enter sleep mode for periodBase * sleepPeriodBaseCount before re-entering receive mode. // The loop is exited when a packet is received or the device is put into standby mode. +func (d *Device) SetRxDutyCycle(periodBase PeriodBase, rxPeriodBaseCount uint16, sleepPeriodBaseCount uint16) error { err := checkPeriodBase(periodBase) if err != nil { return err @@ -310,13 +316,14 @@ func (d *Device) SetTxContinuousPreamble() error { // This command allows the transceiver to send a packet at a user programmable time after the end of a packet reception. // This is useful for Bluetooth Low Energy (BLE) compatibility which requires the transceiver to be able to send back a response 150µs after a packet reception. +func (d *Device) SetAutoTx(timeUs uint16) error { err := d.WaitWhileBusy(time.Second) if err != nil { return err } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_TX, uint8((time&0xFF00)>>8), uint8(time&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_TX, uint8((timeUs&0xFF00)>>8), uint8(timeUs&0x00FF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -343,6 +350,7 @@ func (d *Device) SetAutoFs(enable bool) error { } // Choose between GFSK, LoRa, Ranging, FLRC or BLE packet types, this will affect the available configuration parameters and the structure of the packet +func (d *Device) SetPacketType(packetType PacketType) error { err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -356,6 +364,7 @@ func (d *Device) SetAutoFs(enable bool) error { } // Get the currently configured packet type, this will be 0 (GFSK), 1 (LoRa), 2 (Ranging), 3 (FLRC) or 4 (BLE) +func (d *Device) GetPacketType() (PacketType, error) { err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err @@ -373,9 +382,11 @@ func (d *Device) SetAutoFs(enable bool) error { } // Set the RF frequency in Hz, must be between 2.4 GHz and 2.5 GHz +func (d *Device) SetRfFrequency(frequencyHz uint32) error { + if frequencyHz < 2400000000 { return errors.New("frequency must be greater than or equal to 2.4 GHz") } - if frequency > 2500000000 { + if frequencyHz > 2500000000 { return errors.New("frequency must be less than or equal to 2.5 GHz") } err := d.WaitWhileBusy(time.Second) @@ -384,7 +395,7 @@ func (d *Device) SetAutoFs(enable bool) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - freq := uint32((uint64(frequency) << 18) / 52000000) + freq := uint32((uint64(frequencyHz) << 18) / 52000000) d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((freq>>16)&0xFF), uint8((freq>>8)&0xFF), uint8(freq&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -392,6 +403,7 @@ func (d *Device) SetAutoFs(enable bool) error { } // Set the output power in dBm, must be between -18 and 13 dBm, and the ramp time +func (d *Device) SetTxParams(powerdBm int8, rampTime RadioRampTime) error { if powerdBm < -18 { return errors.New("power in dBm must be greater than or equal to -18") } @@ -470,7 +482,7 @@ func (d *Device) SetModulationParamsFLRC(bitrateBandwidth uint8, codingRate uint return d.SetModulationParams(bitrateBandwidth, codingRate, modulationShaping) } -func (d *Device) SetModulationParamsLoRa(spreadingFactor uint8, bandwidth uint8, codingRate uint8) error { +func (d *Device) SetModulationParamsLoRa(spreadingFactor SpreadingFactor, bandwidth Bandwidth, codingRate CodingRate) error { return d.SetModulationParams(spreadingFactor, bandwidth, codingRate) } @@ -631,6 +643,7 @@ func (d *Device) ClearIrqStatus(irqMask uint16) error { } // Switch between the low-dropout regulator (LDO) and the DC-DC converter for internal power regulation. +func (d *Device) SetRegulatorMode(mode RegulatorMode) error { if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") } From 1badf0905d47987da2db682ebf4714bb6acc0691 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Wed, 29 Apr 2026 12:30:07 -0500 Subject: [PATCH 06/11] use types where applicable and align with datasheet more Co-authored-by: Copilot --- sx128x/commands.go | 55 ++++++ sx128x/constants.go | 410 ++++++++++++++++++++++++++++++++++++++++++++ sx128x/errors.go | 19 ++ sx128x/registers.go | 189 -------------------- sx128x/sx128x.go | 174 ++++++++++++++----- 5 files changed, 618 insertions(+), 229 deletions(-) create mode 100644 sx128x/commands.go create mode 100644 sx128x/constants.go create mode 100644 sx128x/errors.go diff --git a/sx128x/commands.go b/sx128x/commands.go new file mode 100644 index 000000000..fa0eff042 --- /dev/null +++ b/sx128x/commands.go @@ -0,0 +1,55 @@ +package sx128x + +const ( + // SX128X SPI commands + CMD_NOP = uint8(0x00) + + CMD_SET_UART_SPEED = uint8(0x9D) + CMD_GET_STATUS = uint8(0xC0) + + // Register Access Operations + CMD_WRITE_REGISTER = uint8(0x18) + CMD_READ_REGISTER = uint8(0x19) + + // Data Buffer Operations + CMD_WRITE_BUFFER = uint8(0x1A) + CMD_READ_BUFFER = uint8(0x1B) + + // Radio Operation Modes + CMD_SET_SLEEP = uint8(0x84) + CMD_SET_STANDBY = uint8(0x80) + CMD_SET_FS = uint8(0xC1) + CMD_SET_TX = uint8(0x83) + CMD_SET_RX = uint8(0x82) + CMD_SET_RX_DUTY_CYCLE = uint8(0x94) + CMD_SET_LONG_PREAMBLE = uint8(0x9B) + CMD_SET_CAD = uint8(0xC5) + CMD_SET_TX_CONTINUOUS_WAVE = uint8(0xD1) + CMD_SET_TX_CONTINUOUS_PREAMBLE = uint8(0xD2) + CMD_SET_AUTO_TX = uint8(0x98) + CMD_SET_AUTO_FS = uint8(0x9E) + + // Radio Configuration + CMD_SET_PACKET_TYPE = uint8(0x8A) + CMD_GET_PACKET_TYPE = uint8(0x03) + CMD_SET_RF_FREQUENCY = uint8(0x86) + CMD_SET_TX_PARAMS = uint8(0x8E) + CMD_SET_CAD_PARAMS = uint8(0x88) + CMD_SET_BUFFER_BASE_ADDRESS = uint8(0x8F) + CMD_SET_MODULATION_PARAMS = uint8(0x8B) + CMD_SET_PACKET_PARAMS = uint8(0x8C) + + // Communication Status Information + CMD_GET_RX_BUFFER_STATUS = uint8(0x17) + CMD_GET_PACKET_STATUS = uint8(0x1D) + CMD_GET_RSSI_INST = uint8(0x1F) + + // IRQ Handling + CMD_SET_DIO_IRQ_PARAMS = uint8(0x8D) + CMD_GET_IRQ_STATUS = uint8(0x15) + CMD_CLEAR_IRQ_STATUS = uint8(0x97) + + // Miscellaneous + CMD_SET_REGULATOR_MODE = uint8(0x96) + CMD_SET_SAVE_CONTEXT = uint8(0xD5) +) diff --git a/sx128x/constants.go b/sx128x/constants.go new file mode 100644 index 000000000..59918811e --- /dev/null +++ b/sx128x/constants.go @@ -0,0 +1,410 @@ +package sx128x + +type SleepConfig = uint8 +type StandbyConfig = uint8 +type PeriodBase = uint8 +type PacketType = uint8 +type RadioRampTime = uint8 +type CadSymbolNum = uint8 + +// GFSK Modulation Params +type GFSKBitrateBandwidth = uint8 +type GFSKModulationIndex = uint8 +type GFSKModulationShaping = uint8 + +// GFSK Packet Params +type GFSKPreambleLength = uint8 +type GFSKSyncWordLength = uint8 +type GFSKSyncWordMatch = uint8 +type GFSKHeaderType = uint8 +type GFSKCrcType = uint8 + +// BLE Modulation Params +type BLEBitrateBandwidth = uint8 +type BLEModulationIndex = uint8 +type BLEModulationShaping = uint8 + +// BLE Packet Params +type BLEConnectionState = uint8 +type BLECrcType = uint8 +type BLETestPayload = uint8 + +// FLRC Modulation Params +type FLRCBitrateBandwidth = uint8 +type FLRCCodingRate = uint8 +type FLRCModulationShaping = uint8 + +// FLRC Packet Params +type FLRCPreambleLength = uint8 +type FLRCSyncWordLength = uint8 +type FLRCSyncWordMatch = uint8 +type FLRCHeaderType = uint8 +type FLRCCrcType = uint8 + +// LoRa Modulation Params +type LoRaSpreadingFactor = uint8 +type LoRaBandwidth = uint8 +type LoRaCodingRate = uint8 + +// LoRa Packet Params +type LoRaHeaderType = uint8 +type LoRaCrcType = uint8 +type LoRaIqType = uint8 + +// Misc +type RegulatorMode = uint8 + +type IRQMask = uint16 + +type CircuitMode = uint8 +type CommandStatus = uint8 + +// Packet Status +type GFSKPacketInfo = uint8 +type BLEPacketInfo = uint8 +type FLRCPacketInfo = uint8 + +const ( + WHITENING_DISABLE = 0x00 + WHITENING_ENABLE = 0x08 + + // Circuit Mode + CIRCUIT_MODE_MASK = uint8(0b11100000) + CIRCUIT_MODE_STDBY_RC = CircuitMode(0x2) + CIRCUIT_MODE_STDBY_XOSC = CircuitMode(0x3) + CIRCUIT_MODE_FS = CircuitMode(0x4) + CIRCUIT_MODE_RX = CircuitMode(0x5) + CIRCUIT_MODE_TX = CircuitMode(0x6) + + // Command Status + COMMAND_STATUS_MASK = uint8(0b00011100) + COMMAND_STATUS_SUCCESS = CommandStatus(0x1) + COMMAND_STATUS_DATA_AVAILABLE = CommandStatus(0x2) + COMMAND_STATUS_TIMEOUT = CommandStatus(0x3) + COMMAND_STATUS_PROCESSING_ERROR = CommandStatus(0x4) + COMMAND_STATUS_EXECUTION_ERROR = CommandStatus(0x5) + COMMAND_STATUS_TX_DONE = CommandStatus(0x6) + + // SleepConfig + SLEEP_DATA_BUFFER_RETAIN = SleepConfig(2) + SLEEP_DATA_RAM_RETAIN = SleepConfig(1) + + // StandbyConfig + STANDBY_RC = StandbyConfig(0) + STANDBY_XOSC = StandbyConfig(1) + + // PeriodBase + PERIOD_BASE_15_625_US = PeriodBase(0) + PERIOD_BASE_62_5_US = PeriodBase(1) + PERIOD_BASE_1_MS = PeriodBase(2) + PERIOD_BASE_4_MS = PeriodBase(3) + + RX_CONTINUOUS_MODE = uint16(0xFFFF) + + // PacketType + PACKET_TYPE_GFSK = PacketType(0x00) // default + PACKET_TYPE_LORA = PacketType(0x01) + PACKET_TYPE_RANGING = PacketType(0x02) + PACKET_TYPE_FLRC = PacketType(0x03) + PACKET_TYPE_BLE = PacketType(0x04) + + // RampTime + RADIO_RAMP_02_US = RadioRampTime(0x00) + RADIO_RAMP_04_US = RadioRampTime(0x20) + RADIO_RAMP_06_US = RadioRampTime(0x40) + RADIO_RAMP_08_US = RadioRampTime(0x60) + RADIO_RAMP_10_US = RadioRampTime(0x80) + RADIO_RAMP_12_US = RadioRampTime(0xA0) + RADIO_RAMP_16_US = RadioRampTime(0xC0) + RADIO_RAMP_20_US = RadioRampTime(0xE0) + + // CadSymbolNum + LORA_CAD_01_SYMBOL = CadSymbolNum(0x00) + LORA_CAD_02_SYMBOLS = CadSymbolNum(0x20) + LORA_CAD_04_SYMBOLS = CadSymbolNum(0x40) + LORA_CAD_08_SYMBOLS = CadSymbolNum(0x60) + LORA_CAD_16_SYMBOLS = CadSymbolNum(0x80) + + // GFSK Modulation Params + // Bitrate + Bandwidth + GFSK_BR_2_000_BW_2_4 = GFSKBitrateBandwidth(0x04) + GFSK_BR_1_600_BW_2_4 = GFSKBitrateBandwidth(0x28) + GFSK_BR_1_000_BW_2_4 = GFSKBitrateBandwidth(0x4C) + GFSK_BR_1_000_BW_1_2 = GFSKBitrateBandwidth(0x45) + GFSK_BR_0_800_BW_2_4 = GFSKBitrateBandwidth(0x70) + GFSK_BR_0_800_BW_1_2 = GFSKBitrateBandwidth(0x69) + GFSK_BR_0_500_BW_1_2 = GFSKBitrateBandwidth(0x8D) + GFSK_BR_0_500_BW_0_6 = GFSKBitrateBandwidth(0x86) + GFSK_BR_0_400_BW_1_2 = GFSKBitrateBandwidth(0xB1) + GFSK_BR_0_400_BW_0_6 = GFSKBitrateBandwidth(0xAA) + GFSK_BR_0_250_BW_0_6 = GFSKBitrateBandwidth(0xCE) + GFSK_BR_0_250_BW_0_3 = GFSKBitrateBandwidth(0xC7) + GFSK_BR_0_125_BW_0_3 = GFSKBitrateBandwidth(0xEF) + + // Modulation Index + GFS_MOD_IND_0_35 = GFSKModulationIndex(0x00) + GFS_MOD_IND_0_5 = GFSKModulationIndex(0x01) + GFS_MOD_IND_0_75 = GFSKModulationIndex(0x02) + GFS_MOD_IND_1_00 = GFSKModulationIndex(0x03) + GFS_MOD_IND_1_25 = GFSKModulationIndex(0x04) + GFS_MOD_IND_1_50 = GFSKModulationIndex(0x05) + GFS_MOD_IND_1_75 = GFSKModulationIndex(0x06) + GFS_MOD_IND_2_00 = GFSKModulationIndex(0x07) + GFS_MOD_IND_2_25 = GFSKModulationIndex(0x08) + GFS_MOD_IND_2_50 = GFSKModulationIndex(0x09) + GFS_MOD_IND_2_75 = GFSKModulationIndex(0x0A) + GFS_MOD_IND_3_00 = GFSKModulationIndex(0x0B) + GFS_MOD_IND_3_25 = GFSKModulationIndex(0x0C) + GFS_MOD_IND_3_50 = GFSKModulationIndex(0x0D) + GFS_MOD_IND_3_75 = GFSKModulationIndex(0x0E) + GFS_MOD_IND_4_00 = GFSKModulationIndex(0x0F) + + // GFSK Modulation Shaping + GFSK_MOD_SHAPING_OFF = GFSKModulationShaping(0x00) + GFSK_MOD_SHAPING_1_0 = GFSKModulationShaping(0x10) + GFSK_MOD_SHAPING_0_5 = GFSKModulationShaping(0x20) + + // GFSK Packet Params + // Preamble Length + GFSK_PREAMBLE_LENGTH_04_BITS = GFSKPreambleLength(0x00) + GFSK_PREAMBLE_LENGTH_08_BITS = GFSKPreambleLength(0x10) + GFSK_PREAMBLE_LENGTH_12_BITS = GFSKPreambleLength(0x20) + GFSK_PREAMBLE_LENGTH_16_BITS = GFSKPreambleLength(0x30) + GFSK_PREAMBLE_LENGTH_20_BITS = GFSKPreambleLength(0x40) + GFSK_PREAMBLE_LENGTH_24_BITS = GFSKPreambleLength(0x50) + GFSK_PREAMBLE_LENGTH_28_BITS = GFSKPreambleLength(0x60) + GFSK_PREAMBLE_LENGTH_32_BITS = GFSKPreambleLength(0x70) + + // Sync Word Length + GFSK_SYNC_WORD_LEN_1_B = GFSKSyncWordLength(0x00) + GFSK_SYNC_WORD_LEN_2_B = GFSKSyncWordLength(0x02) + GFSK_SYNC_WORD_LEN_3_B = GFSKSyncWordLength(0x04) + GFSK_SYNC_WORD_LEN_4_B = GFSKSyncWordLength(0x06) + GFSK_SYNC_WORD_LEN_5_B = GFSKSyncWordLength(0x08) + + // Sync Word Match + GFSK_SYNCWORD_MATCH_OFF = GFSKSyncWordMatch(0x00) + GFSK_SYNCWORD_MATCH_1 = GFSKSyncWordMatch(0x10) + GFSK_SYNCWORD_MATCH_2 = GFSKSyncWordMatch(0x20) + GFSK_SYNCWORD_MATCH_1_2 = GFSKSyncWordMatch(0x30) + GFSK_SYNCWORD_MATCH_3 = GFSKSyncWordMatch(0x40) + GFSK_SYNCWORD_MATCH_1_3 = GFSKSyncWordMatch(0x50) + GFSK_SYNCWORD_MATCH_2_3 = GFSKSyncWordMatch(0x60) + GFSK_SYNCWORD_MATCH_1_2_3 = GFSKSyncWordMatch(0x70) + + // GFSK Header Type + GFSK_HEADER_FIXED_LENGTH = GFSKHeaderType(0x00) + GFSK_HEADER_VARIABLE_LENGTH = GFSKHeaderType(0x20) + + // GFSK CRC Type + GFSK_CRC_OFF = GFSKCrcType(0x00) + GFSK_CRC_1_BYTE = GFSKCrcType(0x10) + GFSK_CRC_2_BYTES = GFSKCrcType(0x20) + + // BLE Modulation Params + // Bitrate + Bandwidth + BLE_BR_2_000_BW_2_4 = BLEBitrateBandwidth(0x04) + BLE_BR_1_600_BW_2_4 = BLEBitrateBandwidth(0x28) + BLE_BR_1_000_BW_2_4 = BLEBitrateBandwidth(0x4C) + BLE_BR_1_000_BW_1_2 = BLEBitrateBandwidth(0x45) + BLE_BR_0_800_BW_2_4 = BLEBitrateBandwidth(0x70) + BLE_BR_0_800_BW_1_2 = BLEBitrateBandwidth(0x69) + BLE_BR_0_500_BW_1_2 = BLEBitrateBandwidth(0x8D) + BLE_BR_0_500_BW_0_6 = BLEBitrateBandwidth(0x86) + BLE_BR_0_400_BW_1_2 = BLEBitrateBandwidth(0xB1) + BLE_BR_0_400_BW_0_6 = BLEBitrateBandwidth(0xAA) + BLE_BR_0_250_BW_0_6 = BLEBitrateBandwidth(0xCE) + BLE_BR_0_250_BW_0_3 = BLEBitrateBandwidth(0xC7) + BLE_BR_0_125_BW_0_3 = BLEBitrateBandwidth(0xEF) + + // Modulation Index + BLE_MOD_IND_0_35 = BLEModulationIndex(0x00) + BLE_MOD_IND_0_5 = BLEModulationIndex(0x01) + BLE_MOD_IND_0_75 = BLEModulationIndex(0x02) + BLE_MOD_IND_1 = BLEModulationIndex(0x03) + BLE_MOD_IND_1_25 = BLEModulationIndex(0x04) + BLE_MOD_IND_1_5 = BLEModulationIndex(0x05) + BLE_MOD_IND_1_75 = BLEModulationIndex(0x06) + BLE_MOD_IND_2 = BLEModulationIndex(0x07) + BLE_MOD_IND_2_25 = BLEModulationIndex(0x08) + BLE_MOD_IND_2_5 = BLEModulationIndex(0x09) + BLE_MOD_IND_2_75 = BLEModulationIndex(0x0A) + BLE_MOD_IND_3 = BLEModulationIndex(0x0B) + BLE_MOD_IND_3_25 = BLEModulationIndex(0x0C) + BLE_MOD_IND_3_5 = BLEModulationIndex(0x0D) + BLE_MOD_IND_3_75 = BLEModulationIndex(0x0E) + BLE_MOD_IND_4 = BLEModulationIndex(0x0F) + + // Modulation Shaping + BLE_MOD_SHAPING_OFF = BLEModulationShaping(0x00) + BLE_MOD_SHAPING_1_0 = BLEModulationShaping(0x10) + BLE_MOD_SHAPING_0_5 = BLEModulationShaping(0x20) + + // BLE Packet Params + // Connection State + BLE_MASTER_SLAVE = BLEConnectionState(0x00) + BLE_ADVERTISER = BLEConnectionState(0x02) + BLE_TX_TEST_MODE = BLEConnectionState(0x04) + BLE_RX_TEST_MODE = BLEConnectionState(0x06) + BLE_RXTX_TEST_MODE = BLEConnectionState(0x08) + + // CRC Type + BLE_CRC_OFF = BLECrcType(0x00) + BLE_CRC_3_BYTES = BLECrcType(0x10) + + // BLE Test Payload + BLE_PAYLOAD_PRBS_9 = BLETestPayload(0x00) + BLE_PAYLOAD_EYELONG_1_0 = BLETestPayload(0x04) + BLE_PAYLOAD_EYESHORT_1_0 = BLETestPayload(0x08) + BLE_PAYLOAD_PRBS_15 = BLETestPayload(0x0C) + BLE_PAYLOAD_ALL_1 = BLETestPayload(0x10) + BLE_PAYLOAD_ALL_0 = BLETestPayload(0x14) + BLE_PAYLOAD_EYELONG_0_1 = BLETestPayload(0x18) + BLE_PAYLOAD_EYESHORT_0_1 = BLETestPayload(0x1C) + + // FLRC Modulation Params + // Bitrate + Bandwidth + FLRC_BR_1_300_BW_1_2 = FLRCBitrateBandwidth(0x45) + FLRC_BR_1_000_BW_1_2 = FLRCBitrateBandwidth(0x69) + FLRC_BR_0_650_BW_0_6 = FLRCBitrateBandwidth(0x86) + FLRC_BR_0_520_BW_0_6 = FLRCBitrateBandwidth(0xAA) + FLRC_BR_0_325_BW_0_3 = FLRCBitrateBandwidth(0xC7) + FLRC_BR_0_260_BW_0_3 = FLRCBitrateBandwidth(0xEB) + + // Coding Rate + FLRC_CR_1_2 = FLRCCodingRate(0x00) // 1/2 + FLRC_CR_3_4 = FLRCCodingRate(0x02) // 3/4 + FLRC_CR_1_0 = FLRCCodingRate(0x04) // 1 + + // Modulation Shaping + FLRC_MOD_SHAPING_OFF = FLRCModulationShaping(0x00) + FLRC_MOD_SHAPING_1_0 = FLRCModulationShaping(0x10) // 1 + FLRC_MOD_SHAPING_0_5 = FLRCModulationShaping(0x20) // 0.5 + + // FLRC Packet Params + // Preamble Length + FLRC_PREAMBLE_LENGTH_4_BITS = FLRCPreambleLength(0x00) + FLRC_PREAMBLE_LENGTH_8_BITS = FLRCPreambleLength(0x10) + FLRC_PREAMBLE_LENGTH_12_BITS = FLRCPreambleLength(0x20) + FLRC_PREAMBLE_LENGTH_16_BITS = FLRCPreambleLength(0x30) + FLRC_PREAMBLE_LENGTH_20_BITS = FLRCPreambleLength(0x40) + FLRC_PREAMBLE_LENGTH_24_BITS = FLRCPreambleLength(0x50) + FLRC_PREAMBLE_LENGTH_28_BITS = FLRCPreambleLength(0x60) + FLRC_PREAMBLE_LENGTH_32_BITS = FLRCPreambleLength(0x70) + + // Sync Word Length + FLRC_SYNC_WORD_LEN_0 = FLRCSyncWordLength(0x00) + FLRC_SYNC_WORD_LEN_32_BITS = FLRCSyncWordLength(0x04) + + // Sync Word Match + FLRC_SYNC_WORD_MATCH_DISABLE = FLRCSyncWordMatch(0x00) // Disable Sync Word + FLRC_SYNC_WORD_MATCH_1 = FLRCSyncWordMatch(0x10) // Sync Word 1 + FLRC_SYNC_WORD_MATCH_2 = FLRCSyncWordMatch(0x20) // Sync Word 2 + FLRC_SYNC_WORD_MATCH_1_2 = FLRCSyncWordMatch(0x30) // Sync Word 1 or Sync Word 2 + FLRC_SYNC_WORD_MATCH_3 = FLRCSyncWordMatch(0x40) // Sync Word 3 + FLRC_SYNC_WORD_MATCH_1_3 = FLRCSyncWordMatch(0x50) // Sync Word 1 or Sync Word 3 + FLRC_SYNC_WORD_MATCH_2_3 = FLRCSyncWordMatch(0x60) // Sync Word 2 or Sync Word 3 + FLRC_SYNC_WORD_MATCH_1_2_3 = FLRCSyncWordMatch(0x70) // Sync Word 1 or Sync Word 2 or Sync Word 3 + + // Header Type + FLRC_HEADER_FIXED_LENGTH = FLRCHeaderType(0x00) + FLRC_HEADER_VARIABLE_LENGTH = FLRCHeaderType(0x20) + + // CRC Type + FLRC_CRC_OFF = FLRCCrcType(0x00) + FLRC_CRC_1_BYTE = FLRCCrcType(0x10) + FLRC_CRC_2_BYTES = FLRCCrcType(0x20) + FLRC_CRC_3_BYTES = FLRCCrcType(0x30) + + // LoRa Modulation Params + + // SpreadingFactor + LORA_SF_5 = LoRaSpreadingFactor(0x50) + LORA_SF_6 = LoRaSpreadingFactor(0x60) + LORA_SF_7 = LoRaSpreadingFactor(0x70) + LORA_SF_8 = LoRaSpreadingFactor(0x80) + LORA_SF_9 = LoRaSpreadingFactor(0x90) + LORA_SF_10 = LoRaSpreadingFactor(0xA0) + LORA_SF_11 = LoRaSpreadingFactor(0xB0) + LORA_SF_12 = LoRaSpreadingFactor(0xC0) + + // Bandwidth + LORA_BW_1600 = LoRaBandwidth(0x0A) + LORA_BW_800 = LoRaBandwidth(0x18) + LORA_BW_400 = LoRaBandwidth(0x26) + LORA_BW_200 = LoRaBandwidth(0x34) + + // CodingRate + LORA_CR_4_5 = LoRaCodingRate(0x01) + LORA_CR_4_6 = LoRaCodingRate(0x02) + LORA_CR_4_7 = LoRaCodingRate(0x03) + LORA_CR_4_8 = LoRaCodingRate(0x04) + LORA_CR_LI_4_5 = LoRaCodingRate(0x05) + LORA_CR_LI_4_6 = LoRaCodingRate(0x06) + LORA_CR_LI_4_8 = LoRaCodingRate(0x07) + + // LoraPacketParams + // HeaderType + LORA_HEADER_EXPLICIT = LoRaHeaderType(0x00) + LORA_HEADER_IMPLICIT = LoRaHeaderType(0x80) + + // CRC Type + LORA_CRC_ENABLE = LoRaCrcType(0x20) + LORA_CRC_DISABLE = LoRaCrcType(0x00) + + // IQ Type + LORA_IQ_INVERTED = LoRaIqType(0x00) + LORA_IQ_STD = LoRaIqType(0x40) + + // RegulatorMode + REGULATOR_LDO = RegulatorMode(0) + REGULATOR_DC_DC = RegulatorMode(1) + + // IRQ masks + IRQ_ALL_MASK = IRQMask(0xFFFF) + IRQ_NONE_MASK = IRQMask(0x0000) + IRQ_TX_DONE_MASK = IRQMask(0b0000000000000001) + IRQ_RX_DONE_MASK = IRQMask(0b0000000000000010) + IRQ_SYNC_WORD_VALID_MASK = IRQMask(0b0000000000000100) + IRQ_SYNC_WORD_ERROR_MASK = IRQMask(0b0000000000001000) + IRQ_HEADER_VALID_MASK = IRQMask(0b0000000000010000) + IRQ_HEADER_ERROR_MASK = IRQMask(0b0000000000100000) + IRQ_CRC_ERROR_MASK = IRQMask(0b0000000001000000) + IRQ_RANGING_SLAVE_RESPONSE_DONE_MASK = IRQMask(0b0000000010000000) + IRQ_RANGING_SLAVE_RESPONSE_DISCARD_MASK = IRQMask(0b0000000100000000) + IRQ_RANGING_MASTER_RESULT_VALID_MASK = IRQMask(0b0000001000000000) + IRQ_RANGING_MASTER_TIMEOUT_MASK = IRQMask(0b0000010000000000) + IRQ_RANGING_SLAVE_REQUEST_VALID_MASK = IRQMask(0b0000100000000000) + IRQ_CAD_DONE_MASK = IRQMask(0b0001000000000000) + IRQ_CAD_DETECTED_MASK = IRQMask(0b0010000000000000) + IRQ_RX_TX_TIMEOUT_MASK = IRQMask(0b0100000000000000) + IRQ_PREAMBLE_DETECTED_MASK = IRQMask(0b1000000000000000) + IRQ_ADVANCED_RANGING_DONE_MASK = IRQMask(0b1000000000000000) + + // GFSK Packet Info + GFSK_SYNC_ERROR = GFSKPacketInfo(0b1000000) + GFSK_LENGTH_ERROR = GFSKPacketInfo(0b0100000) + GFSK_CRC_ERROR = GFSKPacketInfo(0b0010000) + GFSK_ABORT_ERROR = GFSKPacketInfo(0b0001000) + GFSK_HEADER_RECEIVED = GFSKPacketInfo(0b0000100) + GFSK_PACKET_RECEIVED = GFSKPacketInfo(0b0000010) + GFSK_PACKET_CRTL_BUSY = GFSKPacketInfo(0b0000001) + + // BLE Packet Info + BLE_SYNC_ERROR = BLEPacketInfo(0b1000000) + BLE_LENGTH_ERROR = BLEPacketInfo(0b0100000) + BLE_CRC_ERROR = BLEPacketInfo(0b0010000) + BLE_ABORT_ERROR = BLEPacketInfo(0b0001000) + BLE_HEADER_RECEIVED = BLEPacketInfo(0b0000100) + BLE_PACKET_RECEIVED = BLEPacketInfo(0b0000010) + BLE_PACKET_CRTL_BUSY = BLEPacketInfo(0b0000001) + + // FLRC Packet Info + FLRC_SYNC_ERROR = FLRCPacketInfo(0b1000000) + FLRC_LENGTH_ERROR = FLRCPacketInfo(0b0100000) + FLRC_CRC_ERROR = FLRCPacketInfo(0b0010000) + FLRC_ABORT_ERROR = FLRCPacketInfo(0b0001000) + FLRC_HEADER_RECEIVED = FLRCPacketInfo(0b0000100) + FLRC_PACKET_RECEIVED = FLRCPacketInfo(0b0000010) + FLRC_PACKET_CRTL_BUSY = FLRCPacketInfo(0b0000001) +) diff --git a/sx128x/errors.go b/sx128x/errors.go new file mode 100644 index 000000000..9ec5261f0 --- /dev/null +++ b/sx128x/errors.go @@ -0,0 +1,19 @@ +package sx128x + +import "errors" + +var ( + ErrBusyPinTimeout = errors.New("busy pin timeout") + ErrDataTooLong = errors.New("data over 256 bytes") + ErrInvalidSleepConfig = errors.New("invalid sleep config") + ErrInvalidStandbyConfig = errors.New("invalid standby config") + ErrFrequencyTooLow = errors.New("frequency below 2.4Ghz") + ErrFrequencyTooHigh = errors.New("frequency above 2.5Ghz") + ErrPowerTooLow = errors.New("power level below -18dBm") + ErrPowerTooHigh = errors.New("power level above 13dBm") + ErrInvalidPeriodBase = errors.New("invalid period base") + ErrInvalidPacketType = errors.New("invalid packet type") + ErrInvalidRegulatorMode = errors.New("invalid regulator mode") + ErrPayloadLengthTooShort = errors.New("payload length too short") + ErrPayloadLengthTooLong = errors.New("payload length too long") +) diff --git a/sx128x/registers.go b/sx128x/registers.go index edba774c8..83cd9db52 100644 --- a/sx128x/registers.go +++ b/sx128x/registers.go @@ -1,195 +1,6 @@ package sx128x -type SleepConfig = uint8 -type StandbyConfig = uint8 -type PeriodBase = uint8 -type PacketType = uint8 -type RadioRampTime = uint8 -type CadSymbolNum = uint8 -type SpreadingFactor = uint8 -type Bandwidth = uint8 -type CodingRate = uint8 -type RegulatorMode = uint8 - -type CircuitMode = uint8 -type CommandStatus = uint8 - const ( - // SX128X SPI commands - CMD_NOP = uint8(0x00) - - CMD_SET_UART_SPEED = uint8(0x9D) - CMD_GET_STATUS = uint8(0xC0) - - // Register Access Operations - CMD_WRITE_REGISTER = uint8(0x18) - CMD_READ_REGISTER = uint8(0x19) - - // Data Buffer Operations - CMD_WRITE_BUFFER = uint8(0x1A) - CMD_READ_BUFFER = uint8(0x1B) - - // Radio Operation Modes - CMD_SET_SLEEP = uint8(0x84) - CMD_SET_STANDBY = uint8(0x80) - CMD_SET_FS = uint8(0xC1) - CMD_SET_TX = uint8(0x83) - CMD_SET_RX = uint8(0x82) - CMD_SET_RX_DUTY_CYCLE = uint8(0x94) - CMD_SET_LONG_PREAMBLE = uint8(0x9B) - CMD_SET_CAD = uint8(0xC5) - CMD_SET_TX_CONTINUOUS_WAVE = uint8(0xD1) - CMD_SET_TX_CONTINUOUS_PREAMBLE = uint8(0xD2) - CMD_SET_AUTO_TX = uint8(0x98) - CMD_SET_AUTO_FS = uint8(0x9E) - - // Radio Configuration - CMD_SET_PACKET_TYPE = uint8(0x8A) - CMD_GET_PACKET_TYPE = uint8(0x03) - CMD_SET_RF_FREQUENCY = uint8(0x86) - CMD_SET_TX_PARAMS = uint8(0x8E) - CMD_SET_CAD_PARAMS = uint8(0x88) - CMD_SET_BUFFER_BASE_ADDRESS = uint8(0x8F) - CMD_SET_MODULATION_PARAMS = uint8(0x8B) - CMD_SET_PACKET_PARAMS = uint8(0x8C) - - // Communication Status Information - CMD_GET_RX_BUFFER_STATUS = uint8(0x17) - CMD_GET_PACKET_STATUS = uint8(0x1D) - CMD_GET_RSSI_INST = uint8(0x1F) - - // IRQ Handling - CMD_SET_DIO_IRQ_PARAMS = uint8(0x8D) - CMD_GET_IRQ_STATUS = uint8(0x15) - CMD_CLEAR_IRQ_STATUS = uint8(0x97) - - // Miscellaneous - CMD_SET_REGULATOR_MODE = uint8(0x96) - CMD_SET_SAVE_CONTEXT = uint8(0xD5) - - // GetStatus - CIRCUIT_MODE_MASK = uint8(0b11100000) - CIRCUIT_MODE_STDBY_RC = CircuitMode(0x2) - CIRCUIT_MODE_STDBY_XOSC = CircuitMode(0x3) - CIRCUIT_MODE_FS = CircuitMode(0x4) - CIRCUIT_MODE_RX = CircuitMode(0x5) - CIRCUIT_MODE_TX = CircuitMode(0x6) - - COMMAND_STATUS_MASK = uint8(0b00011100) - COMMAND_STATUS_SUCCESS = CommandStatus(0x1) - COMMAND_STATUS_DATA_AVAILABLE = CommandStatus(0x2) - COMMAND_STATUS_TIMEOUT = CommandStatus(0x3) - COMMAND_STATUS_PROCESSING_ERROR = CommandStatus(0x4) - COMMAND_STATUS_EXECUTION_ERROR = CommandStatus(0x5) - COMMAND_STATUS_TX_DONE = CommandStatus(0x6) - - // SleepConfig - SLEEP_DATA_BUFFER_RETAIN = SleepConfig(2) - SLEEP_DATA_RAM_RETAIN = SleepConfig(1) - - // StandbyConfig - STANDBY_RC = StandbyConfig(0) - STANDBY_XOSC = StandbyConfig(1) - - // PeriodBase - PERIOD_BASE_15_625_US = PeriodBase(0) - PERIOD_BASE_62_5_US = PeriodBase(1) - PERIOD_BASE_1_MS = PeriodBase(2) - PERIOD_BASE_4_MS = PeriodBase(3) - - RX_CONTINUOUS_MODE = uint16(0xFFFF) - - // LongPreamble - LONG_PREAMBLE_ENABLE = uint8(1) - LONG_PREAMBLE_DISABLE = uint8(0) - - // AutoFs - AUTO_FS_ENABLE = uint8(1) - AUTO_FS_DISABLE = uint8(0) - - // PacketType - PACKET_TYPE_GFSK = PacketType(0x00) // default - PACKET_TYPE_LORA = PacketType(0x01) - PACKET_TYPE_RANGING = PacketType(0x02) - PACKET_TYPE_FLRC = PacketType(0x03) - PACKET_TYPE_BLE = PacketType(0x04) - - // RampTime - RADIO_RAMP_02_US = RadioRampTime(0x00) - RADIO_RAMP_04_US = RadioRampTime(0x20) - RADIO_RAMP_06_US = RadioRampTime(0x40) - RADIO_RAMP_08_US = RadioRampTime(0x60) - RADIO_RAMP_10_US = RadioRampTime(0x80) - RADIO_RAMP_12_US = RadioRampTime(0xA0) - RADIO_RAMP_16_US = RadioRampTime(0xC0) - RADIO_RAMP_20_US = RadioRampTime(0xE0) - - // CadSymbolNum - LORA_CAD_01_SYMBOL = CadSymbolNum(0x00) - LORA_CAD_02_SYMBOLS = CadSymbolNum(0x20) - LORA_CAD_04_SYMBOLS = CadSymbolNum(0x40) - LORA_CAD_08_SYMBOLS = CadSymbolNum(0x60) - LORA_CAD_16_SYMBOLS = CadSymbolNum(0x80) - - // SpreadingFactor - LORA_SF_5 = SpreadingFactor(0x50) - LORA_SF_6 = SpreadingFactor(0x60) - LORA_SF_7 = SpreadingFactor(0x70) - LORA_SF_8 = SpreadingFactor(0x80) - LORA_SF_9 = SpreadingFactor(0x90) - LORA_SF_10 = SpreadingFactor(0xA0) - LORA_SF_11 = SpreadingFactor(0xB0) - LORA_SF_12 = SpreadingFactor(0xC0) - - // Bandwidth - LORA_BW_1600 = Bandwidth(0x0A) - LORA_BW_800 = Bandwidth(0x18) - LORA_BW_400 = Bandwidth(0x26) - LORA_BW_200 = Bandwidth(0x34) - - // CodingRate - LORA_CR_4_5 = CodingRate(0x01) - LORA_CR_4_6 = CodingRate(0x02) - LORA_CR_4_7 = CodingRate(0x03) - LORA_CR_4_8 = CodingRate(0x04) - LORA_CR_LI_4_5 = CodingRate(0x05) - LORA_CR_LI_4_6 = CodingRate(0x06) - LORA_CR_LI_4_8 = CodingRate(0x07) - - // LoraPacketParams - LORA_EXPLICIT_HEADER = uint8(0x00) - LORA_IMPLICIT_HEADER = uint8(0x80) - - LORA_CRC_ENABLE = uint8(0x20) - LORA_CRC_DISABLE = uint8(0x00) - - LORA_IQ_INVERTED = uint8(0x00) - LORA_IQ_STD = uint8(0x40) - - // RegulatorMode - REGULATOR_LDO = RegulatorMode(0) - REGULATOR_DC_DC = RegulatorMode(1) - - // IRQ masks - IRQ_ALL_MASK = uint16(0xFFFF) - IRQ_NONE_MASK = uint16(0x0000) - IRQ_TX_DONE_MASK = uint16(0b0000000000000001) - IRQ_RX_DONE_MASK = uint16(0b0000000000000010) - IRQ_SYNC_WORD_VALID_MASK = uint16(0b0000000000000100) - IRQ_SYNC_WORD_ERROR_MASK = uint16(0b0000000000001000) - IRQ_HEADER_VALID_MASK = uint16(0b0000000000010000) - IRQ_HEADER_ERROR_MASK = uint16(0b0000000000100000) - IRQ_CRC_ERROR_MASK = uint16(0b0000000001000000) - IRQ_RANGING_SLAVE_RESPONSE_DONE_MASK = uint16(0b0000000010000000) - IRQ_RANGING_SLAVE_RESPONSE_DISCARD_MASK = uint16(0b0000000100000000) - IRQ_RANGING_MASTER_RESULT_VALID_MASK = uint16(0b0000001000000000) - IRQ_RANGING_MASTER_TIMEOUT_MASK = uint16(0b0000010000000000) - IRQ_RANGING_SLAVE_REQUEST_VALID_MASK = uint16(0b0000100000000000) - IRQ_CAD_DONE_MASK = uint16(0b0001000000000000) - IRQ_CAD_DETECTED_MASK = uint16(0b0010000000000000) - IRQ_RX_TX_TIMEOUT_MASK = uint16(0b0100000000000000) - IRQ_PREAMBLE_DETECTED_MASK = uint16(0b1000000000000000) - IRQ_ADVANCED_RANGING_DONE_MASK = uint16(0b1000000000000000) // SX128X register map REG_FIRMWARE_VERSIONS = uint16(0x153) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 7540d6b80..84ea90470 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -1,7 +1,6 @@ package sx128x import ( - "errors" "runtime" "time" @@ -24,8 +23,8 @@ func New(spi drivers.SPI, nssPin pin.Output, resetPin pin.Output, busyPin pin.In nssPin: nssPin, resetPin: resetPin, busyPin: busyPin, - spiTxBuf: make([]byte, 255), // TODO: optimize buffer size - spiRxBuf: make([]byte, 255), + spiTxBuf: make([]byte, 256), // TODO: optimize buffer size + spiRxBuf: make([]byte, 256), } } @@ -41,7 +40,7 @@ func (d *Device) WaitWhileBusy(timeout time.Duration) error { now := time.Now() for d.busyPin.Get() { if time.Since(now) > timeout { - return errors.New("busy pin timeout") + return ErrBusyPinTimeout } runtime.Gosched() } @@ -99,8 +98,8 @@ func (d *Device) ReadRegister(addr uint16) (uint8, error) { } func (d *Device) WriteBuffer(offset uint8, data []byte) error { - if len(data) > 255 { - return errors.New("length of data over max length of 255") + if len(data) > 256 { + return ErrDataTooLong } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -138,8 +137,8 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { // Set the device into sleep mode with the given configuration: 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention) func (d *Device) SetSleep(sleepConfig SleepConfig) error { - if sleepConfig > 3 { - return errors.New("sleep config must be 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention)") + if sleepConfig > (SLEEP_DATA_BUFFER_RETAIN | SLEEP_DATA_RAM_RETAIN) { + return ErrInvalidSleepConfig } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -155,8 +154,8 @@ func (d *Device) SetSleep(sleepConfig SleepConfig) error { // Put device into standby mode, 0 (RC) or 1 (XOSC) func (d *Device) SetStandby(standbyConfig StandbyConfig) error { - if standbyConfig != STANDBY_RC && standbyConfig != STANDBY_XOSC { - return errors.New("standby config must be 0 (RC) or 1 (XOSC)") + if standbyConfig > STANDBY_XOSC { // XOSC is the highest standby config anything higher is invalid + return ErrInvalidStandbyConfig } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -185,8 +184,8 @@ func (d *Device) SetFs() error { } func checkPeriodBase(periodBase PeriodBase) error { - if periodBase != PERIOD_BASE_15_625_US && periodBase != PERIOD_BASE_62_5_US && periodBase != PERIOD_BASE_1_MS && periodBase != PERIOD_BASE_4_MS { - return errors.New("period base must be 0, 1, 2 or 4") + if periodBase > PERIOD_BASE_4_MS { // 4ms is the highest period base anything higher is invalid + return ErrInvalidPeriodBase } return nil } @@ -260,9 +259,9 @@ func (d *Device) SetLongPreamble(enable bool) error { d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_LONG_PREAMBLE) if enable { - d.spiTxBuf = append(d.spiTxBuf, LONG_PREAMBLE_ENABLE) + d.spiTxBuf = append(d.spiTxBuf, 1) } else { - d.spiTxBuf = append(d.spiTxBuf, LONG_PREAMBLE_DISABLE) + d.spiTxBuf = append(d.spiTxBuf, 0) } err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -340,9 +339,9 @@ func (d *Device) SetAutoFs(enable bool) error { d.spiTxBuf = d.spiTxBuf[:0] d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_FS) if enable { - d.spiTxBuf = append(d.spiTxBuf, AUTO_FS_ENABLE) + d.spiTxBuf = append(d.spiTxBuf, 1) } else { - d.spiTxBuf = append(d.spiTxBuf, AUTO_FS_DISABLE) + d.spiTxBuf = append(d.spiTxBuf, 0) } err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -351,6 +350,9 @@ func (d *Device) SetAutoFs(enable bool) error { // Choose between GFSK, LoRa, Ranging, FLRC or BLE packet types, this will affect the available configuration parameters and the structure of the packet func (d *Device) SetPacketType(packetType PacketType) error { + if packetType > PACKET_TYPE_BLE { // BLE is the highest packet type anything higher is invalid. + return ErrInvalidPacketType + } err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -384,10 +386,10 @@ func (d *Device) GetPacketType() (PacketType, error) { // Set the RF frequency in Hz, must be between 2.4 GHz and 2.5 GHz func (d *Device) SetRfFrequency(frequencyHz uint32) error { if frequencyHz < 2400000000 { - return errors.New("frequency must be greater than or equal to 2.4 GHz") + return ErrFrequencyTooLow } if frequencyHz > 2500000000 { - return errors.New("frequency must be less than or equal to 2.5 GHz") + return ErrFrequencyTooHigh } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -395,8 +397,8 @@ func (d *Device) SetRfFrequency(frequencyHz uint32) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - freq := uint32((uint64(frequencyHz) << 18) / 52000000) - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((freq>>16)&0xFF), uint8((freq>>8)&0xFF), uint8(freq&0xFF)) + rfFrequency := uint32((uint64(frequencyHz) << 18) / 52000000) + d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((rfFrequency>>16)&0xFF), uint8((rfFrequency>>8)&0xFF), uint8(rfFrequency&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -405,10 +407,10 @@ func (d *Device) SetRfFrequency(frequencyHz uint32) error { // Set the output power in dBm, must be between -18 and 13 dBm, and the ramp time func (d *Device) SetTxParams(powerdBm int8, rampTime RadioRampTime) error { if powerdBm < -18 { - return errors.New("power in dBm must be greater than or equal to -18") + return ErrPowerTooLow } if powerdBm > 13 { - return errors.New("power in dBm must be less than or equal to 13") + return ErrPowerTooHigh } err := d.WaitWhileBusy(time.Second) @@ -454,6 +456,7 @@ func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { return err } +// The arguments to this function depend on the packet type. It is recommended to use the mode specific functions for a better experience. // BLE & GFSK: BitrateBandwidth, ModulationIndex, ModulationShaping // FLRC: BitrateBandwidth, CodingRate, ModulationShaping // LoRa & Ranging: SpreadingFactor, Bandwidth, CodingRate @@ -470,22 +473,23 @@ func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) erro return err } -func (d *Device) SetModulationParamsBLE(bitrateBandwidth uint8, modulationIndex uint8, modulationShaping uint8) error { +func (d *Device) SetModulationParamsBLE(bitrateBandwidth BLEBitrateBandwidth, modulationIndex BLEModulationIndex, modulationShaping BLEModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) } -func (d *Device) SetModulationParamsGFSK(bitrateBandwidth uint8, modulationIndex uint8, modulationShaping uint8) error { +func (d *Device) SetModulationParamsGFSK(bitrateBandwidth GFSKBitrateBandwidth, modulationIndex GFSKModulationIndex, modulationShaping GFSKModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) } -func (d *Device) SetModulationParamsFLRC(bitrateBandwidth uint8, codingRate uint8, modulationShaping uint8) error { +func (d *Device) SetModulationParamsFLRC(bitrateBandwidth FLRCBitrateBandwidth, codingRate FLRCCodingRate, modulationShaping FLRCModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, codingRate, modulationShaping) } -func (d *Device) SetModulationParamsLoRa(spreadingFactor SpreadingFactor, bandwidth Bandwidth, codingRate CodingRate) error { +func (d *Device) SetModulationParamsLoRa(spreadingFactor LoRaSpreadingFactor, bandwidth LoRaBandwidth, codingRate LoRaCodingRate) error { return d.SetModulationParams(spreadingFactor, bandwidth, codingRate) } +// The arguments to this function depend on the packet type. It is recommended to use the mode specific functions for a better experience. // GFSK & FLRC: PreambleLength, SyncWordLength, SyncWordMatch, HeaderType, PayloadLength, CrcLength, Whitening // BLE: ConnectionState, CrcLength, BleTestPayload, Whitening // LoRa & Ranging: PreambleLength, HeaderType, PayloadLength, CRC, InvertIQ/chirp invert @@ -502,19 +506,47 @@ func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, return err } -func (d *Device) SetPacketParamsGFSK(preambleLength uint8, syncWordLength uint8, syncWordMatch uint8, headerType uint8, payloadLength uint8, crcLength uint8, whitening uint8) error { - return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whitening) +// Set GFSK related packet parameters, this assumes the packet type is already set to GFSK. +// - payloadLength: range of 0-255 +func (d *Device) SetPacketParamsGFSK(preambleLength GFSKPreambleLength, syncWordLength GFSKSyncWordLength, syncWordMatch GFSKSyncWordMatch, headerType GFSKHeaderType, payloadLength uint8, crcLength GFSKCrcType, whitening bool) error { + var whiteningVal uint8 + if whitening { + whiteningVal = WHITENING_ENABLE + } else { + whiteningVal = WHITENING_DISABLE + } + return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningVal) } -func (d *Device) SetPacketParamsFLRC(preambleLength uint8, syncWordLength uint8, syncWordMatch uint8, headerType uint8, payloadLength uint8, crcLength uint8, whitening uint8) error { - return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whitening) +// Set FLRC related packet parameters, this assumes the packet type is already set to FLRC. +// - payloadLength: range of 6-127 +func (d *Device) SetPacketParamsFLRC(preambleLength FLRCPreambleLength, syncWordLength FLRCSyncWordLength, syncWordMatch FLRCSyncWordMatch, headerType FLRCHeaderType, payloadLength uint8, crcLength FLRCCrcType) error { + if payloadLength < 6 { + return ErrPayloadLengthTooShort + } + if payloadLength > 127 { + return ErrPayloadLengthTooLong + } + return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, WHITENING_DISABLE) } -func (d *Device) SetPacketParamsBLE(connectionState uint8, crcLength uint8, bleTestPayload uint8, whitening uint8) error { - return d.SetPacketParams(connectionState, crcLength, bleTestPayload, whitening, 0, 0, 0) +// Set BLE related packet parameters, this assumes the packet type is already set to BLE. +func (d *Device) SetPacketParamsBLE(connectionState BLEConnectionState, crcLength BLECrcType, bleTestPayload BLETestPayload, whitening bool) error { + var whiteningVal uint8 + if whitening { + whiteningVal = WHITENING_ENABLE + } else { + whiteningVal = WHITENING_DISABLE + } + return d.SetPacketParams(connectionState, crcLength, bleTestPayload, whiteningVal, 0, 0, 0) } -func (d *Device) SetPacketParamsLoRa(preambleLength uint32, headerType uint8, payloadLength uint8, crcType uint8, iqType uint8) error { +// Set LoRa related packet parameters, this assumes the packet type is already set to LoRa. +// - payloadLength: range of 1-255 +func (d *Device) SetPacketParamsLoRa(preambleLength uint32, headerType LoRaHeaderType, payloadLength uint8, crcType LoRaCrcType, iqType LoRaIqType) error { + if payloadLength == 0 { + return ErrPayloadLengthTooShort + } exponent, mantissa := getExponentAndMantissa(preambleLength) return d.SetPacketParams(uint8(exponent<<4)|mantissa, headerType, payloadLength, crcType, iqType, 0, 0) } @@ -558,6 +590,9 @@ func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { return d.spiRxBuf[2], d.spiRxBuf[3], nil } +// The return type of this function depends on the packet type. Use mode specific function for typed returns. +// BLE, GFSK & FLRC: unused, rssiSync, errors, status, sync +// LoRa & Ranging: rssiSync, SNR func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { err := d.WaitWhileBusy(time.Second) if err != nil { @@ -575,8 +610,67 @@ func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { return d.spiRxBuf[2], d.spiRxBuf[3], d.spiRxBuf[4], d.spiRxBuf[5], d.spiRxBuf[6], nil } +// Get information about the most recent GFSK packet received or transmitted: +// - RSSI of last received packet +// - packet information (each bit represents a different error or status flag) +// - whether the last packet transmission has ended +// - the sync word that was used for the last packet reception (0-3) +func (d *Device) GetPacketStatusGFSK() (float32, GFSKPacketInfo, bool, uint8, error) { + _, rssiSync, packetInfo, status, sync, err := d.GetPacketStatus() + if err != nil { + return 0, 0, false, 0, err + } + return float32(int8(rssiSync)) / 2 * -1, GFSKPacketInfo(packetInfo), status != 0, sync, nil +} + +// Get information about the most recent BLE packet received or transmitted: +// - RSSI of last received packet +// - packet information (each bit represents a different error or status flag) +// - whether the last packet transmission has ended +// - the sync word that was used for the last packet reception (0-1) +func (d *Device) GetPacketStatusBLE() (float32, BLEPacketInfo, bool, uint8, error) { + _, rssiSync, packetInfo, status, sync, err := d.GetPacketStatus() + if err != nil { + return 0, 0, false, 0, err + } + return float32(int8(rssiSync)) / 2 * -1, BLEPacketInfo(packetInfo), status != 0, sync, nil +} + +// Get information about the most recent BLE packet received or transmitted: +// - RSSI of last received packet +// - packet information (each bit represents a different error or status flag) +// - PID field of the received packet +// - NO_ACK field of the received packet +// - PID check status of the current packet +// - whether the last packet transmission has ended +// - the sync word that was used for the last packet reception (0-1) +func (d *Device) GetPacketStatusFLRC() (float32, FLRCPacketInfo, uint8, bool, bool, bool, uint8, error) { + _, rawRSSI, packetInfo, rxTxInfo, sync, err := d.GetPacketStatus() + + rxPid := (rxTxInfo & 0b11000000) >> 6 + noAck := (rxTxInfo & 0b00100000) != 0 + pidCheck := (rxTxInfo & 0b00010000) != 0 + txDone := (rxTxInfo & 0b00000001) != 0 + + if err != nil { + return 0, 0, 0, false, false, false, 0, err + } + return float32(int8(rawRSSI)) / 2 * -1, FLRCPacketInfo(packetInfo), rxPid, noAck, pidCheck, txDone, sync, nil +} + +// Get information about the most recent LoRa packet received: +// - RSSI of last received packet +// - signal-to-noise ratio (SNR) of last received packet +func (d *Device) GetPacketStatusLoRa() (float32, float32, error) { + rawRSSI, rawSnr, _, _, _, err := d.GetPacketStatus() + if err != nil { + return 0, 0, err + } + return float32(int8(rawRSSI)) / 2 * -1, float32(int8(rawSnr)) / 4, nil +} + // Get the instantaneous RSSI value during reception of the packet -func (d *Device) GetRssiInst() (int8, error) { +func (d *Device) GetRssiInst() (float32, error) { err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err @@ -590,11 +684,11 @@ func (d *Device) GetRssiInst() (int8, error) { if err != nil { return 0, err } - return int8(d.spiRxBuf[2]/2) * -1, nil + return float32(int8(d.spiRxBuf[2])) / 2 * -1, nil } // Configure the overall IRQ mask and the mapping of individual IRQs to the DIO1, DIO2 and DIO3 pins -func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint16, dio3Mask uint16) error { +func (d *Device) SetDioIrqParams(irqMask IRQMask, dio1Mask IRQMask, dio2Mask IRQMask, dio3Mask IRQMask) error { err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -611,7 +705,7 @@ func (d *Device) SetDioIrqParams(irqMask uint16, dio1Mask uint16, dio2Mask uint1 } // Get the current IRQ status. -func (d *Device) GetIrqStatus() (uint16, error) { +func (d *Device) GetIrqStatus() (IRQMask, error) { err := d.WaitWhileBusy(time.Second) if err != nil { return 0, err @@ -629,7 +723,7 @@ func (d *Device) GetIrqStatus() (uint16, error) { } // Clear the IRQ bits specified in the irqMask. -func (d *Device) ClearIrqStatus(irqMask uint16) error { +func (d *Device) ClearIrqStatus(irqMask IRQMask) error { err := d.WaitWhileBusy(time.Second) if err != nil { return err @@ -644,8 +738,8 @@ func (d *Device) ClearIrqStatus(irqMask uint16) error { // Switch between the low-dropout regulator (LDO) and the DC-DC converter for internal power regulation. func (d *Device) SetRegulatorMode(mode RegulatorMode) error { - if mode != REGULATOR_LDO && mode != REGULATOR_DC_DC { - return errors.New("regulator mode must be 0 (LDO) or 1 (DC-DC)") + if mode > REGULATOR_DC_DC { // DC-DC is the highest regulator mode anything higher is invalid + return ErrInvalidRegulatorMode } err := d.WaitWhileBusy(time.Second) if err != nil { From 67e64b2d2496c3ae43d3f170440f4658ee6aaf01 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 30 Apr 2026 20:25:08 -0500 Subject: [PATCH 07/11] work on exporting less constants --- sx128x/commands.go | 69 +++++++++++++++++++------------------- sx128x/constants.go | 8 ++--- sx128x/sx128x.go | 80 ++++++++++++++++++++++----------------------- 3 files changed, 77 insertions(+), 80 deletions(-) diff --git a/sx128x/commands.go b/sx128x/commands.go index fa0eff042..fc294cdb6 100644 --- a/sx128x/commands.go +++ b/sx128x/commands.go @@ -2,54 +2,51 @@ package sx128x const ( // SX128X SPI commands - CMD_NOP = uint8(0x00) - - CMD_SET_UART_SPEED = uint8(0x9D) - CMD_GET_STATUS = uint8(0xC0) + cmdGetStatus = uint8(0xC0) // Register Access Operations - CMD_WRITE_REGISTER = uint8(0x18) - CMD_READ_REGISTER = uint8(0x19) + cmdWriteRegister = uint8(0x18) + cmdReadRegister = uint8(0x19) // Data Buffer Operations - CMD_WRITE_BUFFER = uint8(0x1A) - CMD_READ_BUFFER = uint8(0x1B) + cmdWriteBuffer = uint8(0x1A) + cmdReadBuffer = uint8(0x1B) // Radio Operation Modes - CMD_SET_SLEEP = uint8(0x84) - CMD_SET_STANDBY = uint8(0x80) - CMD_SET_FS = uint8(0xC1) - CMD_SET_TX = uint8(0x83) - CMD_SET_RX = uint8(0x82) - CMD_SET_RX_DUTY_CYCLE = uint8(0x94) - CMD_SET_LONG_PREAMBLE = uint8(0x9B) - CMD_SET_CAD = uint8(0xC5) - CMD_SET_TX_CONTINUOUS_WAVE = uint8(0xD1) - CMD_SET_TX_CONTINUOUS_PREAMBLE = uint8(0xD2) - CMD_SET_AUTO_TX = uint8(0x98) - CMD_SET_AUTO_FS = uint8(0x9E) + cmdSetSleep = uint8(0x84) + cmdSetStandby = uint8(0x80) + cmdSetFS = uint8(0xC1) + cmdSetTx = uint8(0x83) + cmdSetRx = uint8(0x82) + cmdSetRxDutyCycle = uint8(0x94) + cmdSetLongPreamble = uint8(0x9B) + cmdSetCAD = uint8(0xC5) + cmdSetTxContinuousWave = uint8(0xD1) + cmdSetContinuousPreamble = uint8(0xD2) + cmdSetAutoTx = uint8(0x98) + cmdSetAutoFS = uint8(0x9E) // Radio Configuration - CMD_SET_PACKET_TYPE = uint8(0x8A) - CMD_GET_PACKET_TYPE = uint8(0x03) - CMD_SET_RF_FREQUENCY = uint8(0x86) - CMD_SET_TX_PARAMS = uint8(0x8E) - CMD_SET_CAD_PARAMS = uint8(0x88) - CMD_SET_BUFFER_BASE_ADDRESS = uint8(0x8F) - CMD_SET_MODULATION_PARAMS = uint8(0x8B) - CMD_SET_PACKET_PARAMS = uint8(0x8C) + cmdSetPacketType = uint8(0x8A) + cmdGetPacketType = uint8(0x03) + cmdSetRFFrequency = uint8(0x86) + cmdSetTxParams = uint8(0x8E) + cmdSetCADParams = uint8(0x88) + cmdSetBufferBaseAddress = uint8(0x8F) + cmdSetModulationParams = uint8(0x8B) + cmdSetPacketParams = uint8(0x8C) // Communication Status Information - CMD_GET_RX_BUFFER_STATUS = uint8(0x17) - CMD_GET_PACKET_STATUS = uint8(0x1D) - CMD_GET_RSSI_INST = uint8(0x1F) + cmdGetRxBufferStatus = uint8(0x17) + cmdGetPacketStatus = uint8(0x1D) + cmdGetRSSIInst = uint8(0x1F) // IRQ Handling - CMD_SET_DIO_IRQ_PARAMS = uint8(0x8D) - CMD_GET_IRQ_STATUS = uint8(0x15) - CMD_CLEAR_IRQ_STATUS = uint8(0x97) + cmdSetDIOIRQParams = uint8(0x8D) + cmdGetIRQStatus = uint8(0x15) + cmdClearIRQStatus = uint8(0x97) // Miscellaneous - CMD_SET_REGULATOR_MODE = uint8(0x96) - CMD_SET_SAVE_CONTEXT = uint8(0xD5) + cmdSetRegulatorMode = uint8(0x96) + cmdSetSaveContext = uint8(0xD5) ) diff --git a/sx128x/constants.go b/sx128x/constants.go index 59918811e..8dc169695 100644 --- a/sx128x/constants.go +++ b/sx128x/constants.go @@ -65,11 +65,11 @@ type BLEPacketInfo = uint8 type FLRCPacketInfo = uint8 const ( - WHITENING_DISABLE = 0x00 - WHITENING_ENABLE = 0x08 + whiteningDisable = 0x00 + whiteningEnable = 0x08 // Circuit Mode - CIRCUIT_MODE_MASK = uint8(0b11100000) + circuitModeMask = uint8(0b11100000) CIRCUIT_MODE_STDBY_RC = CircuitMode(0x2) CIRCUIT_MODE_STDBY_XOSC = CircuitMode(0x3) CIRCUIT_MODE_FS = CircuitMode(0x4) @@ -77,7 +77,7 @@ const ( CIRCUIT_MODE_TX = CircuitMode(0x6) // Command Status - COMMAND_STATUS_MASK = uint8(0b00011100) + commandStatusMask = uint8(0b00011100) COMMAND_STATUS_SUCCESS = CommandStatus(0x1) COMMAND_STATUS_DATA_AVAILABLE = CommandStatus(0x2) COMMAND_STATUS_TIMEOUT = CommandStatus(0x3) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 84ea90470..ed3cf5fb8 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -54,15 +54,15 @@ func (d *Device) GetStatus() (CircuitMode, CommandStatus, error) { return 0, 0, err } d.nssPin.Set(false) - status, err := d.spi.Transfer(CMD_GET_STATUS) + status, err := d.spi.Transfer(cmdGetStatus) d.nssPin.Set(true) if err != nil { return 0, 0, err } - circuitMode := (status & CIRCUIT_MODE_MASK) >> 5 - commandStatus := (status & COMMAND_STATUS_MASK) >> 2 + circuitMode := (status & circuitModeMask) >> 5 + commandStatus := (status & commandStatusMask) >> 2 return circuitMode, commandStatus, nil } @@ -73,7 +73,7 @@ func (d *Device) WriteRegister(addr uint16, data []byte) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_REGISTER, uint8((addr>>8)&0xFF), uint8(addr&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdWriteRegister, uint8((addr>>8)&0xFF), uint8(addr&0xFF)) d.spiTxBuf = append(d.spiTxBuf, data...) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -87,7 +87,7 @@ func (d *Device) ReadRegister(addr uint16) (uint8, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_READ_REGISTER, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF), 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdReadRegister, uint8((addr&0xFF00)>>8), uint8(addr&0x00FF), 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:5] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -107,7 +107,7 @@ func (d *Device) WriteBuffer(offset uint8, data []byte) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_WRITE_BUFFER, offset) + d.spiTxBuf = append(d.spiTxBuf, cmdWriteBuffer, offset) d.spiTxBuf = append(d.spiTxBuf, data...) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -122,7 +122,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_READ_BUFFER, offset, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdReadBuffer, offset, 0x00) for i := uint8(0); i < length; i++ { d.spiTxBuf = append(d.spiTxBuf, 0x00) } @@ -146,7 +146,7 @@ func (d *Device) SetSleep(sleepConfig SleepConfig) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SLEEP, sleepConfig) + d.spiTxBuf = append(d.spiTxBuf, cmdSetSleep, sleepConfig) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -163,7 +163,7 @@ func (d *Device) SetStandby(standbyConfig StandbyConfig) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_STANDBY, standbyConfig) + d.spiTxBuf = append(d.spiTxBuf, cmdSetStandby, standbyConfig) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -177,7 +177,7 @@ func (d *Device) SetFs() error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_FS) + d.spiTxBuf = append(d.spiTxBuf, cmdSetFS) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -203,7 +203,7 @@ func (d *Device) SetTx(periodBase PeriodBase, periodBaseCount uint16) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetTx, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -222,7 +222,7 @@ func (d *Device) SetRx(periodBase PeriodBase, periodBaseCount uint16) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRx, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -242,7 +242,7 @@ func (d *Device) SetRxDutyCycle(periodBase PeriodBase, rxPeriodBaseCount uint16, } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RX_DUTY_CYCLE, periodBase, uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRxDutyCycle, periodBase, uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((sleepPeriodBaseCount&0xFF00)>>8), uint8(sleepPeriodBaseCount&0x00FF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -257,7 +257,7 @@ func (d *Device) SetLongPreamble(enable bool) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_LONG_PREAMBLE) + d.spiTxBuf = append(d.spiTxBuf, cmdSetLongPreamble) if enable { d.spiTxBuf = append(d.spiTxBuf, 1) } else { @@ -277,7 +277,7 @@ func (d *Device) SetCAD() error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD) + d.spiTxBuf = append(d.spiTxBuf, cmdSetCAD) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -292,7 +292,7 @@ func (d *Device) SetTxContinuousWave() error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_WAVE) + d.spiTxBuf = append(d.spiTxBuf, cmdSetTxContinuousWave) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -307,7 +307,7 @@ func (d *Device) SetTxContinuousPreamble() error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_CONTINUOUS_PREAMBLE) + d.spiTxBuf = append(d.spiTxBuf, cmdSetContinuousPreamble) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -322,7 +322,7 @@ func (d *Device) SetAutoTx(timeUs uint16) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_TX, uint8((timeUs&0xFF00)>>8), uint8(timeUs&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetAutoTx, uint8((timeUs&0xFF00)>>8), uint8(timeUs&0x00FF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -337,7 +337,7 @@ func (d *Device) SetAutoFs(enable bool) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_AUTO_FS) + d.spiTxBuf = append(d.spiTxBuf, cmdSetAutoFS) if enable { d.spiTxBuf = append(d.spiTxBuf, 1) } else { @@ -359,7 +359,7 @@ func (d *Device) SetPacketType(packetType PacketType) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_TYPE, packetType) + d.spiTxBuf = append(d.spiTxBuf, cmdSetPacketType, packetType) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -373,7 +373,7 @@ func (d *Device) GetPacketType() (PacketType, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_TYPE, 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdGetPacketType, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:3] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -398,7 +398,7 @@ func (d *Device) SetRfFrequency(frequencyHz uint32) error { d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] rfFrequency := uint32((uint64(frequencyHz) << 18) / 52000000) - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_RF_FREQUENCY, uint8((rfFrequency>>16)&0xFF), uint8((rfFrequency>>8)&0xFF), uint8(rfFrequency&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRFFrequency, uint8((rfFrequency>>16)&0xFF), uint8((rfFrequency>>8)&0xFF), uint8(rfFrequency&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -420,7 +420,7 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime RadioRampTime) error { d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] adjustedPower := uint8(powerdBm + 18) - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_TX_PARAMS, adjustedPower, rampTime) + d.spiTxBuf = append(d.spiTxBuf, cmdSetTxParams, adjustedPower, rampTime) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -435,7 +435,7 @@ func (d *Device) SetCadParams(cadSymbolNum uint8) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_CAD_PARAMS, cadSymbolNum) + d.spiTxBuf = append(d.spiTxBuf, cmdSetCADParams, cadSymbolNum) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -450,7 +450,7 @@ func (d *Device) SetBufferBaseAddress(txBase uint8, rxBase uint8) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_BUFFER_BASE_ADDRESS, txBase, rxBase) + d.spiTxBuf = append(d.spiTxBuf, cmdSetBufferBaseAddress, txBase, rxBase) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -467,7 +467,7 @@ func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) erro } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_MODULATION_PARAMS, modParam1, modParam2, modParam3) + d.spiTxBuf = append(d.spiTxBuf, cmdSetModulationParams, modParam1, modParam2, modParam3) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -500,7 +500,7 @@ func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_PACKET_PARAMS, param1, param2, param3, param4, param5, param6, param7) + d.spiTxBuf = append(d.spiTxBuf, cmdSetPacketParams, param1, param2, param3, param4, param5, param6, param7) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -511,9 +511,9 @@ func (d *Device) SetPacketParams(param1, param2, param3, param4, param5, param6, func (d *Device) SetPacketParamsGFSK(preambleLength GFSKPreambleLength, syncWordLength GFSKSyncWordLength, syncWordMatch GFSKSyncWordMatch, headerType GFSKHeaderType, payloadLength uint8, crcLength GFSKCrcType, whitening bool) error { var whiteningVal uint8 if whitening { - whiteningVal = WHITENING_ENABLE + whiteningVal = whiteningEnable } else { - whiteningVal = WHITENING_DISABLE + whiteningVal = whiteningDisable } return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningVal) } @@ -527,16 +527,16 @@ func (d *Device) SetPacketParamsFLRC(preambleLength FLRCPreambleLength, syncWord if payloadLength > 127 { return ErrPayloadLengthTooLong } - return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, WHITENING_DISABLE) + return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningDisable) } // Set BLE related packet parameters, this assumes the packet type is already set to BLE. func (d *Device) SetPacketParamsBLE(connectionState BLEConnectionState, crcLength BLECrcType, bleTestPayload BLETestPayload, whitening bool) error { var whiteningVal uint8 if whitening { - whiteningVal = WHITENING_ENABLE + whiteningVal = whiteningEnable } else { - whiteningVal = WHITENING_DISABLE + whiteningVal = whiteningDisable } return d.SetPacketParams(connectionState, crcLength, bleTestPayload, whiteningVal, 0, 0, 0) } @@ -580,7 +580,7 @@ func (d *Device) GetRxBufferStatus() (uint8, uint8, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RX_BUFFER_STATUS, 0x00, 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdGetRxBufferStatus, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:4] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -600,7 +600,7 @@ func (d *Device) GetPacketStatus() (uint8, uint8, uint8, uint8, uint8, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_GET_PACKET_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdGetPacketStatus, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:7] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -677,7 +677,7 @@ func (d *Device) GetRssiInst() (float32, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_GET_RSSI_INST, 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdGetRSSIInst, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:3] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -695,7 +695,7 @@ func (d *Device) SetDioIrqParams(irqMask IRQMask, dio1Mask IRQMask, dio2Mask IRQ } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_DIO_IRQ_PARAMS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetDIOIRQParams, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio1Mask&0xFF00)>>8), uint8(dio1Mask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio2Mask&0xFF00)>>8), uint8(dio2Mask&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((dio3Mask&0xFF00)>>8), uint8(dio3Mask&0x00FF)) @@ -712,7 +712,7 @@ func (d *Device) GetIrqStatus() (IRQMask, error) { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_GET_IRQ_STATUS, 0x00, 0x00, 0x00) + d.spiTxBuf = append(d.spiTxBuf, cmdGetIRQStatus, 0x00, 0x00, 0x00) d.spiRxBuf = d.spiRxBuf[:4] err = d.spi.Tx(d.spiTxBuf, d.spiRxBuf) d.nssPin.Set(true) @@ -730,7 +730,7 @@ func (d *Device) ClearIrqStatus(irqMask IRQMask) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_CLEAR_IRQ_STATUS, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, cmdClearIRQStatus, uint8((irqMask&0xFF00)>>8), uint8(irqMask&0x00FF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -747,7 +747,7 @@ func (d *Device) SetRegulatorMode(mode RegulatorMode) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_REGULATOR_MODE, mode) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRegulatorMode, mode) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -761,7 +761,7 @@ func (d *Device) SetSaveContext() error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, CMD_SET_SAVE_CONTEXT) + d.spiTxBuf = append(d.spiTxBuf, cmdSetSaveContext) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err From 26769eec45a4c4e77b0bbbc508672bab3cc885bf Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 30 Apr 2026 20:42:17 -0500 Subject: [PATCH 08/11] only export "actionable" errors --- sx128x/errors.go | 24 ++++++++++++------------ sx128x/sx128x.go | 26 +++++++++++++------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/sx128x/errors.go b/sx128x/errors.go index 9ec5261f0..e81b812a6 100644 --- a/sx128x/errors.go +++ b/sx128x/errors.go @@ -4,16 +4,16 @@ import "errors" var ( ErrBusyPinTimeout = errors.New("busy pin timeout") - ErrDataTooLong = errors.New("data over 256 bytes") - ErrInvalidSleepConfig = errors.New("invalid sleep config") - ErrInvalidStandbyConfig = errors.New("invalid standby config") - ErrFrequencyTooLow = errors.New("frequency below 2.4Ghz") - ErrFrequencyTooHigh = errors.New("frequency above 2.5Ghz") - ErrPowerTooLow = errors.New("power level below -18dBm") - ErrPowerTooHigh = errors.New("power level above 13dBm") - ErrInvalidPeriodBase = errors.New("invalid period base") - ErrInvalidPacketType = errors.New("invalid packet type") - ErrInvalidRegulatorMode = errors.New("invalid regulator mode") - ErrPayloadLengthTooShort = errors.New("payload length too short") - ErrPayloadLengthTooLong = errors.New("payload length too long") + errDataTooLong = errors.New("data over 256 bytes") + errInvalidSleepConfig = errors.New("invalid sleep config") + errInvalidStandbyConfig = errors.New("invalid standby config") + errFrequencyTooLow = errors.New("frequency below 2.4Ghz") + errFrequencyTooHigh = errors.New("frequency above 2.5Ghz") + errPowerTooLow = errors.New("power level below -18dBm") + errPowerTooHigh = errors.New("power level above 13dBm") + errInvalidPeriodBase = errors.New("invalid period base") + errInvalidPacketType = errors.New("invalid packet type") + errInvalidRegulatorMode = errors.New("invalid regulator mode") + errPayloadLengthTooShort = errors.New("payload length too short") + errPayloadLengthTooLong = errors.New("payload length too long") ) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index ed3cf5fb8..2e6c64d59 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -99,7 +99,7 @@ func (d *Device) ReadRegister(addr uint16) (uint8, error) { func (d *Device) WriteBuffer(offset uint8, data []byte) error { if len(data) > 256 { - return ErrDataTooLong + return errDataTooLong } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -138,7 +138,7 @@ func (d *Device) ReadBuffer(offset uint8, length uint8) ([]byte, error) { // Set the device into sleep mode with the given configuration: 0 (no retention), 1 (ram retentation), 2 (buffer retention) or 3 (ram and buffer retention) func (d *Device) SetSleep(sleepConfig SleepConfig) error { if sleepConfig > (SLEEP_DATA_BUFFER_RETAIN | SLEEP_DATA_RAM_RETAIN) { - return ErrInvalidSleepConfig + return errInvalidSleepConfig } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -155,7 +155,7 @@ func (d *Device) SetSleep(sleepConfig SleepConfig) error { // Put device into standby mode, 0 (RC) or 1 (XOSC) func (d *Device) SetStandby(standbyConfig StandbyConfig) error { if standbyConfig > STANDBY_XOSC { // XOSC is the highest standby config anything higher is invalid - return ErrInvalidStandbyConfig + return errInvalidStandbyConfig } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -185,7 +185,7 @@ func (d *Device) SetFs() error { func checkPeriodBase(periodBase PeriodBase) error { if periodBase > PERIOD_BASE_4_MS { // 4ms is the highest period base anything higher is invalid - return ErrInvalidPeriodBase + return errInvalidPeriodBase } return nil } @@ -351,7 +351,7 @@ func (d *Device) SetAutoFs(enable bool) error { // Choose between GFSK, LoRa, Ranging, FLRC or BLE packet types, this will affect the available configuration parameters and the structure of the packet func (d *Device) SetPacketType(packetType PacketType) error { if packetType > PACKET_TYPE_BLE { // BLE is the highest packet type anything higher is invalid. - return ErrInvalidPacketType + return errInvalidPacketType } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -386,10 +386,10 @@ func (d *Device) GetPacketType() (PacketType, error) { // Set the RF frequency in Hz, must be between 2.4 GHz and 2.5 GHz func (d *Device) SetRfFrequency(frequencyHz uint32) error { if frequencyHz < 2400000000 { - return ErrFrequencyTooLow + return errFrequencyTooLow } if frequencyHz > 2500000000 { - return ErrFrequencyTooHigh + return errFrequencyTooHigh } err := d.WaitWhileBusy(time.Second) if err != nil { @@ -407,10 +407,10 @@ func (d *Device) SetRfFrequency(frequencyHz uint32) error { // Set the output power in dBm, must be between -18 and 13 dBm, and the ramp time func (d *Device) SetTxParams(powerdBm int8, rampTime RadioRampTime) error { if powerdBm < -18 { - return ErrPowerTooLow + return errPowerTooLow } if powerdBm > 13 { - return ErrPowerTooHigh + return errPowerTooHigh } err := d.WaitWhileBusy(time.Second) @@ -522,10 +522,10 @@ func (d *Device) SetPacketParamsGFSK(preambleLength GFSKPreambleLength, syncWord // - payloadLength: range of 6-127 func (d *Device) SetPacketParamsFLRC(preambleLength FLRCPreambleLength, syncWordLength FLRCSyncWordLength, syncWordMatch FLRCSyncWordMatch, headerType FLRCHeaderType, payloadLength uint8, crcLength FLRCCrcType) error { if payloadLength < 6 { - return ErrPayloadLengthTooShort + return errPayloadLengthTooShort } if payloadLength > 127 { - return ErrPayloadLengthTooLong + return errPayloadLengthTooLong } return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningDisable) } @@ -545,7 +545,7 @@ func (d *Device) SetPacketParamsBLE(connectionState BLEConnectionState, crcLengt // - payloadLength: range of 1-255 func (d *Device) SetPacketParamsLoRa(preambleLength uint32, headerType LoRaHeaderType, payloadLength uint8, crcType LoRaCrcType, iqType LoRaIqType) error { if payloadLength == 0 { - return ErrPayloadLengthTooShort + return errPayloadLengthTooShort } exponent, mantissa := getExponentAndMantissa(preambleLength) return d.SetPacketParams(uint8(exponent<<4)|mantissa, headerType, payloadLength, crcType, iqType, 0, 0) @@ -739,7 +739,7 @@ func (d *Device) ClearIrqStatus(irqMask IRQMask) error { // Switch between the low-dropout regulator (LDO) and the DC-DC converter for internal power regulation. func (d *Device) SetRegulatorMode(mode RegulatorMode) error { if mode > REGULATOR_DC_DC { // DC-DC is the highest regulator mode anything higher is invalid - return ErrInvalidRegulatorMode + return errInvalidRegulatorMode } err := d.WaitWhileBusy(time.Second) if err != nil { From 33d4ccbf6a1abe2d0f291c787727aaee1769047e Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 30 Apr 2026 20:49:23 -0500 Subject: [PATCH 09/11] combine identical constants --- sx128x/constants.go | 134 +++++++++++++------------------------------- sx128x/sx128x.go | 6 +- 2 files changed, 43 insertions(+), 97 deletions(-) diff --git a/sx128x/constants.go b/sx128x/constants.go index 8dc169695..c88a42b57 100644 --- a/sx128x/constants.go +++ b/sx128x/constants.go @@ -8,9 +8,9 @@ type RadioRampTime = uint8 type CadSymbolNum = uint8 // GFSK Modulation Params -type GFSKBitrateBandwidth = uint8 -type GFSKModulationIndex = uint8 -type GFSKModulationShaping = uint8 +type GFSKBLEBitrateBandwidth = uint8 +type ModulationIndex = uint8 +type ModulationShaping = uint8 // GFSK Packet Params type GFSKPreambleLength = uint8 @@ -19,11 +19,6 @@ type GFSKSyncWordMatch = uint8 type GFSKHeaderType = uint8 type GFSKCrcType = uint8 -// BLE Modulation Params -type BLEBitrateBandwidth = uint8 -type BLEModulationIndex = uint8 -type BLEModulationShaping = uint8 - // BLE Packet Params type BLEConnectionState = uint8 type BLECrcType = uint8 @@ -32,7 +27,6 @@ type BLETestPayload = uint8 // FLRC Modulation Params type FLRCBitrateBandwidth = uint8 type FLRCCodingRate = uint8 -type FLRCModulationShaping = uint8 // FLRC Packet Params type FLRCPreambleLength = uint8 @@ -53,9 +47,7 @@ type LoRaIqType = uint8 // Misc type RegulatorMode = uint8 - type IRQMask = uint16 - type CircuitMode = uint8 type CommandStatus = uint8 @@ -99,8 +91,6 @@ const ( PERIOD_BASE_1_MS = PeriodBase(2) PERIOD_BASE_4_MS = PeriodBase(3) - RX_CONTINUOUS_MODE = uint16(0xFFFF) - // PacketType PACKET_TYPE_GFSK = PacketType(0x00) // default PACKET_TYPE_LORA = PacketType(0x01) @@ -126,43 +116,43 @@ const ( LORA_CAD_16_SYMBOLS = CadSymbolNum(0x80) // GFSK Modulation Params - // Bitrate + Bandwidth - GFSK_BR_2_000_BW_2_4 = GFSKBitrateBandwidth(0x04) - GFSK_BR_1_600_BW_2_4 = GFSKBitrateBandwidth(0x28) - GFSK_BR_1_000_BW_2_4 = GFSKBitrateBandwidth(0x4C) - GFSK_BR_1_000_BW_1_2 = GFSKBitrateBandwidth(0x45) - GFSK_BR_0_800_BW_2_4 = GFSKBitrateBandwidth(0x70) - GFSK_BR_0_800_BW_1_2 = GFSKBitrateBandwidth(0x69) - GFSK_BR_0_500_BW_1_2 = GFSKBitrateBandwidth(0x8D) - GFSK_BR_0_500_BW_0_6 = GFSKBitrateBandwidth(0x86) - GFSK_BR_0_400_BW_1_2 = GFSKBitrateBandwidth(0xB1) - GFSK_BR_0_400_BW_0_6 = GFSKBitrateBandwidth(0xAA) - GFSK_BR_0_250_BW_0_6 = GFSKBitrateBandwidth(0xCE) - GFSK_BR_0_250_BW_0_3 = GFSKBitrateBandwidth(0xC7) - GFSK_BR_0_125_BW_0_3 = GFSKBitrateBandwidth(0xEF) - - // Modulation Index - GFS_MOD_IND_0_35 = GFSKModulationIndex(0x00) - GFS_MOD_IND_0_5 = GFSKModulationIndex(0x01) - GFS_MOD_IND_0_75 = GFSKModulationIndex(0x02) - GFS_MOD_IND_1_00 = GFSKModulationIndex(0x03) - GFS_MOD_IND_1_25 = GFSKModulationIndex(0x04) - GFS_MOD_IND_1_50 = GFSKModulationIndex(0x05) - GFS_MOD_IND_1_75 = GFSKModulationIndex(0x06) - GFS_MOD_IND_2_00 = GFSKModulationIndex(0x07) - GFS_MOD_IND_2_25 = GFSKModulationIndex(0x08) - GFS_MOD_IND_2_50 = GFSKModulationIndex(0x09) - GFS_MOD_IND_2_75 = GFSKModulationIndex(0x0A) - GFS_MOD_IND_3_00 = GFSKModulationIndex(0x0B) - GFS_MOD_IND_3_25 = GFSKModulationIndex(0x0C) - GFS_MOD_IND_3_50 = GFSKModulationIndex(0x0D) - GFS_MOD_IND_3_75 = GFSKModulationIndex(0x0E) - GFS_MOD_IND_4_00 = GFSKModulationIndex(0x0F) - - // GFSK Modulation Shaping - GFSK_MOD_SHAPING_OFF = GFSKModulationShaping(0x00) - GFSK_MOD_SHAPING_1_0 = GFSKModulationShaping(0x10) - GFSK_MOD_SHAPING_0_5 = GFSKModulationShaping(0x20) + // Bitrate + Bandwidth - same for BLE + GFSK_BLE_BR_2_000_BW_2_4 = GFSKBLEBitrateBandwidth(0x04) + GFSK_BLE_BR_1_600_BW_2_4 = GFSKBLEBitrateBandwidth(0x28) + GFSK_BLE_BR_1_000_BW_2_4 = GFSKBLEBitrateBandwidth(0x4C) + GFSK_BLE_BR_1_000_BW_1_2 = GFSKBLEBitrateBandwidth(0x45) + GFSK_BLE_BR_0_800_BW_2_4 = GFSKBLEBitrateBandwidth(0x70) + GFSK_BLE_BR_0_800_BW_1_2 = GFSKBLEBitrateBandwidth(0x69) + GFSK_BLE_BR_0_500_BW_1_2 = GFSKBLEBitrateBandwidth(0x8D) + GFSK_BLE_BR_0_500_BW_0_6 = GFSKBLEBitrateBandwidth(0x86) + GFSK_BLE_BR_0_400_BW_1_2 = GFSKBLEBitrateBandwidth(0xB1) + GFSK_BLE_BR_0_400_BW_0_6 = GFSKBLEBitrateBandwidth(0xAA) + GFSK_BLE_BR_0_250_BW_0_6 = GFSKBLEBitrateBandwidth(0xCE) + GFSK_BLE_BR_0_250_BW_0_3 = GFSKBLEBitrateBandwidth(0xC7) + GFSK_BLE_BR_0_125_BW_0_3 = GFSKBLEBitrateBandwidth(0xEF) + + // Modulation Index - same for BLE + MOD_IND_0_35 = ModulationIndex(0x00) + MOD_IND_0_5 = ModulationIndex(0x01) + MOD_IND_0_75 = ModulationIndex(0x02) + MOD_IND_1_00 = ModulationIndex(0x03) + MOD_IND_1_25 = ModulationIndex(0x04) + MOD_IND_1_50 = ModulationIndex(0x05) + MOD_IND_1_75 = ModulationIndex(0x06) + MOD_IND_2_00 = ModulationIndex(0x07) + MOD_IND_2_25 = ModulationIndex(0x08) + MOD_IND_2_50 = ModulationIndex(0x09) + MOD_IND_2_75 = ModulationIndex(0x0A) + MOD_IND_3_00 = ModulationIndex(0x0B) + MOD_IND_3_25 = ModulationIndex(0x0C) + MOD_IND_3_50 = ModulationIndex(0x0D) + MOD_IND_3_75 = ModulationIndex(0x0E) + MOD_IND_4_00 = ModulationIndex(0x0F) + + // Modulation Shaping - same for BLE and FLRC + MOD_SHAPING_OFF = ModulationShaping(0x00) + MOD_SHAPING_1_0 = ModulationShaping(0x10) + MOD_SHAPING_0_5 = ModulationShaping(0x20) // GFSK Packet Params // Preamble Length @@ -201,45 +191,6 @@ const ( GFSK_CRC_1_BYTE = GFSKCrcType(0x10) GFSK_CRC_2_BYTES = GFSKCrcType(0x20) - // BLE Modulation Params - // Bitrate + Bandwidth - BLE_BR_2_000_BW_2_4 = BLEBitrateBandwidth(0x04) - BLE_BR_1_600_BW_2_4 = BLEBitrateBandwidth(0x28) - BLE_BR_1_000_BW_2_4 = BLEBitrateBandwidth(0x4C) - BLE_BR_1_000_BW_1_2 = BLEBitrateBandwidth(0x45) - BLE_BR_0_800_BW_2_4 = BLEBitrateBandwidth(0x70) - BLE_BR_0_800_BW_1_2 = BLEBitrateBandwidth(0x69) - BLE_BR_0_500_BW_1_2 = BLEBitrateBandwidth(0x8D) - BLE_BR_0_500_BW_0_6 = BLEBitrateBandwidth(0x86) - BLE_BR_0_400_BW_1_2 = BLEBitrateBandwidth(0xB1) - BLE_BR_0_400_BW_0_6 = BLEBitrateBandwidth(0xAA) - BLE_BR_0_250_BW_0_6 = BLEBitrateBandwidth(0xCE) - BLE_BR_0_250_BW_0_3 = BLEBitrateBandwidth(0xC7) - BLE_BR_0_125_BW_0_3 = BLEBitrateBandwidth(0xEF) - - // Modulation Index - BLE_MOD_IND_0_35 = BLEModulationIndex(0x00) - BLE_MOD_IND_0_5 = BLEModulationIndex(0x01) - BLE_MOD_IND_0_75 = BLEModulationIndex(0x02) - BLE_MOD_IND_1 = BLEModulationIndex(0x03) - BLE_MOD_IND_1_25 = BLEModulationIndex(0x04) - BLE_MOD_IND_1_5 = BLEModulationIndex(0x05) - BLE_MOD_IND_1_75 = BLEModulationIndex(0x06) - BLE_MOD_IND_2 = BLEModulationIndex(0x07) - BLE_MOD_IND_2_25 = BLEModulationIndex(0x08) - BLE_MOD_IND_2_5 = BLEModulationIndex(0x09) - BLE_MOD_IND_2_75 = BLEModulationIndex(0x0A) - BLE_MOD_IND_3 = BLEModulationIndex(0x0B) - BLE_MOD_IND_3_25 = BLEModulationIndex(0x0C) - BLE_MOD_IND_3_5 = BLEModulationIndex(0x0D) - BLE_MOD_IND_3_75 = BLEModulationIndex(0x0E) - BLE_MOD_IND_4 = BLEModulationIndex(0x0F) - - // Modulation Shaping - BLE_MOD_SHAPING_OFF = BLEModulationShaping(0x00) - BLE_MOD_SHAPING_1_0 = BLEModulationShaping(0x10) - BLE_MOD_SHAPING_0_5 = BLEModulationShaping(0x20) - // BLE Packet Params // Connection State BLE_MASTER_SLAVE = BLEConnectionState(0x00) @@ -276,11 +227,6 @@ const ( FLRC_CR_3_4 = FLRCCodingRate(0x02) // 3/4 FLRC_CR_1_0 = FLRCCodingRate(0x04) // 1 - // Modulation Shaping - FLRC_MOD_SHAPING_OFF = FLRCModulationShaping(0x00) - FLRC_MOD_SHAPING_1_0 = FLRCModulationShaping(0x10) // 1 - FLRC_MOD_SHAPING_0_5 = FLRCModulationShaping(0x20) // 0.5 - // FLRC Packet Params // Preamble Length FLRC_PREAMBLE_LENGTH_4_BITS = FLRCPreambleLength(0x00) diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index 2e6c64d59..e5f972b3e 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -473,15 +473,15 @@ func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) erro return err } -func (d *Device) SetModulationParamsBLE(bitrateBandwidth BLEBitrateBandwidth, modulationIndex BLEModulationIndex, modulationShaping BLEModulationShaping) error { +func (d *Device) SetModulationParamsBLE(bitrateBandwidth GFSKBLEBitrateBandwidth, modulationIndex ModulationIndex, modulationShaping ModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) } -func (d *Device) SetModulationParamsGFSK(bitrateBandwidth GFSKBitrateBandwidth, modulationIndex GFSKModulationIndex, modulationShaping GFSKModulationShaping) error { +func (d *Device) SetModulationParamsGFSK(bitrateBandwidth GFSKBLEBitrateBandwidth, modulationIndex ModulationIndex, modulationShaping ModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) } -func (d *Device) SetModulationParamsFLRC(bitrateBandwidth FLRCBitrateBandwidth, codingRate FLRCCodingRate, modulationShaping FLRCModulationShaping) error { +func (d *Device) SetModulationParamsFLRC(bitrateBandwidth FLRCBitrateBandwidth, codingRate FLRCCodingRate, modulationShaping ModulationShaping) error { return d.SetModulationParams(bitrateBandwidth, codingRate, modulationShaping) } From b2553835d993897e52b81c2e21241fa23eef2c45 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sun, 3 May 2026 20:42:28 -0500 Subject: [PATCH 10/11] add crude lora rx and tx examples --- examples/sx128x/lora_rx/main.go | 106 ++++++++++++++++++++++++++++++++ examples/sx128x/lora_tx/main.go | 96 +++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 examples/sx128x/lora_rx/main.go create mode 100644 examples/sx128x/lora_tx/main.go diff --git a/examples/sx128x/lora_rx/main.go b/examples/sx128x/lora_rx/main.go new file mode 100644 index 000000000..33ea60ddf --- /dev/null +++ b/examples/sx128x/lora_rx/main.go @@ -0,0 +1,106 @@ +package main + +import ( + "errors" + "machine" + "runtime" + "time" + + "tinygo.org/x/drivers/sx128x" +) + +var ( + // pin mapping specific to the lilygo t3s3, change as needed for your board + sdoPin = machine.GPIO6 + sdiPin = machine.GPIO3 + sckPin = machine.GPIO5 + nssPin = machine.GPIO7 + busyPin = machine.GPIO36 + resetPin = machine.GPIO8 + dio1Pin = machine.GPIO9 +) + +func setupPins() { + nssPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + nssPin.Set(true) + + resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + resetPin.Set(true) + + busyPin.Configure(machine.PinConfig{Mode: machine.PinInput}) + dio1Pin.Configure(machine.PinConfig{Mode: machine.PinInput}) +} + +func main() { + setupPins() + + spi := machine.SPI0 + spi.Configure(machine.SPIConfig{ + Mode: 0, + Frequency: 8 * 1e6, + SDO: sdoPin, + SDI: sdiPin, + SCK: sckPin, + }) + + radio := sx128x.New( + spi, + nssPin, + resetPin, + busyPin, + ) + + radio.WaitWhileBusy(time.Second) + SetupLora(radio) + + for { + data, err := Rx(radio) + if err != nil { + println("failed to receive:", err) + } else { + println("received:", string(data)) + } + } +} + +func SetupLora(radio *sx128x.Device) { + radio.SetStandby(sx128x.STANDBY_RC) + radio.SetPacketType(sx128x.PACKET_TYPE_LORA) + radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC) + + radio.SetRfFrequency(2400000000) // 2.4Ghz + radio.SetModulationParamsLoRa(sx128x.LORA_SF_9, sx128x.LORA_BW_1600, sx128x.LORA_CR_4_7) + + // section 14.4.1 shows required register setting for setting up LoRa operations. These depend on the chosen spreading factor. + radio.WriteRegister(0x925, []byte{0x32}) + radio.WriteRegister(0x93C, []byte{0x01}) + + radio.SetTxParams(13, sx128x.RADIO_RAMP_02_US) + radio.SetPacketParamsLoRa(12, sx128x.LORA_HEADER_EXPLICIT, 0xFF, sx128x.LORA_CRC_DISABLE, sx128x.LORA_IQ_STD) + radio.WriteRegister(sx128x.REG_LORA_SYNC_WORD_MSB, []byte{0x14, 0x24}) // full sync word is 0x1424 + +} + +func Rx(radio *sx128x.Device) ([]byte, error) { + radio.SetStandby(sx128x.STANDBY_RC) + radio.SetDioIrqParams(sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_RX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00) + radio.SetBufferBaseAddress(0, 0) + radio.ClearIrqStatus(sx128x.IRQ_ALL_MASK) + radio.SetRx(sx128x.PERIOD_BASE_4_MS, 250) // 4ms * 250 = 1s + // busy wait for IRQ indication + for dio1Pin.Get() == false { + runtime.Gosched() + } + irqStatus, _ := radio.GetIrqStatus() + if irqStatus&sx128x.IRQ_RX_DONE_MASK != 0 { + payloadLength, bufferOffset, err := radio.GetRxBufferStatus() + if err != nil { + return nil, err + } + data, err := radio.ReadBuffer(bufferOffset, payloadLength) + return data, nil + } else if irqStatus&sx128x.IRQ_RX_TX_TIMEOUT_MASK != 0 { + return nil, errors.New("rx timeout") + } + return nil, errors.New("unexpected IRQ status") +} diff --git a/examples/sx128x/lora_tx/main.go b/examples/sx128x/lora_tx/main.go new file mode 100644 index 000000000..248d3a7cb --- /dev/null +++ b/examples/sx128x/lora_tx/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "errors" + "machine" + "runtime" + "time" + + "tinygo.org/x/drivers/sx128x" +) + +var ( + // pin mapping specific to the lilygo t3s3, change as needed for your board + sdoPin = machine.GPIO6 + sdiPin = machine.GPIO3 + sckPin = machine.GPIO5 + nssPin = machine.GPIO7 + busyPin = machine.GPIO36 + resetPin = machine.GPIO8 + dio1Pin = machine.GPIO9 +) + +func setupPins() { + nssPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + nssPin.Set(true) + + resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + resetPin.Set(true) + + busyPin.Configure(machine.PinConfig{Mode: machine.PinInput}) + dio1Pin.Configure(machine.PinConfig{Mode: machine.PinInput}) +} + +func main() { + setupPins() + + spi := machine.SPI0 + spi.Configure(machine.SPIConfig{ + Mode: 0, + Frequency: 8 * 1e6, + SDO: sdoPin, + SDI: sdiPin, + SCK: sckPin, + }) + + radio := sx128x.New( + spi, + nssPin, + resetPin, + busyPin, + ) + + radio.WaitWhileBusy(time.Second) + SetupLora(radio) + + for { + Tx(radio, []byte("Hello, world!")) + time.Sleep(1 * time.Second) + } +} + +func SetupLora(radio *sx128x.Device) { + radio.SetStandby(sx128x.STANDBY_RC) + radio.SetPacketType(sx128x.PACKET_TYPE_LORA) + radio.SetRegulatorMode(sx128x.REGULATOR_DC_DC) + + radio.SetRfFrequency(2400000000) // 2.4Ghz + radio.SetModulationParamsLoRa(sx128x.LORA_SF_9, sx128x.LORA_BW_1600, sx128x.LORA_CR_4_7) + + // section 14.4.1 shows required register setting for setting up LoRa operations. These depend on the chosen spreading factor. + radio.WriteRegister(0x925, []byte{0x32}) + radio.WriteRegister(0x93C, []byte{0x01}) + + radio.SetTxParams(13, sx128x.RADIO_RAMP_02_US) + radio.SetPacketParamsLoRa(12, sx128x.LORA_HEADER_EXPLICIT, 0xFF, sx128x.LORA_CRC_DISABLE, sx128x.LORA_IQ_STD) + radio.WriteRegister(sx128x.REG_LORA_SYNC_WORD_MSB, []byte{0x14, 0x24}) // full sync word is 0x1424 + +} + +func Tx(radio *sx128x.Device, data []byte) error { + if len(data) > 255 { + return errors.New("data length exceeds maximum of 255 bytes") + } + radio.SetStandby(sx128x.STANDBY_RC) + radio.SetPacketParamsLoRa(12, sx128x.LORA_HEADER_EXPLICIT, uint8(len(data)&0xFF), sx128x.LORA_CRC_DISABLE, sx128x.LORA_IQ_STD) + radio.SetBufferBaseAddress(0, 0) + radio.WriteBuffer(0, data) + radio.SetDioIrqParams(sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, sx128x.IRQ_TX_DONE_MASK|sx128x.IRQ_RX_TX_TIMEOUT_MASK, 0x00, 0x00) + radio.ClearIrqStatus(sx128x.IRQ_ALL_MASK) + radio.SetTx(sx128x.PERIOD_BASE_4_MS, 250) // 4ms * 250 = 1s + // busy wait for IRQ indication + for dio1Pin.Get() == false { + runtime.Gosched() + } + return nil +} From 9b03124979c92baaf8790f1c5c2398309795ff8b Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sun, 3 May 2026 20:42:53 -0500 Subject: [PATCH 11/11] change from type aliases to local types --- sx128x/constants.go | 72 ++++++++++++++++++++++----------------------- sx128x/sx128x.go | 36 +++++++++++------------ 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/sx128x/constants.go b/sx128x/constants.go index c88a42b57..aa0e17d09 100644 --- a/sx128x/constants.go +++ b/sx128x/constants.go @@ -1,60 +1,60 @@ package sx128x -type SleepConfig = uint8 -type StandbyConfig = uint8 -type PeriodBase = uint8 -type PacketType = uint8 -type RadioRampTime = uint8 -type CadSymbolNum = uint8 +type SleepConfig uint8 +type StandbyConfig uint8 +type PeriodBase uint8 +type PacketType uint8 +type RadioRampTime uint8 +type CadSymbolNum uint8 // GFSK Modulation Params -type GFSKBLEBitrateBandwidth = uint8 -type ModulationIndex = uint8 -type ModulationShaping = uint8 +type GFSKBLEBitrateBandwidth uint8 +type ModulationIndex uint8 +type ModulationShaping uint8 // GFSK Packet Params -type GFSKPreambleLength = uint8 -type GFSKSyncWordLength = uint8 -type GFSKSyncWordMatch = uint8 -type GFSKHeaderType = uint8 -type GFSKCrcType = uint8 +type GFSKPreambleLength uint8 +type GFSKSyncWordLength uint8 +type GFSKSyncWordMatch uint8 +type GFSKHeaderType uint8 +type GFSKCrcType uint8 // BLE Packet Params -type BLEConnectionState = uint8 -type BLECrcType = uint8 -type BLETestPayload = uint8 +type BLEConnectionState uint8 +type BLECrcType uint8 +type BLETestPayload uint8 // FLRC Modulation Params -type FLRCBitrateBandwidth = uint8 -type FLRCCodingRate = uint8 +type FLRCBitrateBandwidth uint8 +type FLRCCodingRate uint8 // FLRC Packet Params -type FLRCPreambleLength = uint8 -type FLRCSyncWordLength = uint8 -type FLRCSyncWordMatch = uint8 -type FLRCHeaderType = uint8 -type FLRCCrcType = uint8 +type FLRCPreambleLength uint8 +type FLRCSyncWordLength uint8 +type FLRCSyncWordMatch uint8 +type FLRCHeaderType uint8 +type FLRCCrcType uint8 // LoRa Modulation Params -type LoRaSpreadingFactor = uint8 -type LoRaBandwidth = uint8 -type LoRaCodingRate = uint8 +type LoRaSpreadingFactor uint8 +type LoRaBandwidth uint8 +type LoRaCodingRate uint8 // LoRa Packet Params -type LoRaHeaderType = uint8 -type LoRaCrcType = uint8 -type LoRaIqType = uint8 +type LoRaHeaderType uint8 +type LoRaCrcType uint8 +type LoRaIqType uint8 // Misc -type RegulatorMode = uint8 +type RegulatorMode uint8 type IRQMask = uint16 -type CircuitMode = uint8 -type CommandStatus = uint8 +type CircuitMode uint8 +type CommandStatus uint8 // Packet Status -type GFSKPacketInfo = uint8 -type BLEPacketInfo = uint8 -type FLRCPacketInfo = uint8 +type GFSKPacketInfo uint8 +type BLEPacketInfo uint8 +type FLRCPacketInfo uint8 const ( whiteningDisable = 0x00 diff --git a/sx128x/sx128x.go b/sx128x/sx128x.go index e5f972b3e..a477fc62c 100644 --- a/sx128x/sx128x.go +++ b/sx128x/sx128x.go @@ -63,7 +63,7 @@ func (d *Device) GetStatus() (CircuitMode, CommandStatus, error) { circuitMode := (status & circuitModeMask) >> 5 commandStatus := (status & commandStatusMask) >> 2 - return circuitMode, commandStatus, nil + return CircuitMode(circuitMode), CommandStatus(commandStatus), nil } func (d *Device) WriteRegister(addr uint16, data []byte) error { @@ -146,7 +146,7 @@ func (d *Device) SetSleep(sleepConfig SleepConfig) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetSleep, sleepConfig) + d.spiTxBuf = append(d.spiTxBuf, cmdSetSleep, uint8(sleepConfig)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -163,7 +163,7 @@ func (d *Device) SetStandby(standbyConfig StandbyConfig) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetStandby, standbyConfig) + d.spiTxBuf = append(d.spiTxBuf, cmdSetStandby, uint8(standbyConfig)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -203,7 +203,7 @@ func (d *Device) SetTx(periodBase PeriodBase, periodBaseCount uint16) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetTx, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetTx, uint8(periodBase), uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -222,7 +222,7 @@ func (d *Device) SetRx(periodBase PeriodBase, periodBaseCount uint16) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetRx, periodBase, uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRx, uint8(periodBase), uint8((periodBaseCount>>8)&0xFF), uint8(periodBaseCount&0xFF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -242,7 +242,7 @@ func (d *Device) SetRxDutyCycle(periodBase PeriodBase, rxPeriodBaseCount uint16, } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetRxDutyCycle, periodBase, uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRxDutyCycle, uint8(periodBase), uint8((rxPeriodBaseCount&0xFF00)>>8), uint8(rxPeriodBaseCount&0x00FF)) d.spiTxBuf = append(d.spiTxBuf, uint8((sleepPeriodBaseCount&0xFF00)>>8), uint8(sleepPeriodBaseCount&0x00FF)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) @@ -359,7 +359,7 @@ func (d *Device) SetPacketType(packetType PacketType) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetPacketType, packetType) + d.spiTxBuf = append(d.spiTxBuf, cmdSetPacketType, uint8(packetType)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -380,7 +380,7 @@ func (d *Device) GetPacketType() (PacketType, error) { if err != nil { return 0, err } - return d.spiRxBuf[2], nil + return PacketType(d.spiRxBuf[2]), nil } // Set the RF frequency in Hz, must be between 2.4 GHz and 2.5 GHz @@ -420,7 +420,7 @@ func (d *Device) SetTxParams(powerdBm int8, rampTime RadioRampTime) error { d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] adjustedPower := uint8(powerdBm + 18) - d.spiTxBuf = append(d.spiTxBuf, cmdSetTxParams, adjustedPower, rampTime) + d.spiTxBuf = append(d.spiTxBuf, cmdSetTxParams, adjustedPower, uint8(rampTime)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err @@ -474,19 +474,19 @@ func (d *Device) SetModulationParams(modParam1, modParam2, modParam3 uint8) erro } func (d *Device) SetModulationParamsBLE(bitrateBandwidth GFSKBLEBitrateBandwidth, modulationIndex ModulationIndex, modulationShaping ModulationShaping) error { - return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) + return d.SetModulationParams(uint8(bitrateBandwidth), uint8(modulationIndex), uint8(modulationShaping)) } func (d *Device) SetModulationParamsGFSK(bitrateBandwidth GFSKBLEBitrateBandwidth, modulationIndex ModulationIndex, modulationShaping ModulationShaping) error { - return d.SetModulationParams(bitrateBandwidth, modulationIndex, modulationShaping) + return d.SetModulationParams(uint8(bitrateBandwidth), uint8(modulationIndex), uint8(modulationShaping)) } func (d *Device) SetModulationParamsFLRC(bitrateBandwidth FLRCBitrateBandwidth, codingRate FLRCCodingRate, modulationShaping ModulationShaping) error { - return d.SetModulationParams(bitrateBandwidth, codingRate, modulationShaping) + return d.SetModulationParams(uint8(bitrateBandwidth), uint8(codingRate), uint8(modulationShaping)) } func (d *Device) SetModulationParamsLoRa(spreadingFactor LoRaSpreadingFactor, bandwidth LoRaBandwidth, codingRate LoRaCodingRate) error { - return d.SetModulationParams(spreadingFactor, bandwidth, codingRate) + return d.SetModulationParams(uint8(spreadingFactor), uint8(bandwidth), uint8(codingRate)) } // The arguments to this function depend on the packet type. It is recommended to use the mode specific functions for a better experience. @@ -515,7 +515,7 @@ func (d *Device) SetPacketParamsGFSK(preambleLength GFSKPreambleLength, syncWord } else { whiteningVal = whiteningDisable } - return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningVal) + return d.SetPacketParams(uint8(preambleLength), uint8(syncWordLength), uint8(syncWordMatch), uint8(headerType), payloadLength, uint8(crcLength), whiteningVal) } // Set FLRC related packet parameters, this assumes the packet type is already set to FLRC. @@ -527,7 +527,7 @@ func (d *Device) SetPacketParamsFLRC(preambleLength FLRCPreambleLength, syncWord if payloadLength > 127 { return errPayloadLengthTooLong } - return d.SetPacketParams(preambleLength, syncWordLength, syncWordMatch, headerType, payloadLength, crcLength, whiteningDisable) + return d.SetPacketParams(uint8(preambleLength), uint8(syncWordLength), uint8(syncWordMatch), uint8(headerType), payloadLength, uint8(crcLength), whiteningDisable) } // Set BLE related packet parameters, this assumes the packet type is already set to BLE. @@ -538,7 +538,7 @@ func (d *Device) SetPacketParamsBLE(connectionState BLEConnectionState, crcLengt } else { whiteningVal = whiteningDisable } - return d.SetPacketParams(connectionState, crcLength, bleTestPayload, whiteningVal, 0, 0, 0) + return d.SetPacketParams(uint8(connectionState), uint8(crcLength), uint8(bleTestPayload), whiteningVal, 0, 0, 0) } // Set LoRa related packet parameters, this assumes the packet type is already set to LoRa. @@ -548,7 +548,7 @@ func (d *Device) SetPacketParamsLoRa(preambleLength uint32, headerType LoRaHeade return errPayloadLengthTooShort } exponent, mantissa := getExponentAndMantissa(preambleLength) - return d.SetPacketParams(uint8(exponent<<4)|mantissa, headerType, payloadLength, crcType, iqType, 0, 0) + return d.SetPacketParams(uint8(exponent<<4)|mantissa, uint8(headerType), payloadLength, uint8(crcType), uint8(iqType), 0, 0) } func getExponentAndMantissa(value uint32) (uint8, uint8) { @@ -747,7 +747,7 @@ func (d *Device) SetRegulatorMode(mode RegulatorMode) error { } d.nssPin.Set(false) d.spiTxBuf = d.spiTxBuf[:0] - d.spiTxBuf = append(d.spiTxBuf, cmdSetRegulatorMode, mode) + d.spiTxBuf = append(d.spiTxBuf, cmdSetRegulatorMode, uint8(mode)) err = d.spi.Tx(d.spiTxBuf, nil) d.nssPin.Set(true) return err