From 000868af23ed2e1f0b728049c1f967964f0febad Mon Sep 17 00:00:00 2001 From: rasmuskleist Date: Fri, 14 Jul 2023 15:21:23 +0200 Subject: [PATCH] [driver] Adding SX128x driver --- src/modm/driver/radio/sx128x.hpp | 219 +++++ src/modm/driver/radio/sx128x.lb | 37 + src/modm/driver/radio/sx128x_definitions.hpp | 981 +++++++++++++++++++ src/modm/driver/radio/sx128x_hal.hpp | 92 ++ src/modm/driver/radio/sx128x_hal_impl.hpp | 202 ++++ src/modm/driver/radio/sx128x_impl.hpp | 412 ++++++++ 6 files changed, 1943 insertions(+) create mode 100644 src/modm/driver/radio/sx128x.hpp create mode 100644 src/modm/driver/radio/sx128x.lb create mode 100644 src/modm/driver/radio/sx128x_definitions.hpp create mode 100644 src/modm/driver/radio/sx128x_hal.hpp create mode 100644 src/modm/driver/radio/sx128x_hal_impl.hpp create mode 100644 src/modm/driver/radio/sx128x_impl.hpp diff --git a/src/modm/driver/radio/sx128x.hpp b/src/modm/driver/radio/sx128x.hpp new file mode 100644 index 0000000000..7f58db8d43 --- /dev/null +++ b/src/modm/driver/radio/sx128x.hpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2023, Lasse Alexander Jensen + * Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_SX128X_HPP +#define MODM_SX128X_HPP + +#include +#include +#include + +#include "sx128x_definitions.hpp" +#include "sx128x_hal.hpp" + +namespace modm +{ + +/** + * @tparam Hal Hardware Abstraction Layer for SX128x + * + * @ingroup modm_driver_sx128x + * @author Lasse Alexander Jensen + * @author Rasmus Kleist Hørlyck Sørensen + */ +template< class Hal > +class Sx128x : public sx128x, public Hal +{ +public: + Sx128x(); + + /// Get the transciever status directly. + /// @attention this command can be issued at any time as long as it is not the very first command send over the interface + modm::ResumableResult + getStatus(Status &status); + + /// Writes a block of bytes in a data memory space starting at a specific address + modm::ResumableResult + writeRegister(Register reg, uint8_t data); + + /// Writes a block of bytes in a data memory space starting at a specific address + modm::ResumableResult + writeRegister(Register reg, uint8_t *data, size_t length); + + /// Read a block of data starting at a given address + modm::ResumableResult + readRegister(Register reg, uint8_t &data); + + /// Read a block of data starting at a given address + modm::ResumableResult + readRegister(Register reg, uint8_t *data, size_t length); + + /// This function is used to write the data payload to be transmitted + /// @attention When the address exceeds 255 it wraps back to 0 due to the circular nature of data buffer + modm::ResumableResult + writeBuffer(uint8_t offset, uint8_t *data, size_t length); + + /// This function allows reading (n-3) bytes of payload received starting at offset + modm::ResumableResult + readBuffer(uint8_t offset, uint8_t *data, size_t length); + + /// Set the transceiver to Sleep mode with the lowest current consumption possible + /// @warning Depending on the specified level of memory retention not all instruction will be retained + modm::ResumableResult + setSleep(SleepConfig_t sleepConfig); + + /// Set the device in either STDBY_RC or STDBY_XOSC mode which are intermediate levels of power consumption + /// By default in this state, the system is clocked by the 13 MHz RC oscillator to reduce power consumption. + /// However if the application is time critical, the XOSC block can be turned or left ON. + /// @attention In this Standby mode, the transceiver may be configured for future F operations + modm::ResumableResult + setStandby(Oscillator oscillatorMode = Oscillator::Rc); + + /// Set the device in Frequency Synthesizer mode where the PLL is locked to the carrier frequency + /// @attention In normal operation of the transceiver, the user does not normally need to use FS mode + modm::ResumableResult + setFs(); + + /// Set the device in Transmit mode + /// @warning The IRQ status must be cleared before using this command + modm::ResumableResult + setTx(PeriodBase periodBase, uint16_t periodBaseCount); + + /// Set the device in Reciever mode + /// @warning The IRQ status must be cleared before using this command + /// @attention Setting periodBaseCount = 0 puts the transciever in RX Single Mode + /// @attention Setting periodBaseCount = 0xFFFF puts the transciever in Rx Continuous mode + modm::ResumableResult + setRx(PeriodBase periodBase, uint16_t periodBaseCount); + + /// Set the transceiver in sniff mode, so that it regularly looks for new packets + /// @warning RxDone interrupt must be configured prior to enter Duty cycled operations + /// @warning SetLongPreamble must be issued prior to setRxDutyCycle + modm::ResumableResult + setRxDutyCycle(PeriodBase periodBase, uint16_t rxPeriodBaseCount, uint16_t sleepPeriodBaseCount); + + /// Set the transceiver to use CAD (Channel Activity Detection) mode + /// @warning The Channel Activity Detection is a LoRa specific mode of operation + modm::ResumableResult + setCad(); + + /// Set the transciever to generate a Continuous Wave (RF tone) at a selected frequency and output power + /// @attention The device remains in Tx Continuous Wave until the host sends a mode confiquration command. + modm::ResumableResult + setTxContinuousWave(); + + /// Set the transciever to generate an infinite sequence of alternating 'O's and '1's in GFSK modulation and symbol 0 in LoRa + /// @attention The device remains in transmit until the host sends a mode confiquration command + modm::ResumableResult + setTxContinuousPreamble(); + + /// Set the transceiver radio frame out of a choice of 5 different packet types + /// @attention the packet type must be set first in the radio configuration sequence + modm::ResumableResult + setPacketType(PacketType packetType); + + /// Get the current operating packet type of the radio + modm::ResumableResult + getPacketType(PacketType &packetType); + + /// Set the frequency of the RF frequency mode. + modm::ResumableResult + setRfFrequency(uint32_t rfFrequency); + + /// Set the Tx output power and the Tx ramp time + /// @attention the physical output power is in the range [-18..13]dBm + modm::ResumableResult + setTxParams(uint8_t power, RampTime rampTime); + + /// Set the number of symbols on which which Channel Activity Detected (CAD) operates + modm::ResumableResult + setCadParams(CadSymbolNumber cadSymbolNumber); + + /// Set the base address for the packet handling operation in Tx and Rx mode for all packet types + modm::ResumableResult + setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress); + + /// Set the modulation parameters of the radio + /// @attention The modulation parameters will be interpreted depending on the frame type + modm::ResumableResult + setModulationParams(ModulationParams modulationParams); + + /// Set the parameters of the packet handling block + /// @warning Interpretation by the transceiver of the packet parameters depends upon the chosen packet type + modm::ResumableResult + setPacketParams(PacketParams packetParams); + + /// Get length of the last received packet and the address of the first byte received + modm::ResumableResult + getRxBufferStatus(RxBufferStatus &rxBufferStatus); + + /// Retrieve information about the last received packet + /// @attention The returned parameters are frame-dependent + modm::ResumableResult + getPacketStatus(PacketStatus &packetStatus); + + /// Get the instantaneous RSSI value during reception of the packet + modm::ResumableResult + getRssiInst(uint8_t &rssiInst); + + /// Enable IRQs and to route IRQs to DIO pins. + modm::ResumableResult + setDioIrqParams(Irq_t irqMask, Irq_t dio1Mask = Irq_t(), Irq_t dio2Mask = Irq_t(), Irq_t dio3Mask = Irq_t()); + + /// Get the value of the IRQ register + modm::ResumableResult + getIrqStatus(Irq_t &irqStatus); + + /// Clear IRQ flags in the IRQ register + modm::ResumableResult + clearIrqStatus(Irq_t irqMask); + + /// Specify if DC-DC or LDO is used for power regulation + modm::ResumableResult + setRegulatorMode(RegulatorMode regModeParam); + + /// Save the present context of the radio register values to the Data RAM + modm::ResumableResult + setSaveContext(); + + /// Set the chip so that the state following a Rx or Tx operation is FS and not STDBY + /// This feature is to be used to reduce the switching time between consecutive Rx and/or Tx operations + modm::ResumableResult + setAutoFs(bool enable = true); + + /// Set the device to be able to send back a response 150 us after a packet reception + modm::ResumableResult + setAutoTx(uint16_t time); + + /// Set the transceiver into Long Preamble mode + /// @warning Long Preamble mode can only be used with either LoRa mode and GFSK mode + modm::ResumableResult + setLongPreamble(bool enable = true); + + /// Set the role of the transciever in ranging operation + modm::ResumableResult + setRangingRole(RangingRole rangingRole); + + /// Enable advanced ranging + modm::ResumableResult + setAdvancedRanging(bool enable = true); + +private: + uint8_t buffer[8]; + +}; + +} + +#include "sx128x_impl.hpp" + +#endif \ No newline at end of file diff --git a/src/modm/driver/radio/sx128x.lb b/src/modm/driver/radio/sx128x.lb new file mode 100644 index 0000000000..b942205e92 --- /dev/null +++ b/src/modm/driver/radio/sx128x.lb @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + + +def init(module): + module.name = ":driver:sx128x" + module.description = """\ +Semtech SX1280/SX1281 Driver + +Long Range, Low Power, 2.4 GHz Transceiver with Ranging Capability +""" + +def prepare(module, options): + module.depends( + ":architecture:gpio", + ":architecture:spi.device", + ":math:utils", + ":processing:resumable", + ":processing:timer") + return True + +def build(env): + env.outbasepath = "modm/src/modm/driver/radio" + env.copy("sx128x.hpp") + env.copy("sx128x_impl.hpp") + env.copy("sx128x_definitions.hpp") + env.copy("sx128x_hal.hpp") + env.copy("sx128x_hal_impl.hpp") diff --git a/src/modm/driver/radio/sx128x_definitions.hpp b/src/modm/driver/radio/sx128x_definitions.hpp new file mode 100644 index 0000000000..3186926eee --- /dev/null +++ b/src/modm/driver/radio/sx128x_definitions.hpp @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2023, Lasse Alexander Jensen + * Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_SX128X_DEFINITIONS_HPP +#define MODM_SX128X_DEFINITIONS_HPP + +#include +#include +#include + +namespace modm +{ + +/// @ingroup modm_driver_sx128x +struct sx128x +{ +protected: + enum class + Opcode : uint8_t + { + // Status + GetStatus = 0xC0, + + // Register Access Operations + WriteRegister = 0x18, + ReadRegister = 0x19, + + // Data buffer Operations + WriteBuffer = 0x1A, + ReadBuffer = 0x1B, + + // Radio Operation Modes + SetSleep = 0x84, + SetStandby = 0x80, + SetFs = 0xC1, + SetTx = 0x83, + SetRx = 0x82, + SetRxDutyCycle = 0x94, + SetCad = 0xC5, + SetTxContinuousWave = 0xD1, + SetTxContinuousPreamble = 0xD2, + + // Radio Configuration + SetPacketType = 0x8A, + GetPacketType = 0x03, + SetRfFrequency = 0x86, + SetTxParams = 0x8E, + SetCadParams = 0x88, + SetBufferBaseAddress = 0x8F, + SetModulationParams = 0x8B, + SetPacketParams = 0x8C, + + // Communication Status Information + GetRxBufferStatus = 0x17, + GetPacketStatus = 0x1D, + GetRssiInst = 0x1F, + + // IRQ handling + SetDioIrqParams = 0x8D, + GetIrqStatus = 0x15, + ClrIrqStatus = 0x97, + + // Settings functions + SetRegulatorMode = 0x96, + SetSaveContext = 0xD5, + SetAutoFs = 0x9E, + SetAutoTx = 0x98, + SetLongPreamble = 0x9B, + SetUartSpeed = 0x9D, + SetRangingRole = 0xA3, + SetAdvancedRanging = 0x9A, + }; + +public: + enum class + Register : uint16_t + { + RxGain = 0x891, + ManualGainSetting = 0x895, + LnaGainValue = 0x89E, + LnaGainControl = 0x89F, + SynchPeakAttenuation = 0x8C2, + PayloadLength = 0x901, + LoRaHeaderMode = 0x903, + + RangingRequestAddressByte3 = 0x912, + RangingRequestAddressByte2 = 0x913, + RangingRequestAddressByte1 = 0x914, + RangingRequestAddressByte0 = 0x915, + + RangingDeviceAdressByte3 = 0x916, + RangingDeviceAdressByte2 = 0x917, + RangingDeviceAdressByte1 = 0x918, + RangingDeviceAdressByte0 = 0x919, + + RangingFilterWindowSize = 0x91E, + ResetRangingFilter = 0x923, + RangingResultMux = 0x924, + + SfAdditionalConfiguration = 0x925, + + RangingCalibrationByte2 = 0x92B, + RangingCalibrationByte1 = 0x92C, + RangingCalibrationByte0 = 0x92D, + + RangingIdCheckLength = 0x931, + FrequencyErrorCorrection = 0x93C, + + LoRaSynchWordByte1 = 0x944, + LoRaSynchWordByte0 = 0x945, + + FeiByte2 = 0x954, + FeiByte1 = 0x955, + FeiByte0 = 0x956, + + RangingResultByte2 = 0x961, + RangingResultByte1 = 0x962, + RangingResultByte0 = 0x963, + + RangingRssi = 0x964, + FreezeRangingResult = 0x97F, + PacketPreambleSettings = 0x9C1, + WhiteningInitialValue = 0x9C5, + + CrcPolynomialDefMsb = 0x9C6, + CrcPolynomialDefLsb = 0x9C7, + + CrcPolynomialSeedByte2 = 0x9C7, + CrcPolynomialSeedByte1 = 0x9C8, + CrcPolynomialSeedByte0 = 0x9C9, + + CrcMsbInitialValue = 0x9C8, + CrcLsbInitialValue = 0x9C9, + + SynchAddressControl = 0x9CD, + + SyncAddress1Byte4 = 0x9CE, + SyncAddress1Byte3 = 0x9CF, + SyncAddress1Byte2 = 0x9D0, + SyncAddress1Byte1 = 0x9D1, + SyncAddress1Byte0 = 0x9D2, + + SyncAddress2Byte4 = 0x9D3, + SyncAddress2Byte3 = 0x9D4, + SyncAddress2Byte2 = 0x9D5, + SyncAddress2Byte1 = 0x9D6, + SyncAddress2Byte0 = 0x9D7, + + SyncAddress3Byte4 = 0x9D8, + SyncAddress3Byte3 = 0x9D9, + SyncAddress3Byte2 = 0x9DA, + SyncAddress3Byte1 = 0x9DB, + SyncAddress3Byte0 = 0x9DC + }; + + +public: + enum class + OperatingMode : uint8_t + { + Sleep, + Standby, + Fs, + Tx, + Rx, + }; + + enum class + CircuitMode : uint8_t + { + StdbyRc = 0x2, + StdbyXosc = 0x3, + Fs = 0x4, + Rx = 0x5, + Tx = 0x6, + }; + + enum class + CommandStatus : uint8_t + { + Processed = 0x1, /// Transceiver has successfully processed the command + DataAvailable = 0x2, /// Data are available to host + Timeout = 0x3, /// Command time-out + ProcessingError = 0x4, /// Command processing error + ExecutionFailure = 0x5, /// Failure to execute command + TxDone = 0x6, /// Command Tx done + }; + + struct modm_packed + Status + { + uint8_t: 2; + CommandStatus commandStatus: 3; + CircuitMode circuitMode: 3; + }; + + enum class + SleepConfig : uint8_t + { + DataRamFlushed = Bit0, + DataRamRetention = Bit1, + DataBufferRetention = Bit2, + }; + MODM_FLAGS8(SleepConfig); + + enum class + Oscillator : uint8_t + { + Rc = 0, /// Device running on RC 13MHz, set STDBY_RC mode + Xosc = 1, /// Device running on XTAL 52MHz, set STDBY_XOSC mode + }; + + enum class + PeriodBase : uint8_t + { + us15_625 = 0x00, + us62_5 = 0x01, + ms1 = 0x02, + ms4 = 0x03 + }; + + enum class + PacketType : uint8_t + { + Gfsk = 0x00, + LoRa = 0x01, + Ranging = 0x02, + Flrc = 0x03, + Ble = 0x04, + }; + + enum class + RampTime : uint8_t + { + us2 = 0x00, + us4 = 0x20, + us6 = 0x40, + us8 = 0x60, + us10 = 0x80, + us12 = 0xA0, + us16 = 0xC0, + us20 = 0xE0 + }; + + enum class + CadSymbolNumber : uint8_t + { + One = 0x00, + Two = 0x20, + Four = 0x40, + Eight = 0x60, + Sixteen = 0x80 + }; + + enum class + RegulatorMode : uint8_t + { + Ldo = 0x00, + DcDc = 0x01, + }; + + enum class + Irq : uint16_t + { + TxDone = Bit0, + RxDone = Bit1, + SyncWordValid = Bit2, + SyncWordError = Bit3, + HeaderValid = Bit4, + HeaderError = Bit5, + CrcError = Bit6, + RangingSlaveResponseDone = Bit7, + RangingSlaveRequestDiscard = Bit8, + RangingMasterResultValid = Bit9, + RangingMasterTimeout = Bit10, + RangingMasterRequestTimeout = Bit11, + CadDone = Bit12, + CadDetected = Bit13, + RxTxTimeout = Bit14, + PreambleDetected = Bit15, + }; + MODM_FLAGS16(Irq); + + struct RxBufferStatus + { + uint8_t rxPayloadLength; + uint8_t rxStartBufferPointer; + }; + + enum class + RangingRole : uint8_t + { + Master = 0x01, + Slave = 0x00, + }; + + struct Gfsk + { + struct modm_packed + PacketStatus + { + enum class + Status : uint8_t + { + RxNoAck = Bit5, + PktSent = Bit0, + }; + MODM_FLAGS8(Status); + + enum class + Error : uint8_t + { + SyncError = Bit6, + LengthError = Bit5, + CrcError = Bit4, + AbortError = Bit3, + HeaderReceived = Bit2, + PacketCtrlBusy = Bit1, + }; + MODM_FLAGS8(Error); + + enum class + Sync : uint8_t + { + SyncAddrsCode2 = Bit2, + SyncAddrsCode1 = Bit1, + SyncAddrsCode0 = Bit0, + }; + MODM_FLAGS8(Sync); + + uint8_t rfu; + uint8_t rssiSync; + Error_t error; + Status_t status; + Sync_t sync; + }; + + + struct modm_packed + PacketParams + { + enum class + PreambleLength : uint8_t + { + Bits4 = 0x00, + Bits8 = 0x10, + Bits12 = 0x20, + Bits16 = 0x30, + Bits20 = 0x40, + Bits24 = 0x50, + Bits28 = 0x60, + Bits32 = 0x70, + }; + + enum class + SyncWordLength : uint8_t + { + Byte1 = 0x00, + Byte2 = 0x02, + Byte3 = 0x04, + Byte4 = 0x06, + Byte5 = 0x08, + }; + enum class + SyncWordMatch : uint8_t + { + Disable = 0x00, + One = 0x10, + Two = 0x20, + OneTwo = 0x30, + Three = 0x40, + OneThree = 0x50, + TwoThree = 0x60, + OneTwoThree = 0x70, + }; + + enum class + HeaderType : uint8_t + { + FixedLength = 0x00, + VariableLength = 0x20, + }; + + enum class + CrcLength : uint8_t + { + Off = 0x00, + Byte2 = 0x10, + Byte3 = 0x20, + Byte4 = 0x30, + }; + + enum class + Whitening : uint8_t + { + Enable = 0x00, + Disable = 0x08, + }; + + PreambleLength preambleLength; + SyncWordLength syncWordLength; + SyncWordMatch syncWordMatch; + PacketType packetType; + uint8_t payloadLength; + CrcLength crcLength; + Whitening whitening; + + }; + + struct modm_packed + ModulationParams + { + + enum class + BitrateBandwidth : uint8_t + { + Br2000Bw2400 = 0x04, + Br1600Bw2400 = 0x28, + Br1000Bw2400 = 0x4C, + Br1000Bw1200 = 0x45, + Br800Bw2400 = 0x70, + Br800Bw1200 = 0x69, + Br500Bw1200 = 0x8D, + Br500Bw600 = 0x86, + Br400Bw1200 = 0xB1, + Br400Bw600 = 0xAA, + Br250Bw600 = 0xCE, + Br250Bw300 = 0xC7, + Br124Bw300 = 0xEF, + }; + + enum class + ModulationIndex : uint8_t + { + Ind0_35 = 0x00, + Ind0_50 = 0x01, + Ind0_75 = 0x02, + Ind1_00 = 0x03, + Ind1_25 = 0x04, + Ind1_50 = 0x05, + Ind1_75 = 0x06, + Ind2_00 = 0x07, + Ind2_25 = 0x08, + Ind2_50 = 0x09, + Ind2_75 = 0x0A, + Ind3_00 = 0x0B, + Ind3_25 = 0x0C, + Ind3_50 = 0x0D, + Ind3_75 = 0x0E, + Ind4_00 = 0x0F, + }; + + enum class + ModulationShaping : uint8_t + { + BtOff = 0x00, + Bt1_0 = 0x10, + Bt0_5 = 0x20, + }; + + BitrateBandwidth bitrateBandwidth; + ModulationIndex modulationIndex; + ModulationShaping modulationShaping; + }; + }; + + struct Ble + { + struct modm_packed + PacketStatus + { + enum class + Status : uint8_t + { + RxNoAck = Bit5, + PktSent = Bit0, + }; + MODM_FLAGS8(Status); + + enum class + Error : uint8_t + { + SyncError = Bit6, + LengthError = Bit5, + CrcError = Bit4, + AbortError = Bit3, + HeaderReceived = Bit2, + PacketCtrlBusy = Bit1, + }; + MODM_FLAGS8(Error); + + enum class + Sync : uint8_t + { + SyncAddrsCode2 = Bit2, + SyncAddrsCode1 = Bit1, + SyncAddrsCode0 = Bit0, + }; + MODM_FLAGS8(Sync); + + uint8_t rfu; + uint8_t rssiSync; + Error_t error; + Status_t status; + Sync_t sync; + }; + + struct modm_packed + PacketParams + { + enum class + ConnectionState : uint8_t + { + PayloadLengthMax31Bytes = 0x00, + PayloadLengthMax37Bytes = 0x20, + TxTestMode = 0x40, + PayloadLengthMax355Bytes = 0x80, + }; + + enum class + CrcLength : uint8_t + { + Off = 0x00, + Byte3 = 0x10, + }; + + enum class + TestPayload : uint8_t + { + Prbs9 = 0x00, + Eyelong10 = 0x04, + Eyeshort10 = 0x08, + Prbs15 = 0x0C, + All1 = 0x10, + All0 = 0x14, + Eyelong01 = 0x18, + Eyeshort01 = 0x1c, + }; + + enum class + Whitening : uint8_t + { + Enable = 0x00, + Disable = 0x08, + }; + + ConnectionState connectionState; + CrcLength crcLength; + TestPayload testPayload; + Whitening whitening; + }; + + struct modm_packed + ModulationParams + { + enum class + BitrateBandwidth : uint8_t + { + Br2000Bw2400 = 0x04, + Br1600Bw2400 = 0x28, + Br1000Bw2400 = 0x4C, + Br1000Bw1200 = 0x45, + Br800Bw2400 = 0x70, + Br800Bw1200 = 0x69, + Br500Bw1200 = 0x8D, + Br500Bw600 = 0x86, + Br400Bw1200 = 0xB1, + Br400Bw600 = 0xAA, + Br250Bw600 = 0xCE, + Br250Bw300 = 0xC7, + Br124Bw300 = 0xEF, + }; + + enum class + ModulationIndex : uint8_t + { + Ind0_35 = 0x00, + Ind0_50 = 0x01, + Ind0_75 = 0x02, + Ind1_00 = 0x03, + Ind1_25 = 0x04, + Ind1_50 = 0x05, + Ind1_75 = 0x06, + Ind2_00 = 0x07, + Ind2_25 = 0x08, + Ind2_50 = 0x09, + Ind2_75 = 0x0A, + Ind3_00 = 0x0B, + Ind3_25 = 0x0C, + Ind3_50 = 0x0D, + Ind3_75 = 0x0E, + Ind4_00 = 0x0F, + }; + + enum class + ModulationShaping : uint8_t + { + BtOff = 0x00, + Bt1_0 = 0x10, + Bt0_5 = 0x20, + }; + + BitrateBandwidth bitrateBandwidth; + ModulationIndex modulationIndex; + ModulationShaping modulationShaping; + }; + }; + + struct Flrc + { + struct modm_packed + PacketStatus + { + enum class + Status : uint8_t + { + RxNoAck = Bit5, + PktSent = Bit0, + }; + MODM_FLAGS8(Status); + + enum class + Error : uint8_t + { + SyncError = Bit6, + LengthError = Bit5, + CrcError = Bit4, + AbortError = Bit3, + HeaderReceived = Bit2, + PacketCtrlBusy = Bit1, + }; + MODM_FLAGS8(Error); + + enum class + Sync : uint8_t + { + SyncAddrsCode2 = Bit2, + SyncAddrsCode1 = Bit1, + SyncAddrsCode0 = Bit0, + }; + MODM_FLAGS8(Sync); + + uint8_t rfu; + uint8_t rssiSync; + Error_t error; + Status_t status; + Sync_t sync; + }; + + struct modm_packed + PacketParams + { + enum class + PreambleLength : uint8_t + { + Bits4 = 0x00, + Bits8 = 0x10, + Bits12 = 0x20, + Bits16 = 0x30, + Bits20 = 0x40, + Bits24 = 0x50, + Bits28 = 0x60, + Bits32 = 0x70, + }; + + enum class + SyncWordLength : uint8_t + { + NoSync = 0x00, + Bits32 = 0x02, + }; + + enum class + SyncWordMatch : uint8_t + { + Disable = 0x00, + One = 0x10, + Two = 0x20, + OneTwo = 0x30, + Three = 0x40, + OneThree = 0x50, + TwoThree = 0x60, + OneTwoThree = 0x70, + }; + + enum class + PacketType : uint8_t { + FixedLength = 0x00, + VariableLength = 0x20, + }; + + enum class + CrcLength : uint8_t + { + Off = 0x00, + Byte1 = 0x10, + Byte2 = 0x20, + }; + + enum class + Whitening : uint8_t + { + Disable = 0x08, + }; + + PreambleLength preambleLength; + SyncWordLength syncWordLength; + SyncWordMatch syncWordMatch; + PacketType packetType; + uint8_t payloadLength; + CrcLength crcLength; + Whitening whitening; + }; + + struct modm_packed + ModulationParams + { + enum class + BitrateBandwidth : uint8_t + { + Br1300Bw1200 = 0x45, + Br1000Bw1200 = 0x69, + Br650Bw600 = 0x86, + Br520Bw600 = 0xAA, + Br325Bw300 = 0xC7, + Br260Bw300 = 0xEB, + }; + + enum class + CodingRate : uint8_t + { + Cr1_2 = 0x00, + Cr3_4 = 0x02, + Cr1_1 = 0x04, + }; + + enum class + ModulationShaping : uint8_t + { + BtDis = 0x00, + Bt1_0 = 0x10, + Bt0_5 = 0x20, + }; + + BitrateBandwidth bitrateBandwidth; + CodingRate codingRate; + ModulationShaping modulationShaping; + }; + }; + + struct LoRa + { + struct modm_packed + PacketStatus { + uint8_t rssiSync; + uint8_t snr; + }; + + struct modm_packed + PacketParams + { + enum class + HeaderType : uint8_t + { + Explicit = 0x00, + Implicit = 0x80, + }; + + enum class + Crc : uint8_t + { + Enable = 0x20, + Disable = 0x00, + }; + + enum class + InvertIq : uint8_t + { + Inverted = 0x00, + Standard = 0x40, + }; + + uint8_t preambleLength; + HeaderType headerType; + uint8_t payloadLength; + Crc crc; + InvertIq invertIq; + }; + + struct modm_packed + ModulationParams + { + enum class + SpreadingFactor : uint8_t + { + Sf5 = 0x50, + Sf6 = 0x60, + Sf7 = 0x70, + Sf8 = 0x80, + Sf9 = 0x90, + Sf10 = 0xA0, + Sf11 = 0xB0, + Sf12 = 0xC0, + }; + + enum class + Bandwidth : uint8_t + { + Bw1600 = 0x0A, + Bw800 = 0x18, + Bw400 = 0x26, + Bw200 = 0x34, + }; + + enum class + CodingRate : uint8_t + { + Cr4_5 = 0x01, + Cr4_6 = 0x02, + Cr4_7 = 0x03, + Cr4_8 = 0x04, + Cr_Li_4_5 = 0x05, + Cr_Li_4_6 = 0x06, + Cr_Li_4_7 = 0x07, + }; + + SpreadingFactor spreadingFactor; + Bandwidth bandwidth; + CodingRate codingRate; + }; + }; + + struct Ranging + { + struct modm_packed + PacketStatus { + uint8_t rssiSync; + uint8_t sni; + }; + + struct modm_packed + PacketParams + { + enum class + HeaderType : uint8_t + { + Explicit = 0x00, + Implicit = 0x80, + }; + + enum class + Crc : uint8_t + { + Enable = 0x20, + Disable = 0x00, + }; + + enum class + InvertIq : uint8_t + { + Inverted = 0x00, + Standard = 0x40, + }; + + uint8_t preambleLength; + HeaderType headerType; + uint8_t payloadLength; + Crc crc; + InvertIq invertIq; + }; + + struct modm_packed + ModulationParams + { + enum class + SpreadingFactor : uint8_t + { + Sf5 = 0x50, + Sf6 = 0x60, + Sf7 = 0x70, + Sf8 = 0x80, + Sf9 = 0x90, + Sf10 = 0xA0, + }; + + enum class + Bandwidth : uint8_t + { + Bw1600 = 0x0A, + Bw800 = 0x18, + Bw400 = 0x26, + }; + + enum class + CodingRate : uint8_t + { + Cr4_5 = 0x01, + Cr4_6 = 0x02, + Cr4_7 = 0x03, + Cr4_8 = 0x04, + Cr_Li_4_5 = 0x05, + Cr_Li_4_6 = 0x06, + Cr_Li_4_7 = 0x07, + }; + SpreadingFactor spreadingFactor; + Bandwidth bandwidth; + CodingRate codingRate; + }; + }; + + union PacketParams + { + Gfsk::PacketParams gfsk; + Flrc::PacketParams flrc; + Ble::PacketParams ble; + LoRa::PacketParams lora; + Ranging::PacketParams ranging; + + PacketParams() {} + PacketParams(Gfsk::PacketParams packetParams) : gfsk(packetParams) {} + PacketParams(Flrc::PacketParams packetParams) : flrc(packetParams) {} + PacketParams(Ble::PacketParams packetParams) : ble(packetParams) {} + PacketParams(LoRa::PacketParams packetParams) : lora(packetParams) {} + PacketParams(Ranging::PacketParams packetParams) : ranging(packetParams) {} + }; + + union PacketStatus + { + Gfsk::PacketStatus gfsk; + Flrc::PacketStatus flrc; + Ble::PacketStatus ble; + LoRa::PacketStatus lora; + Ranging::PacketStatus ranging; + + PacketStatus() {} + PacketStatus(Gfsk::PacketStatus packetStatus) : gfsk(packetStatus) {} + PacketStatus(Flrc::PacketStatus packetStatus) : flrc(packetStatus) {} + PacketStatus(Ble::PacketStatus packetStatus) : ble(packetStatus) {} + PacketStatus(LoRa::PacketStatus packetStatus) : lora(packetStatus) {} + PacketStatus(Ranging::PacketStatus packetStatus) : ranging(packetStatus) {} + }; + + union ModulationParams + { + Gfsk::ModulationParams gfsk; + Flrc::ModulationParams flrc; + Ble::ModulationParams ble; + LoRa::ModulationParams lora; + Ranging::ModulationParams ranging; + + ModulationParams() {} + ModulationParams(Gfsk::ModulationParams modulationParams) : gfsk(modulationParams) {} + ModulationParams(Flrc::ModulationParams modulationParams) : flrc(modulationParams) {} + ModulationParams(Ble::ModulationParams modulationParams) : ble(modulationParams) {} + ModulationParams(LoRa::ModulationParams modulationParams) : lora(modulationParams) {} + ModulationParams(Ranging::ModulationParams modulationParams) : ranging(modulationParams) {} + }; + +protected: + /// @cond + static constexpr uint16_t + i(Register reg) { return uint16_t(reg); } + static constexpr uint8_t + i(Opcode op) { return uint8_t(op); } + /// @endcond +}; + +} + + + +#endif \ No newline at end of file diff --git a/src/modm/driver/radio/sx128x_hal.hpp b/src/modm/driver/radio/sx128x_hal.hpp new file mode 100644 index 0000000000..a27d833f96 --- /dev/null +++ b/src/modm/driver/radio/sx128x_hal.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_SX128X_HAL_HPP +#define MODM_SX128X_HAL_HPP + +#include "sx128x_definitions.hpp" + +#include +#include + +namespace modm +{ + +/** + * SX128X SPI Hardware Abstraction Layer. + * + * @tparam SpiMaster SpiMaster interface + * @tparam Cs Chip-select pin + * @tparam Busy BUSY pin + * @tparam Reset RESET pin + * + * + * @ingroup modm_driver_sx128x_hal + * @author Rasmus Kleist Hørlyck Sørensen + */ +template < class SpiMaster, class Nss, class Busy, class Reset > +class Sx128xHalSpi : public modm::SpiDevice< SpiMaster >, protected modm::NestedResumable<2> +{ +public: + Sx128xHalSpi(); + + inline bool + reset(); + + inline bool + isBusy(); + +protected: + + modm::ResumableResult + writeRegister(uint16_t reg, uint8_t value); + + modm::ResumableResult + writeRegister(uint16_t reg, uint8_t *buffer = nullptr, uint16_t length = 0); + + modm::ResumableResult + readRegister(uint16_t reg, uint8_t &value); + + modm::ResumableResult + readRegister(uint16_t reg, uint8_t *buffer = nullptr, uint16_t length = 0); + + modm::ResumableResult + writeBuffer(uint8_t offset, uint8_t *buffer = nullptr, uint16_t length = 0); + + modm::ResumableResult + readBuffer(uint8_t offset, uint8_t *buffer = nullptr, uint16_t length = 0); + + modm::ResumableResult + writeCommand(uint8_t opcode, uint8_t *buffer = nullptr, uint16_t length = 0); + + modm::ResumableResult + readCommand(uint8_t opcode, uint8_t *buffer = nullptr, uint16_t length = 0); + +private: + // Register Access Operations + static constexpr uint8_t WriteRegister = 0x18; + static constexpr uint8_t ReadRegister = 0x19; + + // Data buffer Operations + static constexpr uint8_t WriteBuffer = 0x1A; + static constexpr uint8_t ReadBuffer = 0x1B; + + static constexpr uint8_t GetStatus = 0xC0; + // Read Operation Dummy Cycle + static constexpr uint8_t Nop = 0x00; + +}; + +} // namespace modm + +#include "sx128x_hal_impl.hpp" + +#endif // MODM_SX128X_HAL_HPP diff --git a/src/modm/driver/radio/sx128x_hal_impl.hpp b/src/modm/driver/radio/sx128x_hal_impl.hpp new file mode 100644 index 0000000000..a4a52df0e4 --- /dev/null +++ b/src/modm/driver/radio/sx128x_hal_impl.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_SX128X_HAL_HPP +# error "Don't include this file directly, use 'sx128x_hal.hpp' instead!" +#endif + +namespace modm +{ + +template < class SpiMaster, class Nss, class Busy, class Reset > +Sx128xHalSpi::Sx128xHalSpi() +{ +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +bool +Sx128xHalSpi::reset() +{ + Reset::setOutput(); + modm::delay_ms(50); + + Reset::setInput(); + modm::delay_ms(20); + + return true; +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +bool +Sx128xHalSpi::isBusy() +{ + return Busy::read(); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::writeRegister(uint16_t reg, uint8_t value) +{ + return writeRegister(reg, &value, 1); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::writeRegister(uint16_t reg, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(WriteRegister)); + RF_CALL(SpiMaster::transfer((reg & 0xFF00) >> 8)); + RF_CALL(SpiMaster::transfer((reg & 0x00FF))); + RF_CALL(SpiMaster::transfer(buffer, nullptr, length)); + + if (this->releaseMaster()) + Nss::set(); + + RF_END_RETURN(true); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::readRegister(uint16_t reg, uint8_t &value) +{ + return readRegister(reg, &value, 1); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::readRegister(uint16_t reg, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(ReadRegister)); + RF_CALL(SpiMaster::transfer((reg & 0xFF00) >> 8)); + RF_CALL(SpiMaster::transfer((reg & 0x00FF))); + RF_CALL(SpiMaster::transfer(0x00)); + RF_CALL(SpiMaster::transfer(buffer, nullptr, length)); + + if (this->releaseMaster()) + Nss::set(); + + RF_END_RETURN(true); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::writeBuffer(uint8_t offset, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(WriteBuffer)); + RF_CALL(SpiMaster::transfer(offset)); + RF_CALL(SpiMaster::transfer(buffer, nullptr, length)); + + if (this->releaseMaster()) + Nss::set(); + + RF_END_RETURN(true); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::readBuffer(uint8_t offset, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(ReadBuffer)); + RF_CALL(SpiMaster::transfer(offset)); + RF_CALL(SpiMaster::transfer(0x00)); + RF_CALL(SpiMaster::transfer(nullptr, buffer, length)); + + if (this->releaseMaster()) + Nss::set(); + + RF_END_RETURN(true); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::writeCommand(uint8_t opcode, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(opcode)); + RF_CALL(SpiMaster::transfer(buffer, nullptr, length)); + + if (this->releaseMaster()) + Nss::set(); + + + RF_END_RETURN(true); +} + +// ---------------------------------------------------------------------------- + +template < class SpiMaster, class Nss, class Busy, class Reset > +modm::ResumableResult +Sx128xHalSpi::readCommand(uint8_t opcode, uint8_t *buffer, uint16_t length) +{ + RF_BEGIN(); + + RF_WAIT_WHILE(isBusy()); + RF_WAIT_UNTIL(this->acquireMaster()); + Nss::reset(); + + RF_CALL(SpiMaster::transfer(opcode)); + RF_CALL(SpiMaster::transfer(0x00)); + RF_CALL(SpiMaster::transfer(nullptr, buffer, length)); + + if (this->releaseMaster()) + Nss::set(); + + RF_END_RETURN(true); +} + +} // namespace modm \ No newline at end of file diff --git a/src/modm/driver/radio/sx128x_impl.hpp b/src/modm/driver/radio/sx128x_impl.hpp new file mode 100644 index 0000000000..7e80d5444c --- /dev/null +++ b/src/modm/driver/radio/sx128x_impl.hpp @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2023, Lasse Alexander Jensen + * Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_SX128X_HPP +# error "Don't include this file directly, use 'sx128x.hpp' instead!" +#endif + +namespace modm +{ + +// ---------------------------------------------------------------------------- + +template < class Hal > +Sx128x< Hal >::Sx128x() +{ +} + +// ---------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getStatus(sx128x::Status &status) +{ + return Hal::readCommand(i(Opcode::GetStatus), status, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::writeRegister(Register reg, uint8_t data) +{ + return Hal::writeRegister(i(reg), data); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::writeRegister(Register reg, uint8_t *data, size_t length) +{ + return Hal::writeRegister(i(reg), data, length); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::readRegister(Register reg, uint8_t &value) +{ + return Hal::readRegister(reg, value); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::readRegister(Register reg, uint8_t *data, size_t length) +{ + return Hal::readRegister(i(reg), data, length); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::writeBuffer(uint8_t offset, uint8_t *data, size_t length) +{ + return Hal::writeBuffer(offset, data, length); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::readBuffer(uint8_t offset, uint8_t *data, size_t length) +{ + return Hal::readBuffer(offset, data, length); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setSleep(SleepConfig_t sleepConfig) +{ + buffer[0] = sleepConfig.value; + return Hal::writeCommand(i(Opcode::SetSleep), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setStandby(Oscillator oscillatorMode) +{ + buffer[0] = uint8_t(oscillatorMode); + return Hal::writeCommand(i(Opcode::SetStandby), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setFs() +{ + return Hal::writeCommand(i(Opcode::SetFs)); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setTx(PeriodBase periodBase, uint16_t periodBaseCount) +{ + buffer[0] = uint8_t(periodBase); + buffer[1] = (periodBaseCount >> 8) & 0xFF; + buffer[2] = periodBaseCount & 0xFF; + return Hal::writeCommand(i(Opcode::SetTx), buffer, 3); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setRx(PeriodBase periodBase, uint16_t periodBaseCount) +{ + buffer[0] = uint8_t(periodBase); + buffer[1] = (periodBaseCount >> 8) & 0xFF; + buffer[2] = periodBaseCount & 0xFF; + return Hal::writeCommand(i(Opcode::SetRx), buffer, 3); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setRxDutyCycle(PeriodBase periodBase, uint16_t rxPeriodBaseCount, uint16_t sleepPeriodBaseCount) +{ + buffer[0] = uint8_t(periodBase); + buffer[1] = (rxPeriodBaseCount >> 8) & 0x00FF; + buffer[2] = (rxPeriodBaseCount & 0x00FF); + buffer[3] = (sleepPeriodBaseCount >> 8) & 0x00FF; + buffer[4] = (sleepPeriodBaseCount & 0x00FF); + return Hal::writeCommand(i(Opcode::SetRxDutyCycle), buffer, 5); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setCad() +{ + return Hal::writeCommand(i(Opcode::SetCad)); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setTxContinuousWave() +{ + return Hal::writeCommand(i(Opcode::SetTxContinuousWave)); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setTxContinuousPreamble() +{ + return Hal::writeCommand(i(Opcode::SetTxContinuousPreamble)); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setPacketType(PacketType packetType) +{ + buffer[0] = uint8_t(packetType); + return Hal::writeCommand(i(Opcode::SetPacketType), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getPacketType(PacketType &packetType) +{ + return Hal::readCommand(i(Opcode::GetPacketType), (uint8_t *) &packetType, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setRfFrequency(uint32_t rfFrequency) +{ + // The LSB of rfFrequency is equal to the PLL step i.e. 52e6/2^18 Hz, where 52e6 is the crystal frequency in Hz + constexpr float frequencyLsb = float(52_MHz) / 262144.f; + uint32_t freq = float(rfFrequency) / frequencyLsb; + + buffer[0] = (freq >> 16) & 0xFF; + buffer[1] = (freq >> 8) & 0xFF; + buffer[2] = freq & 0xFF; + + return Hal::writeCommand(i(Opcode::SetRfFrequency), buffer, 3); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setTxParams(uint8_t power, RampTime rampTime) +{ + buffer[0] = power; + buffer[1] = uint8_t(rampTime); + return Hal::writeCommand(i(Opcode::SetTxParams), buffer, 2); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setCadParams(CadSymbolNumber cadSymbolNumber) +{ + buffer[0] = uint8_t(cadSymbolNumber); + return Hal::writeCommand(i(Opcode::SetCadParams), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setBufferBaseAddress(uint8_t txBaseAddress , uint8_t rxBaseAddress) +{ + buffer[0] = txBaseAddress; + buffer[1] = rxBaseAddress; + return Hal::writeCommand(i(Opcode::SetBufferBaseAddress), buffer, 2); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setModulationParams(ModulationParams modulationParams) +{ + return Hal::writeCommand(i(Opcode::SetModulationParams), (uint8_t *) &modulationParams, 3); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setPacketParams(PacketParams packetParams) +{ + return Hal::writeCommand(i(Opcode::SetPacketParams), (uint8_t *) &packetParams, 7); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getRxBufferStatus(RxBufferStatus &rxBufferStatus) +{ + return Hal::readCommand(i(Opcode::GetRxBufferStatus), (uint8_t *) &rxBufferStatus, 2); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getPacketStatus(PacketStatus &packetStatus) +{ + return Hal::readCommand(i(Opcode::GetPacketStatus), (uint8_t *) &packetStatus, 5); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getRssiInst(uint8_t &rssiInst) +{ + return Hal::readCommand(Opcode::GetRssiInst, &rssiInst, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setDioIrqParams(Irq_t irqMask, Irq_t dio1Mask, Irq_t dio2Mask, Irq_t dio3Mask) +{ + buffer[0] = (irqMask.value >> 8) & 0x00FF; + buffer[1] = (irqMask.value & 0x00FF); + buffer[2] = (dio1Mask.value >> 8) & 0x00FF; + buffer[3] = (dio1Mask.value & 0x00FF); + buffer[4] = (dio2Mask.value >> 8) & 0x00FF; + buffer[5] = (dio2Mask.value & 0x00FF); + buffer[6] = (dio3Mask.value >> 8) & 0xFF; + buffer[7] = (dio3Mask.value & 0x00FF); + return Hal::writeCommand(i(Opcode::SetDioIrqParams), buffer, 8); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::getIrqStatus(Irq_t &irqStatus) +{ + RF_BEGIN(); + + if (RF_CALL(Hal::readCommand(i(Opcode::GetIrqStatus), buffer, 2))) + { + irqStatus.value = (buffer[0] << 8) | buffer[1]; + RF_RETURN(true); + } + + RF_END_RETURN(false); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::clearIrqStatus(Irq_t irqMask) +{ + buffer[0] = (irqMask.value >> 8) & 0xFF; + buffer[1] = irqMask.value & 0xFF; + return Hal::writeCommand(i(Opcode::ClrIrqStatus), buffer, 2); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setRegulatorMode(RegulatorMode regModeParam) +{ + buffer[0] = uint8_t(regModeParam); + return Hal::writeCommand(i(Opcode::SetRegulatorMode), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setSaveContext() +{ + return Hal::writeCommand(i(Opcode::SetSaveContext)); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setAutoFs(bool enable) +{ + buffer[0] = enable ? 0x01 : 0x00; + return Hal::writeCommand(i(Opcode::SetAutoFs), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setAutoTx(uint16_t time) +{ + buffer[0] = (time >> 8) & 0xFF; + buffer[1] = time & 0xFF; + return Hal::writeCommand(i(Opcode::SetAutoTx), buffer, 2); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setLongPreamble(bool enable) +{ + buffer[0] = enable ? 0x01 : 0x00; + return Hal::writeCommand(i(Opcode::SetLongPreamble), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setRangingRole(RangingRole rangingRole) +{ + buffer[0] = uint8_t(rangingRole); + return Hal::writeCommand(i(Opcode::SetLongPreamble), buffer, 1); +} + +// ----------------------------------------------------------------------------- + +template < class Hal > +modm::ResumableResult +Sx128x< Hal >::setAdvancedRanging(bool enable) +{ + buffer[0] = enable ? 0x01 : 0x00; + return Hal::writeCommand(i(Opcode::SetAdvancedRanging), buffer, 1); +} + +} \ No newline at end of file