Skip to main content

Sx126x

Struct Sx126x 

Source
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>

Source

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.

Source

pub fn board(&self) -> Board

Returns how the module wires the chip.

§Returns

The board.

Source

pub fn config(&self) -> Option<&RadioConfig>

Returns the configuration the chip was last tuned to.

§Returns

The configuration, or None before configure or after a reset or sleep.

Source

pub fn tx_power(&self, output_dbm: i8) -> TxPower

Returns the power settings for an output power on this board’s amplifier.

§Arguments
  • output_dbm - the output power wanted at the antenna port.
§Returns

The amplifier configuration and power setting.

Source

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,

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn standby(&mut self) -> Result<(), RadioError<SPI::Error>>

Puts the chip in STDBY_RC, which stops a transmission or a reception.

§Errors

Returns the bus errors of command.

Source

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 - true to keep the configuration in retention.
§Errors

Returns the bus errors of command.

Source

pub fn status(&mut self) -> Result<Status, RadioError<SPI::Error>>

Reads the status byte.

§Returns

The chip mode and how the last command went.

§Errors

Returns the bus errors of command.

Source

pub fn irq_status(&mut self) -> Result<Irq, RadioError<SPI::Error>>

Reads the pending interrupts.

§Returns

The IRQ register.

§Errors

Returns the bus errors of command.

Source

pub fn instantaneous_rssi(&mut self) -> Result<Decibels, RadioError<SPI::Error>>

Reads the signal power the receiver hears right now, while it listens.

§Returns

The instantaneous RSSI in dBm.

§Errors

Returns the bus errors of command.

Source

pub fn device_errors(&mut self) -> Result<DeviceErrors, RadioError<SPI::Error>>

Reads the calibration, oscillator, PLL, and amplifier errors the chip has flagged.

§Returns

The device errors.

§Errors

Returns the bus errors of command.

Source

pub fn clear_device_errors(&mut self) -> Result<(), RadioError<SPI::Error>>

Clears the device errors.

§Errors

Returns the bus errors of command.

Source

pub fn set_rx_boosted( &mut self, boosted: bool, ) -> Result<(), RadioError<SPI::Error>>

Chooses between the receiver’s power saving gain, the chip’s default, and its boosted gain, which buys sensitivity for current (Table 9-3).

§Arguments
  • boosted - true for boosted gain.
§Errors

Returns the bus errors of command.

Source

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.

Source

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 first query.answer_len bytes are filled.
§Errors

Returns RadioError::BufferTooSmall if answer is shorter than the answer, and the errors of command.

Source

pub fn write_register( &mut self, address: u16, values: &[u8], ) -> Result<(), RadioError<SPI::Error>>

Writes consecutive registers.

§Arguments
  • address - the first register’s address.
  • values - the values, one per register.
§Errors

Returns the errors of command.

Source

pub fn read_register( &mut self, address: u16, values: &mut [u8], ) -> Result<(), RadioError<SPI::Error>>

Reads consecutive registers.

§Arguments
  • address - the first register’s address.
  • values - where the values go, one per register.
§Errors

Returns the errors of command.

Source

pub fn write_buffer( &mut self, offset: u8, bytes: &[u8], ) -> Result<(), RadioError<SPI::Error>>

Writes bytes into the data buffer.

§Arguments
  • offset - where in the buffer the first byte goes.
  • bytes - the bytes.
§Errors

Returns the errors of command.

Source

pub fn read_buffer( &mut self, offset: u8, bytes: &mut [u8], ) -> Result<(), RadioError<SPI::Error>>

Reads bytes out of the data buffer.

§Arguments
  • offset - where in the buffer the first byte is.
  • bytes - where the bytes go.
§Errors

Returns the errors of command.

Trait Implementations§

Source§

impl<SPI, BUSY, RESET, D> From<Sx126x<SPI, BUSY, RESET, D>> for Radio<SPI, BUSY, RESET, D>

Source§

fn from(radio: Sx126x<SPI, BUSY, RESET, D>) -> Self

Converts to this type from the input type.
Source§

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>

What the radio reports when it or the bus under it fails.
Returns the link settings frames go out with, which the duty cycle’s arithmetic needs. Read more
Source§

fn start_transmit(&mut self, frame: &[u8]) -> Result<u64, Self::Error>

Starts sending one frame, without waiting for it to leave. Read more
Source§

fn finish_transmit(&mut self) -> Result<bool, Self::Error>

Reports whether the frame start_transmit began has left. Read more
Source§

fn listen(&mut self) -> Result<(), Self::Error>

Starts listening, and keeps listening frame after frame. Read more
Source§

fn take_frame( &mut self, buffer: &mut [u8], ) -> Result<Option<usize>, Self::Error>

Takes a frame the radio has received since the last call, dropping one whose CRC failed. Read more

Auto Trait Implementations§

§

impl<SPI, BUSY, RESET, D> Freeze for Sx126x<SPI, BUSY, RESET, D>
where SPI: Freeze, BUSY: Freeze, RESET: Freeze, D: Freeze,

§

impl<SPI, BUSY, RESET, D> RefUnwindSafe for Sx126x<SPI, BUSY, RESET, D>

§

impl<SPI, BUSY, RESET, D> Send for Sx126x<SPI, BUSY, RESET, D>
where SPI: Send, BUSY: Send, RESET: Send, D: Send,

§

impl<SPI, BUSY, RESET, D> Sync for Sx126x<SPI, BUSY, RESET, D>
where SPI: Sync, BUSY: Sync, RESET: Sync, D: Sync,

§

impl<SPI, BUSY, RESET, D> Unpin for Sx126x<SPI, BUSY, RESET, D>
where SPI: Unpin, BUSY: Unpin, RESET: Unpin, D: Unpin,

§

impl<SPI, BUSY, RESET, D> UnsafeUnpin for Sx126x<SPI, BUSY, RESET, D>
where SPI: UnsafeUnpin, BUSY: UnsafeUnpin, RESET: UnsafeUnpin, D: UnsafeUnpin,

§

impl<SPI, BUSY, RESET, D> UnwindSafe for Sx126x<SPI, BUSY, RESET, D>
where SPI: UnwindSafe, BUSY: UnwindSafe, RESET: UnwindSafe, D: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.