pub struct Sx126x<SPI, BUSY, RESET, D> { /* private fields */ }Expand description
A Semtech SX1261, SX1262, or LLCC68 on an SPI bus, with its BUSY and NRESET lines.
init resets the chip and sets up what the Board wires around it,
configure tunes it to a RadioConfig, and
transmit and receive send and wait for one
frame each. For anything those do not cover, command,
query, and the register and buffer methods reach the chip directly,
with the BUSY handshake still done for them.
§Examples
The chip’s side of initialization, scripted: an SX1262 module with a crystal, which answers GetStatus in STDBY_RC.
use pamoja_hal::digital::{OutputPin, PinState};
use pamoja_hal::script::{DelayLog, PinScript, SpiScript, SpiStep};
use pamoja_radios::sx126x::config::PowerAmplifier;
use pamoja_radios::sx126x::{Board, Sx126x};
let spi = SpiScript::new([
SpiStep::write([0x80, 0x00]),
SpiStep::write([0xC0]),
SpiStep::read([0x22]),
SpiStep::write([0x96, 0x00]),
SpiStep::write([0x8A, 0x01]),
SpiStep::write([0x1D, 0x08, 0xD8, 0x00]),
SpiStep::read([0x08]),
SpiStep::write([0x0D, 0x08, 0xD8]),
SpiStep::write([0x1E]),
SpiStep::write([0x8F, 0x00, 0x00]),
]);
let mut busy = PinScript::new([]);
busy.set_low()?;
let board = Board::new(PowerAmplifier::HighPower);
let mut radio = Sx126x::new(spi, busy, PinScript::new([]), DelayLog::new(), board);
radio.init().expect("the scripted SX1262 answers");
let (spi, _, reset, _) = radio.release();
assert!(spi.done());
assert_eq!(reset.driven(), [PinState::Low, PinState::High]);Implementations§
Source§impl<SPI, BUSY, RESET, D> Sx126x<SPI, BUSY, RESET, D>
impl<SPI, BUSY, RESET, D> Sx126x<SPI, BUSY, RESET, D>
Sourcepub fn new(spi: SPI, busy: BUSY, reset: RESET, delay: D, board: Board) -> Self
pub fn new(spi: SPI, busy: BUSY, reset: RESET, delay: D, board: Board) -> Self
Wraps a chip’s SPI device and lines. Nothing is sent until init.
§Arguments
spi- the SPI device, with NSS as its chip select.busy- the BUSY line, as an input.reset- the NRESET line, as an output.delay- a delay for the reset pulse and the polling.board- how the module wires the chip.
§Returns
The driver.
Sourcepub fn config(&self) -> Option<&RadioConfig>
pub fn config(&self) -> Option<&RadioConfig>
Sourcepub fn release(self) -> (SPI, BUSY, RESET, D)
pub fn release(self) -> (SPI, BUSY, RESET, D)
Gives back the SPI device, the lines, and the delay.
§Returns
The SPI device, BUSY, NRESET, and the delay.
Source§impl<SPI, BUSY, RESET, D> Sx126x<SPI, BUSY, RESET, D>where
SPI: SpiDevice,
BUSY: InputPin,
RESET: OutputPin,
D: DelayNs,
impl<SPI, BUSY, RESET, D> Sx126x<SPI, BUSY, RESET, D>where
SPI: SpiDevice,
BUSY: InputPin,
RESET: OutputPin,
D: DelayNs,
Sourcepub fn init(&mut self) -> Result<(), RadioError<SPI::Error>>
pub fn init(&mut self) -> Result<(), RadioError<SPI::Error>>
Resets the chip and sets up the parts the board wires around it.
NRESET is pulsed low, and the chip, which calibrates itself on the way out of reset, is put in STDBY_RC and asked for its status. A TCXO is then powered from DIO3 and every block calibrated again, since section 9.2.1 says the calibration at power up fails on a TCXO, and the XOSC start error that section 13.3.6 expects is cleared. The regulator and the DIO2 antenna switch follow, then the LoRa packet type, the antenna mismatch workaround of section 15.2 for the high power amplifier, and the data buffer base addresses.
§Errors
Returns RadioError::Absent if the status is not STDBY_RC, RadioError::Busy if
BUSY never falls, and RadioError::Spi or RadioError::Pin if the bus or a line
fails.
Sourcepub fn configure(
&mut self,
config: RadioConfig,
) -> Result<(), RadioError<SPI::Error>>
pub fn configure( &mut self, config: RadioConfig, ) -> Result<(), RadioError<SPI::Error>>
Tunes the chip to a configuration.
The chip goes to STDBY_RC and takes the LoRa packet type, a new image calibration if the band moved, the frequency, the amplifier configuration and power, the modulation, and the sync word. The packet parameters, which carry the payload length, are sent with each transmission and reception, after the modulation as section 14.5 requires.
§Arguments
config- the configuration.
§Errors
Returns RadioError::Bandwidth if the link’s bandwidth is not one the SX126x has,
RadioError::Llcc68 if the board has an LLCC68 that does not support the link,
RadioError::Amplifier if the power settings are for the other amplifier, and the
bus errors of command.
Sourcepub fn transmit(
&mut self,
payload: &[u8],
) -> Result<u64, RadioError<SPI::Error>>
pub fn transmit( &mut self, payload: &[u8], ) -> Result<u64, RadioError<SPI::Error>>
Sends one frame and waits for it to leave.
This is start_transmit, a wait for the frame’s airtime,
and finish_transmit read every IRQ_POLL_US until the
chip reports the frame sent or timed out.
§Arguments
payload- the frame’s payload, at most 255 bytes.
§Returns
The frame’s airtime in microseconds, for a DutyCycle to
count.
§Errors
Returns the errors of start_transmit and
finish_transmit, and RadioError::NoInterrupt if the
chip reports neither outcome within its own timeout and TIMEOUT_MARGIN_US more.
Sourcepub fn start_transmit(
&mut self,
payload: &[u8],
) -> Result<u64, RadioError<SPI::Error>>
pub fn start_transmit( &mut self, payload: &[u8], ) -> Result<u64, RadioError<SPI::Error>>
Starts sending one frame and returns once the chip is transmitting.
The steps are those of section 14.2 after configuration: the payload into the data
buffer, the packet parameters, the inverted IQ workaround of section 15.4, TxDone and
TIMEOUT routed to DIO1, the 500 kHz workaround of section 15.1, and SetTx with a
timeout of the frame’s airtime and TIMEOUT_MARGIN_US. A caller with its own
scheduler waits out the airtime and then calls
finish_transmit, or watches DIO1.
§Arguments
payload- the frame’s payload, at most 255 bytes.
§Returns
The frame’s airtime in microseconds.
§Errors
Returns RadioError::NotConfigured before configure,
RadioError::PayloadTooLong past 255 bytes, and the bus errors of
command.
Sourcepub fn finish_transmit(&mut self) -> Result<bool, RadioError<SPI::Error>>
pub fn finish_transmit(&mut self) -> Result<bool, RadioError<SPI::Error>>
Reports whether the frame start_transmit began has left.
The IRQ register is read once, and on TxDone or TIMEOUT the interrupts are cleared.
§Returns
true once the frame has been sent, false while it is still going out.
§Errors
Returns RadioError::TxTimeout if the chip timed out, and the bus errors of
command.
Sourcepub fn receive(
&mut self,
buffer: &mut [u8],
timeout_us: u64,
) -> Result<Reception, RadioError<SPI::Error>>
pub fn receive( &mut self, buffer: &mut [u8], timeout_us: u64, ) -> Result<Reception, RadioError<SPI::Error>>
Listens for one frame.
The steps are those of section 14.3 after configuration: the packet parameters with the buffer’s length as the most to accept, the inverted IQ workaround, RxDone, TIMEOUT, CrcErr, and HeaderErr routed to DIO1, and SetRx with the timeout. Once an interrupt arrives, the timer is stopped and its event cleared as section 15.3 advises after any reception with a timeout, the interrupts are cleared, and a frame that checked is copied out of the data buffer with its signal levels.
§Arguments
buffer- where the payload goes; its length, up to 255, is the most accepted.timeout_us- how long to listen for a frame to start, in microseconds.
§Returns
The frame’s length and levels, or that the timeout passed or the frame was corrupt.
§Errors
Returns RadioError::NotConfigured before configure,
RadioError::BufferTooSmall if the chip reports a longer payload than the buffer
holds, RadioError::NoInterrupt if it never answers, and the bus errors of
command.
Sourcepub fn listen(&mut self) -> Result<(), RadioError<SPI::Error>>
pub fn listen(&mut self) -> Result<(), RadioError<SPI::Error>>
Starts listening with no timeout, so the chip receives frame after frame until another command stops it: the Rx Continuous mode of Table 13-9.
The setup is that of receive, accepting the 255 bytes a frame
may carry, with RxDone, CrcErr, and HeaderErr routed to DIO1. Each frame is read with
take_frame.
§Errors
Returns RadioError::NotConfigured before configure, and the
bus errors of command.
Sourcepub fn take_frame(
&mut self,
buffer: &mut [u8],
) -> Result<Option<Reception>, RadioError<SPI::Error>>
pub fn take_frame( &mut self, buffer: &mut [u8], ) -> Result<Option<Reception>, RadioError<SPI::Error>>
Takes the frame a listen has received, if one has arrived.
The IRQ register is read once. On RxDone, CrcErr, or HeaderErr those interrupts are cleared, and a frame that checked is copied out with its signal levels while the chip goes on listening.
§Arguments
buffer- where the payload goes.
§Returns
The frame, a corrupt frame, or None when nothing has arrived.
§Errors
Returns RadioError::BufferTooSmall if the payload does not fit, and the bus errors
of command.
Sourcepub fn standby(&mut self) -> Result<(), RadioError<SPI::Error>>
pub fn standby(&mut self) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn sleep(&mut self, warm_start: bool) -> Result<(), RadioError<SPI::Error>>
pub fn sleep(&mut self, warm_start: bool) -> Result<(), RadioError<SPI::Error>>
Puts the chip to sleep until the next command wakes it.
A warm start keeps the chip’s configuration in retention; a cold start loses it,
and init must run again. Either way the driver forgets the
RadioConfig, so configure runs before the next frame. The
next command wakes the chip with GetStatus, pausing WAKE_SETUP_NS after NSS
falls.
§Arguments
warm_start-trueto keep the configuration in retention.
§Errors
Returns the bus errors of command.
Sourcepub fn status(&mut self) -> Result<Status, RadioError<SPI::Error>>
pub fn status(&mut self) -> Result<Status, RadioError<SPI::Error>>
Sourcepub fn irq_status(&mut self) -> Result<Irq, RadioError<SPI::Error>>
pub fn irq_status(&mut self) -> Result<Irq, RadioError<SPI::Error>>
Sourcepub fn instantaneous_rssi(&mut self) -> Result<Decibels, RadioError<SPI::Error>>
pub fn instantaneous_rssi(&mut self) -> Result<Decibels, RadioError<SPI::Error>>
Sourcepub fn device_errors(&mut self) -> Result<DeviceErrors, RadioError<SPI::Error>>
pub fn device_errors(&mut self) -> Result<DeviceErrors, RadioError<SPI::Error>>
Sourcepub fn clear_device_errors(&mut self) -> Result<(), RadioError<SPI::Error>>
pub fn clear_device_errors(&mut self) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn set_rx_boosted(
&mut self,
boosted: bool,
) -> Result<(), RadioError<SPI::Error>>
pub fn set_rx_boosted( &mut self, boosted: bool, ) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn command(
&mut self,
command: Command,
) -> Result<(), RadioError<SPI::Error>>
pub fn command( &mut self, command: Command, ) -> Result<(), RadioError<SPI::Error>>
Sends one command once BUSY is low, waking the chip first if it sleeps.
§Arguments
command- the command.
§Errors
Returns RadioError::Busy if BUSY never falls, RadioError::Spi if the SPI
device fails, and RadioError::Pin if BUSY cannot be read.
Sourcepub fn query(
&mut self,
query: Query,
answer: &mut [u8],
) -> Result<(), RadioError<SPI::Error>>
pub fn query( &mut self, query: Query, answer: &mut [u8], ) -> Result<(), RadioError<SPI::Error>>
Sends a query and reads its answer in the same transaction, once BUSY is low.
§Arguments
query- the query.answer- where the answer goes; its firstquery.answer_lenbytes are filled.
§Errors
Returns RadioError::BufferTooSmall if answer is shorter than the answer, and
the errors of command.
Sourcepub fn write_register(
&mut self,
address: u16,
values: &[u8],
) -> Result<(), RadioError<SPI::Error>>
pub fn write_register( &mut self, address: u16, values: &[u8], ) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn read_register(
&mut self,
address: u16,
values: &mut [u8],
) -> Result<(), RadioError<SPI::Error>>
pub fn read_register( &mut self, address: u16, values: &mut [u8], ) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn write_buffer(
&mut self,
offset: u8,
bytes: &[u8],
) -> Result<(), RadioError<SPI::Error>>
pub fn write_buffer( &mut self, offset: u8, bytes: &[u8], ) -> Result<(), RadioError<SPI::Error>>
Sourcepub fn read_buffer(
&mut self,
offset: u8,
bytes: &mut [u8],
) -> Result<(), RadioError<SPI::Error>>
pub fn read_buffer( &mut self, offset: u8, bytes: &mut [u8], ) -> Result<(), RadioError<SPI::Error>>
Trait Implementations§
Source§impl<SPI, BUSY, RESET, D> LoraRadio for Sx126x<SPI, BUSY, RESET, D>where
SPI: SpiDevice,
BUSY: InputPin,
RESET: OutputPin,
D: DelayNs,
impl<SPI, BUSY, RESET, D> LoraRadio for Sx126x<SPI, BUSY, RESET, D>where
SPI: SpiDevice,
BUSY: InputPin,
RESET: OutputPin,
D: DelayNs,
Source§type Error = RadioError<<SPI as ErrorType>::Error>
type Error = RadioError<<SPI as ErrorType>::Error>
Source§fn link(&self) -> Option<LinkSettings>
fn link(&self) -> Option<LinkSettings>
Source§fn start_transmit(&mut self, frame: &[u8]) -> Result<u64, Self::Error>
fn start_transmit(&mut self, frame: &[u8]) -> Result<u64, Self::Error>
Source§fn finish_transmit(&mut self) -> Result<bool, Self::Error>
fn finish_transmit(&mut self) -> Result<bool, Self::Error>
start_transmit began has
left. Read more