pub struct Sx1302<SPI, RESET, D> { /* private fields */ }Expand description
A concentrator on an SPI device, with its reset line.
Implementations§
Source§impl<SPI, RESET, D> Sx1302<SPI, RESET, D>
impl<SPI, RESET, D> Sx1302<SPI, RESET, D>
Source§impl<SPI, RESET, D> Sx1302<SPI, RESET, D>where
SPI: SpiDevice,
RESET: OutputPin,
D: DelayNs,
impl<SPI, RESET, D> Sx1302<SPI, RESET, D>where
SPI: SpiDevice,
RESET: OutputPin,
D: DelayNs,
Sourcepub fn reset(&mut self) -> Result<(), ConcentratorError<SPI::Error>>
pub fn reset(&mut self) -> Result<(), ConcentratorError<SPI::Error>>
Pulses the reset line.
The concentrator does not reset itself. On a gateway board the line is a host pin, and this drives it the way the reference platform script does.
§Returns
Ok(()) once the chip has been released and given time to come up.
§Errors
Returns ConcentratorError::Pin if the line cannot be driven.
Sourcepub fn version(&mut self) -> Result<u8, ConcentratorError<SPI::Error>>
pub fn version(&mut self) -> Result<u8, ConcentratorError<SPI::Error>>
Reads the version register.
§Returns
What it answered with, which is EXPECTED_VERSION on a
concentrator that is powered and wired the right way round.
§Errors
Returns ConcentratorError::Spi if the transfer fails.
Sourcepub fn check(&mut self) -> Result<(), ConcentratorError<SPI::Error>>
pub fn check(&mut self) -> Result<(), ConcentratorError<SPI::Error>>
Checks that a concentrator is answering at all.
§Returns
Ok(()) when the version register reads what it should.
§Errors
Returns ConcentratorError::NotAnswering carrying what it read instead, which
separates an unpowered board (zero) from a bus nothing is driving (all ones).
Sourcepub fn identify(&mut self) -> Result<Model, ConcentratorError<SPI::Error>>
pub fn identify(&mut self) -> Result<Model, ConcentratorError<SPI::Error>>
Reads the part number out of the one-time programmable memory.
§Returns
Which concentrator this is.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn reset_front_end(
&mut self,
chain: Chain,
front_end: FrontEnd,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn reset_front_end( &mut self, chain: Chain, front_end: FrontEnd, ) -> Result<(), ConcentratorError<SPI::Error>>
Resets the front end on a chain, through the concentrator.
The concentrator is clocked from the host while it does this, so it is still listening on the bus while the radio it drives is held down.
§Arguments
chain- which chain’s front end to reset.front_end- which front end it is, since the SX1250 calibrates itself afterwards.
§Returns
Ok(()) once it is out of reset and settled.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn load_firmware(
&mut self,
mcu: Mcu,
image: &[u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn load_firmware( &mut self, mcu: Mcu, image: &[u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Gives a microcontroller its firmware, and checks that it took.
The image is written, read back, and compared before the microcontroller is released, and the chip is asked afterwards whether it accepted it. Both checks matter, and they fail differently: a read-back mismatch means the bus is not carrying the bytes, while a parity failure means they arrived and the image itself is wrong.
§Arguments
mcu- which microcontroller to load.image- the firmware, which isFIRMWARE_LENbytes.
§Returns
Ok(()) once it is loaded and the chip has accepted it.
§Errors
Returns ConcentratorError::Firmware for an image of the wrong size, a read-back
that differs, or a parity check the chip refused.
Sourcepub fn read_register(
&mut self,
register: Register,
) -> Result<u8, ConcentratorError<SPI::Error>>
pub fn read_register( &mut self, register: Register, ) -> Result<u8, ConcentratorError<SPI::Error>>
Reads one register.
§Arguments
register- which register.
§Returns
Its value, taken out of the byte it shares with its neighbors.
§Errors
Returns ConcentratorError::Spi if the transfer fails.
Sourcepub fn write_register(
&mut self,
register: Register,
value: u8,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn write_register( &mut self, register: Register, value: u8, ) -> Result<(), ConcentratorError<SPI::Error>>
Writes one register, leaving the rest of the byte it shares as it was.
§Arguments
register- which register.value- what to put there.
§Returns
Ok(()) once written.
§Errors
Returns ConcentratorError::Spi if a transfer fails. A register narrower than a
byte is read first, so this can cost two transfers.
Sourcepub fn write_memory(
&mut self,
address: u16,
data: &[u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn write_memory( &mut self, address: u16, data: &[u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Writes a run of bytes into the chip’s memory.
§Arguments
address- where the first byte lands.data- the bytes.
§Returns
Ok(()) once every chunk has gone out.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn read_memory(
&mut self,
address: u16,
into: &mut [u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn read_memory( &mut self, address: u16, into: &mut [u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Reads a run of bytes out of the chip’s memory.
§Arguments
address- where to start.into- where to put them.
§Returns
Ok(()) once it is filled.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn read_fifo(
&mut self,
address: u16,
into: &mut [u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn read_fifo( &mut self, address: u16, into: &mut [u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Reads a port rather than a window, so every chunk comes from the same address.
The receive buffer is a port: reading it moves the chip pointer along by itself. A reader that moves the address as well walks past the packets it came for, which only shows once there is more waiting than one chunk holds.
§Arguments
address- the port to read.into- where the bytes go, filled to its length.
§Returns
Ok(()) once it is filled.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn waiting(&mut self) -> Result<u16, ConcentratorError<SPI::Error>>
pub fn waiting(&mut self) -> Result<u16, ConcentratorError<SPI::Error>>
How many bytes the receive buffer is holding.
The count is read twice and the larger kept. A read of the pair can answer with less than is really there, and the reference guards against it the same way.
§Returns
The number of bytes waiting, which is zero when nothing has been heard.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn receive<'a>(
&mut self,
into: &'a mut [u8],
) -> Result<&'a [u8], ConcentratorError<SPI::Error>>
pub fn receive<'a>( &mut self, into: &'a mut [u8], ) -> Result<&'a [u8], ConcentratorError<SPI::Error>>
Takes everything the receive buffer is holding.
What comes back is packets back to back, each wrapped in the metadata the chip writes
around it, which packets walks.
§Arguments
into- where the bytes go.BUFFER_LENalways fits.
§Returns
What was read, which is empty when nothing has been heard.
§Errors
Returns ConcentratorError::Overrun if more is waiting than there is room for,
having read nothing, so a larger buffer still gets it. Returns
ConcentratorError::Spi if a transfer fails.
Sourcepub fn transmit(
&mut self,
chain: Chain,
transmit: &Transmit<'_>,
trigger: Trigger,
start_delay: u16,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn transmit( &mut self, chain: Chain, transmit: &Transmit<'_>, trigger: Trigger, start_delay: u16, ) -> Result<(), ConcentratorError<SPI::Error>>
Loads a packet and arms the trigger that sends it.
The chip is not handed the packet and the moment together. The payload goes into the
buffer of the chain, the delay it starts early by is programmed, and only then is the
trigger armed. steps holds that order and this walks it.
§Arguments
chain- which transmit chain sends it.transmit- the packet and everything the modulator has to be told about it. A chain given a payload without this sends it on whatever it was last set to.trigger- what the send waits for.start_delay- whatstart_delayworked out.
§Returns
Ok(()) once the trigger is armed. The packet leaves when the trigger says.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn send(
&mut self,
chain: Chain,
payload: &[u8],
trigger: Trigger,
start_delay: u16,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn send( &mut self, chain: Chain, payload: &[u8], trigger: Trigger, start_delay: u16, ) -> Result<(), ConcentratorError<SPI::Error>>
Loads a payload into a chain that is already configured, and arms its trigger.
transmit describes a packet and then calls this. A caller answering
on settings the chain already holds can call it directly, which is every downlink
after the first on one channel.
§Arguments
chain- which transmit chain sends it.payload- the bytes the chain sends. For frequency shift keying the length byte goes first, as the chip reads it out of the buffer.trigger- what the send waits for.start_delay- whatstart_delayworked out.
§Returns
Ok(()) once the trigger is armed. The packet leaves when the trigger says.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn checked_transmission(
&mut self,
chain: Chain,
) -> Result<bool, ConcentratorError<SPI::Error>>
pub fn checked_transmission( &mut self, chain: Chain, ) -> Result<bool, ConcentratorError<SPI::Error>>
Waits for a transmission a carrier check guards to start, and reports whether the check let it go out.
Semtech’s lgw_lbt_tx_status: poll the gain control until it reports the chain
started, read whether the check held it back, clear the status through the first
mailbox, wait for it to read clear, and acknowledge. The status is cleared even when the
start never came, so the next transmission is not read against this one.
§Arguments
chain- the chain the packet was armed on.
§Returns
true if the packet went out, false if the channel was busy.
§Errors
Returns ConcentratorError::Stalled if the transmission never started or its status
never cleared, and ConcentratorError::Spi if a transfer fails.
Sourcepub fn abort(
&mut self,
chain: Chain,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn abort( &mut self, chain: Chain, ) -> Result<(), ConcentratorError<SPI::Error>>
Takes back a packet armed on a chain and waits for the chain to come free.
Semtech’s sx1302_tx_abort: every trigger reset, then the status polled for up to a
second.
§Arguments
chain- the chain to free.
§Errors
Returns ConcentratorError::Stalled if the chain does not come free, and
ConcentratorError::Spi if a transfer fails.
Sourcepub fn tx_status(
&mut self,
chain: Chain,
) -> Result<TxStatus, ConcentratorError<SPI::Error>>
pub fn tx_status( &mut self, chain: Chain, ) -> Result<TxStatus, ConcentratorError<SPI::Error>>
What a transmit chain is doing.
§Arguments
chain- the chain to ask.
§Returns
Its state, which is TxStatus::Free when it will take another packet.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn configure_channels(
&mut self,
plan: &Plan,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn configure_channels( &mut self, plan: &Plan, ) -> Result<(), ConcentratorError<SPI::Error>>
Points a concentrator at the channels it is to listen on.
A concentrator that has been reset and given firmware still hears nothing until this
has run. Its receivers have been given no frequencies, no radio to take samples from,
no spreading factors to look for, and no permission to run at all.
steps holds that order and this walks it.
§Arguments
plan- what to listen for.
§Returns
Ok(()) once the receivers are running.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn select_clock(
&mut self,
chain: Chain,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn select_clock( &mut self, chain: Chain, ) -> Result<(), ConcentratorError<SPI::Error>>
Takes the concentrator clock from the front end on a chain.
Until this runs the chip is clocked by the bus, which is enough to answer registers
and nothing else. The front end it takes the clock from has to be in receive, which
is where setup_front_end leaves it.
§Arguments
chain- the chain whose front end carries the clock.
§Returns
Ok(()) once the chip is running on the radio clock.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn release_front_ends(
&mut self,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn release_front_ends( &mut self, ) -> Result<(), ConcentratorError<SPI::Error>>
Hands the front ends back to the gain control.
The host drives them while they are being reset and tuned. From here on the gain control owns them, which is what lets it move gains while packets are arriving.
§Returns
Ok(()) once the host has let go.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn start_gain_control(
&mut self,
front_end: FrontEnd,
listen_before_talk: bool,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn start_gain_control( &mut self, front_end: FrontEnd, listen_before_talk: bool, ) -> Result<(), ConcentratorError<SPI::Error>>
Configures the gain control microcontroller and lets it run.
Loading its firmware is only half of bringing it up: it comes out of reset waiting to
be told what gains to use, one group of settings at a time, and a concentrator whose
gain control was never configured hears very little.
start_gain_control holds that exchange and this
walks it against the mailboxes.
§Arguments
front_end- which front end the board carries, which decides the gains and the firmware version expected.listen_before_talk- whether the SX1261 beside the concentrator checks a channel before the gateway talks on it.
§Returns
Ok(()) once the microcontroller has taken every group and been told there is no
more to come.
§Errors
Returns ConcentratorError::WrongFirmware if it is running an image this crate does
not drive, ConcentratorError::Stalled if it stops acknowledging, and
ConcentratorError::Spi if a transfer fails.
Sourcepub fn start_arbiter(
&mut self,
dual_demodulation: u8,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn start_arbiter( &mut self, dual_demodulation: u8, ) -> Result<(), ConcentratorError<SPI::Error>>
Configures the arbiter microcontroller and lets it run.
The arbiter shares the receivers between the channels. It comes up halted and stays halted until it is told to resume.
§Arguments
dual_demodulation- which spreading factors are demodulated twice over, one bit each counting from SF5. Demodulating twice buys a finer timestamp and costs capacity, so a gateway that does not need one passes zero.
§Returns
Ok(()) once the arbiter reports it is running again.
§Errors
Returns ConcentratorError::WrongFirmware if it is running an image this crate does
not drive, ConcentratorError::Stalled if it never resumes, and
ConcentratorError::Spi if a transfer fails.
Sourcepub fn counter(
&mut self,
counter: &mut Counter,
) -> Result<(u32, u32), ConcentratorError<SPI::Error>>
pub fn counter( &mut self, counter: &mut Counter, ) -> Result<(u32, u32), ConcentratorError<SPI::Error>>
Reads the counter packets are stamped against.
Both counters come back in one burst, and the burst is read twice, because a read can catch a counter mid-step. When the two agree the first is kept; when a high byte has moved between them a third read settles it. That is what the reference does, and it is a different guard from the one on the receive byte count, where the larger of two readings is kept instead.
§Arguments
counter- the state carried between readings, which is what widens a counter of 27 bits past its rollover.
§Returns
The free running counter and then the pulse one, in microseconds.
§Errors
Returns ConcentratorError::Spi if a transfer fails.
Sourcepub fn radio_command(
&mut self,
chain: Chain,
opcode: u8,
data: &[u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn radio_command( &mut self, chain: Chain, opcode: u8, data: &[u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Sends a command to the front end on a chain.
A front end answers on the same bus as the concentrator, with the first byte of the
frame naming it rather than the concentrator. It gives the host no line to watch, so
this waits WAIT_BUSY_US first, as the reference does.
§Arguments
chain- the chain the front end is on.opcode- the command.data- what the command carries.
§Returns
Ok(()) once it has been sent.
§Errors
Returns ConcentratorError::Spi if the transfer fails.
Sourcepub fn radio_query(
&mut self,
chain: Chain,
opcode: u8,
into: &mut [u8],
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn radio_query( &mut self, chain: Chain, opcode: u8, into: &mut [u8], ) -> Result<(), ConcentratorError<SPI::Error>>
Asks the front end on a chain for an answer.
§Arguments
chain- the chain the front end is on.opcode- the command.into- where the answer goes, filled to its length.
§Returns
Ok(()) once it is filled.
§Errors
Returns ConcentratorError::Spi if the transfer fails.
Sourcepub fn setup_front_end(
&mut self,
chain: Chain,
hertz: u32,
single_input: bool,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn setup_front_end( &mut self, chain: Chain, hertz: u32, single_input: bool, ) -> Result<(), ConcentratorError<SPI::Error>>
Brings the front end on a chain up and leaves it listening.
A concentrator hears nothing until this has run, because the carrier is set here
rather than on the concentrator. It also matters beyond receiving: the concentrator
takes its clock from a front end that is in receive, so one left idle stops the chip
beside it. setup holds the order and this walks it.
§Arguments
chain- the chain the front end is on.hertz- the carrier to tune to.single_input- whether the board wires the front end single ended rather than differential.
§Returns
Ok(()) once it is tuned and listening.
§Errors
Returns ConcentratorError::FrontEndMode if it does not settle into a standby it
was put in, which is what an unpowered or unclocked front end looks like, and
ConcentratorError::Spi if a transfer fails.
Sourcepub fn calibrate_front_end(
&mut self,
chain: Chain,
hertz: u32,
) -> Result<(), ConcentratorError<SPI::Error>>
pub fn calibrate_front_end( &mut self, chain: Chain, hertz: u32, ) -> Result<(), ConcentratorError<SPI::Error>>
Calibrates the front end on a chain over the band a carrier falls in.
The chip calibrates a band rather than a frequency, and it knows five of them. This is the SX1250 half of radio calibration: it runs once the front ends have been reset and while the host still drives them, before the receivers are given their channels. The front ends that came before calibrate through a firmware image instead.
§Arguments
chain- the chain the front end is on.hertz- the carrier it will be tuned to.
§Returns
Ok(()) once the chip reports no fault.
§Errors
Returns ConcentratorError::UnsupportedBand for a carrier outside every band,
without sending anything, ConcentratorError::ImageCalibration if the chip reports
the calibration failed, and ConcentratorError::Spi if a transfer fails.