pamoja.radios.sx126x

The Semtech SX1261, SX1262, and LLCC68, as the bytes they take and the answers they give.

Every command goes out in one SPI transaction framed by NSS, sent once the chip's BUSY line is low, and a query's answer is read in the same transaction after its bytes. These functions build the bytes and decode the answers from the SX1261/2 datasheet (Rev 2.2), so a program with its own SPI access can drive the chip with nothing else.

  1"""The Semtech SX1261, SX1262, and LLCC68, as the bytes they take and the answers they give.
  2
  3Every command goes out in one SPI transaction framed by NSS, sent once the chip's BUSY line
  4is low, and a query's answer is read in the same transaction after its bytes. These
  5functions build the bytes and decode the answers from the SX1261/2 datasheet (Rev 2.2), so a
  6program with its own SPI access can drive the chip with nothing else.
  7"""
  8
  9from __future__ import annotations
 10
 11from enum import Enum, IntFlag
 12
 13from pamoja._native import (
 14    LinkBudget,
 15    LoraLink,
 16    Sx126xPacketStatus as PacketStatus,
 17    Sx126xQuery as Query,
 18    Sx126xRxBufferStatus as RxBufferStatus,
 19    Sx126xStatus as Status,
 20    Sx126xTxPower as TxPower,
 21)
 22from pamoja._native import sx126x_calibrate_image as _calibrate_image
 23from pamoja._native import sx126x_clear_irq_status as _clear_irq_status
 24from pamoja._native import sx126x_constants as _constants
 25from pamoja._native import sx126x_device_errors as _device_errors
 26from pamoja._native import sx126x_frequency_word as _frequency_word
 27from pamoja._native import sx126x_get_device_errors as _get_device_errors
 28from pamoja._native import sx126x_get_irq_status as _get_irq_status
 29from pamoja._native import sx126x_get_packet_status as _get_packet_status
 30from pamoja._native import sx126x_get_rssi_inst as _get_rssi_inst
 31from pamoja._native import sx126x_get_rx_buffer_status as _get_rx_buffer_status
 32from pamoja._native import sx126x_get_status as _get_status
 33from pamoja._native import sx126x_image_calibration as _image_calibration
 34from pamoja._native import sx126x_irq as _irq
 35from pamoja._native import sx126x_llcc68_supports as _llcc68_supports
 36from pamoja._native import sx126x_packet_status as _packet_status
 37from pamoja._native import sx126x_ramp_time_us as _ramp_time_us
 38from pamoja._native import sx126x_read_buffer as _read_buffer
 39from pamoja._native import sx126x_read_register as _read_register
 40from pamoja._native import sx126x_rssi_inst_dbm as _rssi_inst_dbm
 41from pamoja._native import sx126x_rx_buffer_status as _rx_buffer_status
 42from pamoja._native import sx126x_set_dio_irq_params as _set_dio_irq_params
 43from pamoja._native import sx126x_set_lora_modulation_params as _set_lora_modulation_params
 44from pamoja._native import sx126x_set_lora_packet_params as _set_lora_packet_params
 45from pamoja._native import sx126x_set_pa_config as _set_pa_config
 46from pamoja._native import sx126x_set_packet_type_lora as _set_packet_type_lora
 47from pamoja._native import sx126x_set_rf_frequency as _set_rf_frequency
 48from pamoja._native import sx126x_set_rx as _set_rx
 49from pamoja._native import sx126x_set_rx_continuous as _set_rx_continuous
 50from pamoja._native import sx126x_set_sleep as _set_sleep
 51from pamoja._native import sx126x_set_standby as _set_standby
 52from pamoja._native import sx126x_set_tx as _set_tx
 53from pamoja._native import sx126x_set_tx_params as _set_tx_params
 54from pamoja._native import sx126x_status as _status
 55from pamoja._native import sx126x_timeout_steps as _timeout_steps
 56from pamoja._native import sx126x_tx_power as _tx_power
 57from pamoja._native import sx126x_tx_power_under_ceiling as _tx_power_under_ceiling
 58from pamoja._native import sx126x_write_buffer as _write_buffer
 59from pamoja._native import sx126x_write_register as _write_register
 60
 61__all__ = [
 62    "REGISTER_LORA_SYNC_WORD",
 63    "RX_CONTINUOUS",
 64    "SYNC_WORD_PRIVATE",
 65    "SYNC_WORD_PUBLIC",
 66    "Amplifier",
 67    "DeviceError",
 68    "Irq",
 69    "PacketStatus",
 70    "Query",
 71    "RxBufferStatus",
 72    "Status",
 73    "TxPower",
 74    "calibrate_image",
 75    "clear_irq_status",
 76    "device_errors",
 77    "frequency_word",
 78    "get_device_errors",
 79    "get_irq_status",
 80    "get_packet_status",
 81    "get_rssi_inst",
 82    "get_rx_buffer_status",
 83    "get_status",
 84    "image_calibration",
 85    "irq",
 86    "llcc68_supports",
 87    "packet_status",
 88    "ramp_time_us",
 89    "read_buffer",
 90    "read_register",
 91    "rssi_inst_dbm",
 92    "rx_buffer_status",
 93    "set_dio_irq_params",
 94    "set_lora_modulation_params",
 95    "set_lora_packet_params",
 96    "set_pa_config",
 97    "set_packet_type_lora",
 98    "set_rf_frequency",
 99    "set_rx",
100    "set_rx_continuous",
101    "set_sleep",
102    "set_standby",
103    "set_tx",
104    "set_tx_params",
105    "status",
106    "timeout_steps",
107    "tx_power",
108    "tx_power_under_ceiling",
109    "write_buffer",
110    "write_register",
111]
112
113_CONSTANTS = _constants()
114
115#: The receive timeout word that keeps the chip listening until another command stops it.
116RX_CONTINUOUS = _CONSTANTS["RX_CONTINUOUS"]
117#: The LoRa sync word of a public network such as LoRaWAN.
118SYNC_WORD_PUBLIC = _CONSTANTS["SYNC_WORD_PUBLIC"]
119#: The LoRa sync word of a private network, and the chip's reset value.
120SYNC_WORD_PRIVATE = _CONSTANTS["SYNC_WORD_PRIVATE"]
121#: The register that holds the most significant byte of the LoRa sync word.
122REGISTER_LORA_SYNC_WORD = _CONSTANTS["REGISTER_LORA_SYNC_WORD"]
123
124
125class Amplifier(str, Enum):
126    """Which power amplifier a chip has.
127
128    The SPI interface cannot tell the chips apart, so the caller names the amplifier.
129    """
130
131    #: The low power amplifier of the SX1261, up to +15 dBm.
132    LOW_POWER = "LowPower"
133    #: The high power amplifier of the SX1262 and the LLCC68, up to +22 dBm.
134    HIGH_POWER = "HighPower"
135
136
137class Irq(IntFlag):
138    """The interrupt bits of the IRQ register, from Table 13-29 of the datasheet."""
139
140    #: A packet has been sent.
141    TX_DONE = _CONSTANTS["IRQ_TX_DONE"]
142    #: A packet has been received.
143    RX_DONE = _CONSTANTS["IRQ_RX_DONE"]
144    #: A preamble has been detected.
145    PREAMBLE_DETECTED = _CONSTANTS["IRQ_PREAMBLE_DETECTED"]
146    #: A valid (G)FSK sync word has been detected.
147    SYNC_WORD_VALID = _CONSTANTS["IRQ_SYNC_WORD_VALID"]
148    #: A valid LoRa header has been received.
149    HEADER_VALID = _CONSTANTS["IRQ_HEADER_VALID"]
150    #: A LoRa header failed its CRC.
151    HEADER_ERROR = _CONSTANTS["IRQ_HEADER_ERROR"]
152    #: A packet failed its CRC.
153    CRC_ERROR = _CONSTANTS["IRQ_CRC_ERROR"]
154    #: Channel activity detection has finished.
155    CAD_DONE = _CONSTANTS["IRQ_CAD_DONE"]
156    #: Channel activity detection heard LoRa.
157    CAD_DETECTED = _CONSTANTS["IRQ_CAD_DETECTED"]
158    #: A transmission or a reception timed out.
159    TIMEOUT = _CONSTANTS["IRQ_TIMEOUT"]
160    #: A long-range FHSS hop is due.
161    LR_FHSS_HOP = _CONSTANTS["IRQ_LR_FHSS_HOP"]
162
163
164class DeviceError(IntFlag):
165    """The device error bits GetDeviceErrors answers with."""
166
167    #: The RC64k oscillator failed to calibrate.
168    RC64K_CALIBRATION = _CONSTANTS["ERROR_RC64K_CALIBRATION"]
169    #: The RC13M oscillator failed to calibrate.
170    RC13M_CALIBRATION = _CONSTANTS["ERROR_RC13M_CALIBRATION"]
171    #: The PLL failed to calibrate.
172    PLL_CALIBRATION = _CONSTANTS["ERROR_PLL_CALIBRATION"]
173    #: The ADC failed to calibrate.
174    ADC_CALIBRATION = _CONSTANTS["ERROR_ADC_CALIBRATION"]
175    #: Image rejection failed to calibrate.
176    IMAGE_CALIBRATION = _CONSTANTS["ERROR_IMAGE_CALIBRATION"]
177    #: The crystal oscillator failed to start, which a TCXO raises until it is powered.
178    XOSC_START = _CONSTANTS["ERROR_XOSC_START"]
179    #: The PLL failed to lock.
180    PLL_LOCK = _CONSTANTS["ERROR_PLL_LOCK"]
181    #: The power amplifier failed to ramp.
182    PA_RAMP = _CONSTANTS["ERROR_PA_RAMP"]
183
184
185def frequency_word(frequency_hz: int) -> int:
186    """Return the word SetRfFrequency takes for a frequency.
187
188    :param frequency_hz: The carrier frequency in hertz.
189    :returns: The frequency times 2^25 over the 32 MHz crystal, rounded to the nearest step.
190
191    >>> hex(frequency_word(868_100_000))
192    '0x3641999a'
193    """
194    return _frequency_word(frequency_hz)
195
196
197def timeout_steps(timeout_us: int) -> int:
198    """Return the 24-bit timeout word SetTx and SetRx take for a duration.
199
200    :param timeout_us: The duration in microseconds.
201    :returns: The number of 15.625 us steps; a nonzero duration never becomes the zero word
202        that disables the timeout.
203
204    >>> timeout_steps(1_000_000)
205    64000
206    """
207    return _timeout_steps(timeout_us)
208
209
210def image_calibration(low_hz: int, high_hz: int) -> bytes:
211    """Return the two CalibrateImage codes that cover a band.
212
213    :param low_hz: The lower edge of the band in hertz.
214    :param high_hz: The upper edge of the band in hertz.
215    :returns: ``freq1`` and ``freq2``, 4 MHz steps that always cover the band.
216
217    >>> image_calibration(863_000_000, 870_000_000).hex()
218    'd7da'
219    """
220    return _image_calibration(low_hz, high_hz)
221
222
223def ramp_time_us(at_least_us: int) -> int:
224    """Return the shortest amplifier ramp time the chip offers that lasts at least a duration.
225
226    :param at_least_us: The least ramp time wanted, in microseconds.
227    :returns: One of the eight ramp times of Table 13-41, in microseconds.
228    """
229    return _ramp_time_us(at_least_us)
230
231
232def tx_power(amplifier: Amplifier | str, output_dbm: int) -> TxPower:
233    """Choose the amplifier settings for an output power.
234
235    :param amplifier: The chip's amplifier.
236    :param output_dbm: The output power wanted at the antenna port, in dBm.
237    :returns: The configuration and the setting, clamped to what the amplifier allows.
238    :raises ValueError: If no amplifier goes by that name.
239    """
240    return _tx_power(Amplifier(amplifier).value, output_dbm)
241
242
243def tx_power_under_ceiling(
244    amplifier: Amplifier | str, budget: LinkBudget, eirp_ceiling_dbm: float
245) -> TxPower:
246    """Choose the amplifier settings that keep a link's EIRP at or under a ceiling.
247
248    :param amplifier: The chip's amplifier.
249    :param budget: The link budget, whose transmitting antenna and cable apply.
250    :param eirp_ceiling_dbm: The EIRP limit, such as a channel plan's ceiling for the
251        frequency.
252    :returns: The configuration and the setting, rounded down to whole decibels so the EIRP
253        stays under the ceiling.
254    :raises ValueError: If no amplifier goes by that name.
255    """
256    return _tx_power_under_ceiling(Amplifier(amplifier).value, budget, eirp_ceiling_dbm)
257
258
259def set_standby() -> bytes:
260    """Return SetStandby into STDBY_RC, which stops a transmission or a reception."""
261    return _set_standby()
262
263
264def set_packet_type_lora() -> bytes:
265    """Return SetPacketType for LoRa, the first radio setting a configuration sends."""
266    return _set_packet_type_lora()
267
268
269def set_rf_frequency(frequency_hz: int) -> bytes:
270    """Return SetRfFrequency for a carrier frequency.
271
272    :param frequency_hz: The carrier frequency in hertz.
273    :returns: The command bytes.
274    """
275    return _set_rf_frequency(frequency_hz)
276
277
278def calibrate_image(low_hz: int, high_hz: int) -> bytes:
279    """Return CalibrateImage over a band.
280
281    :param low_hz: The lower edge of the band in hertz.
282    :param high_hz: The upper edge of the band in hertz.
283    :returns: The command bytes.
284    """
285    return _calibrate_image(low_hz, high_hz)
286
287
288def set_pa_config(power: TxPower) -> bytes:
289    """Return SetPaConfig for a power setting.
290
291    :param power: The settings from :func:`tx_power` or :func:`tx_power_under_ceiling`.
292    :returns: The command bytes.
293    """
294    return _set_pa_config(power)
295
296
297def set_tx_params(power: TxPower, ramp_us: int) -> bytes:
298    """Return SetTxParams for a power setting and a ramp time.
299
300    :param power: The power settings.
301    :param ramp_us: The least amplifier ramp time wanted, in microseconds.
302    :returns: The command bytes.
303    """
304    return _set_tx_params(power, ramp_us)
305
306
307def set_lora_modulation_params(link: LoraLink) -> bytes:
308    """Return SetModulationParams for a LoRa link.
309
310    :param link: The link settings, from :mod:`pamoja.lora`.
311    :returns: The command bytes.
312    :raises PamojaError: If the link's bandwidth is not one the SX126x offers.
313    """
314    return _set_lora_modulation_params(link)
315
316
317def set_lora_packet_params(link: LoraLink, payload_len: int, invert_iq: bool) -> bytes:
318    """Return SetPacketParams for a LoRa link and a payload.
319
320    :param link: The link settings, whose preamble, header, and CRC the frame uses.
321    :param payload_len: The payload length to send, or the most a receiver accepts.
322    :param invert_iq: Whether the IQ polarity is inverted, as LoRaWAN downlinks use.
323    :returns: The command bytes.
324    """
325    return _set_lora_packet_params(link, payload_len, invert_iq)
326
327
328def set_dio_irq_params(irq: int, dio1: int, dio2: int = 0, dio3: int = 0) -> bytes:
329    """Return SetDioIrqParams: which interrupts are enabled, and which DIO lines raise them.
330
331    :param irq: The interrupts to enable, as :class:`Irq` bits.
332    :param dio1: The interrupts routed to DIO1.
333    :param dio2: The interrupts routed to DIO2.
334    :param dio3: The interrupts routed to DIO3.
335    :returns: The command bytes.
336    """
337    return _set_dio_irq_params(int(irq), int(dio1), int(dio2), int(dio3))
338
339
340def clear_irq_status(irq: int) -> bytes:
341    """Return ClearIrqStatus for a set of interrupts.
342
343    :param irq: The interrupts to clear, as :class:`Irq` bits.
344    :returns: The command bytes.
345    """
346    return _clear_irq_status(int(irq))
347
348
349def set_tx(timeout_us: int) -> bytes:
350    """Return SetTx with a timeout.
351
352    :param timeout_us: How long the chip may transmit before it raises TIMEOUT, in
353        microseconds; ``0`` disables the timeout.
354    :returns: The command bytes.
355    """
356    return _set_tx(timeout_us)
357
358
359def set_rx(timeout_us: int) -> bytes:
360    """Return SetRx with a timeout.
361
362    :param timeout_us: How long the chip listens for a packet to start, in microseconds;
363        ``0`` listens for one packet with no timeout.
364    :returns: The command bytes.
365    """
366    return _set_rx(timeout_us)
367
368
369def set_rx_continuous() -> bytes:
370    """Return SetRx in continuous mode, receiving packet after packet until another command."""
371    return _set_rx_continuous()
372
373
374def set_sleep(warm_start: bool) -> bytes:
375    """Return SetSleep, without an RTC wake-up.
376
377    :param warm_start: Whether to keep the configuration in retention while asleep.
378    :returns: The command bytes.
379    """
380    return _set_sleep(warm_start)
381
382
383def write_register(address: int, values: bytes) -> bytes:
384    """Return a whole WriteRegister transaction.
385
386    :param address: The first register's address, such as :data:`REGISTER_LORA_SYNC_WORD`.
387    :param values: The register values, one byte each.
388    :returns: The opcode, the address, and the values.
389    """
390    return _write_register(address, bytes(values))
391
392
393def write_buffer(offset: int, payload: bytes) -> bytes:
394    """Return a whole WriteBuffer transaction.
395
396    :param offset: Where in the data buffer the first byte goes.
397    :param payload: The bytes to write.
398    :returns: The opcode, the offset, and the payload.
399    """
400    return _write_buffer(offset, bytes(payload))
401
402
403def get_status() -> Query:
404    """Return GetStatus, answered by the status byte; decode it with :func:`status`."""
405    return _get_status()
406
407
408def get_irq_status() -> Query:
409    """Return GetIrqStatus, answered by two IRQ bytes; decode them with :func:`irq`."""
410    return _get_irq_status()
411
412
413def get_rx_buffer_status() -> Query:
414    """Return GetRxBufferStatus, answered by two bytes; decode them with :func:`rx_buffer_status`."""
415    return _get_rx_buffer_status()
416
417
418def get_packet_status() -> Query:
419    """Return GetPacketStatus, answered by three bytes; decode them with :func:`packet_status`."""
420    return _get_packet_status()
421
422
423def get_rssi_inst() -> Query:
424    """Return GetRssiInst, answered by one byte; decode it with :func:`rssi_inst_dbm`."""
425    return _get_rssi_inst()
426
427
428def get_device_errors() -> Query:
429    """Return GetDeviceErrors, answered by two bytes; decode them with :func:`device_errors`."""
430    return _get_device_errors()
431
432
433def read_register(address: int, length: int) -> Query:
434    """Return ReadRegister for a run of consecutive registers.
435
436    :param address: The first register's address.
437    :param length: How many registers to read.
438    :returns: The query.
439    """
440    return _read_register(address, length)
441
442
443def read_buffer(offset: int, length: int) -> Query:
444    """Return ReadBuffer for a run of the data buffer.
445
446    :param offset: Where in the buffer the first byte is.
447    :param length: How many bytes to read.
448    :returns: The query.
449    """
450    return _read_buffer(offset, length)
451
452
453def status(byte: int) -> Status:
454    """Decode a status byte.
455
456    :param byte: The status byte.
457    :returns: The chip's mode, how its last command went, and whether that was an error.
458
459    >>> status(0x2C).chip_mode
460    'StandbyRc'
461    """
462    return _status(byte)
463
464
465def irq(answer: bytes) -> Irq:
466    """Decode a GetIrqStatus answer.
467
468    :param answer: The two answer bytes.
469    :returns: The pending interrupts.
470    :raises ValueError: If the answer is not two bytes.
471    """
472    return Irq(_irq(bytes(answer)))
473
474
475def device_errors(answer: bytes) -> DeviceError:
476    """Decode a GetDeviceErrors answer.
477
478    :param answer: The two answer bytes.
479    :returns: The flagged errors.
480    :raises ValueError: If the answer is not two bytes.
481    """
482    return DeviceError(_device_errors(bytes(answer)))
483
484
485def packet_status(answer: bytes) -> PacketStatus:
486    """Decode a LoRa GetPacketStatus answer.
487
488    :param answer: RssiPkt, SnrPkt, and SignalRssiPkt.
489    :returns: The three signal levels, exact to a hundredth of a decibel.
490    :raises ValueError: If the answer is not three bytes.
491    """
492    return _packet_status(bytes(answer))
493
494
495def rx_buffer_status(answer: bytes) -> RxBufferStatus:
496    """Decode a GetRxBufferStatus answer.
497
498    :param answer: PayloadLengthRx and RxStartBufferPointer.
499    :returns: The payload length and where it starts in the data buffer.
500    :raises ValueError: If the answer is not two bytes.
501    """
502    return _rx_buffer_status(bytes(answer))
503
504
505def rssi_inst_dbm(byte: int) -> float:
506    """Decode a GetRssiInst answer.
507
508    :param byte: RssiInst.
509    :returns: The signal power the receiver hears right now, in dBm.
510    """
511    return _rssi_inst_dbm(byte)
512
513
514def llcc68_supports(link: LoraLink) -> bool:
515    """Report whether an LLCC68 supports a link's spreading factor at its bandwidth.
516
517    The LLCC68 takes the SX1262's commands but not all its settings: up to SF9 at 125 kHz,
518    SF10 at 250 kHz, and SF11 at 500 kHz, and no bandwidth below 125 kHz.
519
520    :param link: The link settings.
521    :returns: ``True`` when an LLCC68 can use the link.
522    """
523    return _llcc68_supports(link)
REGISTER_LORA_SYNC_WORD = 1856
RX_CONTINUOUS = 16777215
SYNC_WORD_PRIVATE = 5156
SYNC_WORD_PUBLIC = 13380
class Amplifier(builtins.str, enum.Enum):
126class Amplifier(str, Enum):
127    """Which power amplifier a chip has.
128
129    The SPI interface cannot tell the chips apart, so the caller names the amplifier.
130    """
131
132    #: The low power amplifier of the SX1261, up to +15 dBm.
133    LOW_POWER = "LowPower"
134    #: The high power amplifier of the SX1262 and the LLCC68, up to +22 dBm.
135    HIGH_POWER = "HighPower"

Which power amplifier a chip has.

The SPI interface cannot tell the chips apart, so the caller names the amplifier.

LOW_POWER = <Amplifier.LOW_POWER: 'LowPower'>
HIGH_POWER = <Amplifier.HIGH_POWER: 'HighPower'>
class DeviceError(enum.IntFlag):
165class DeviceError(IntFlag):
166    """The device error bits GetDeviceErrors answers with."""
167
168    #: The RC64k oscillator failed to calibrate.
169    RC64K_CALIBRATION = _CONSTANTS["ERROR_RC64K_CALIBRATION"]
170    #: The RC13M oscillator failed to calibrate.
171    RC13M_CALIBRATION = _CONSTANTS["ERROR_RC13M_CALIBRATION"]
172    #: The PLL failed to calibrate.
173    PLL_CALIBRATION = _CONSTANTS["ERROR_PLL_CALIBRATION"]
174    #: The ADC failed to calibrate.
175    ADC_CALIBRATION = _CONSTANTS["ERROR_ADC_CALIBRATION"]
176    #: Image rejection failed to calibrate.
177    IMAGE_CALIBRATION = _CONSTANTS["ERROR_IMAGE_CALIBRATION"]
178    #: The crystal oscillator failed to start, which a TCXO raises until it is powered.
179    XOSC_START = _CONSTANTS["ERROR_XOSC_START"]
180    #: The PLL failed to lock.
181    PLL_LOCK = _CONSTANTS["ERROR_PLL_LOCK"]
182    #: The power amplifier failed to ramp.
183    PA_RAMP = _CONSTANTS["ERROR_PA_RAMP"]

The device error bits GetDeviceErrors answers with.

RC64K_CALIBRATION = <DeviceError.RC64K_CALIBRATION: 1>
RC13M_CALIBRATION = <DeviceError.RC13M_CALIBRATION: 2>
PLL_CALIBRATION = <DeviceError.PLL_CALIBRATION: 4>
ADC_CALIBRATION = <DeviceError.ADC_CALIBRATION: 8>
IMAGE_CALIBRATION = <DeviceError.IMAGE_CALIBRATION: 16>
XOSC_START = <DeviceError.XOSC_START: 32>
PLL_LOCK = <DeviceError.PLL_LOCK: 64>
PA_RAMP = <DeviceError.PA_RAMP: 256>
class Irq(enum.IntFlag):
138class Irq(IntFlag):
139    """The interrupt bits of the IRQ register, from Table 13-29 of the datasheet."""
140
141    #: A packet has been sent.
142    TX_DONE = _CONSTANTS["IRQ_TX_DONE"]
143    #: A packet has been received.
144    RX_DONE = _CONSTANTS["IRQ_RX_DONE"]
145    #: A preamble has been detected.
146    PREAMBLE_DETECTED = _CONSTANTS["IRQ_PREAMBLE_DETECTED"]
147    #: A valid (G)FSK sync word has been detected.
148    SYNC_WORD_VALID = _CONSTANTS["IRQ_SYNC_WORD_VALID"]
149    #: A valid LoRa header has been received.
150    HEADER_VALID = _CONSTANTS["IRQ_HEADER_VALID"]
151    #: A LoRa header failed its CRC.
152    HEADER_ERROR = _CONSTANTS["IRQ_HEADER_ERROR"]
153    #: A packet failed its CRC.
154    CRC_ERROR = _CONSTANTS["IRQ_CRC_ERROR"]
155    #: Channel activity detection has finished.
156    CAD_DONE = _CONSTANTS["IRQ_CAD_DONE"]
157    #: Channel activity detection heard LoRa.
158    CAD_DETECTED = _CONSTANTS["IRQ_CAD_DETECTED"]
159    #: A transmission or a reception timed out.
160    TIMEOUT = _CONSTANTS["IRQ_TIMEOUT"]
161    #: A long-range FHSS hop is due.
162    LR_FHSS_HOP = _CONSTANTS["IRQ_LR_FHSS_HOP"]

The interrupt bits of the IRQ register, from Table 13-29 of the datasheet.

TX_DONE = <Irq.TX_DONE: 1>
RX_DONE = <Irq.RX_DONE: 2>
PREAMBLE_DETECTED = <Irq.PREAMBLE_DETECTED: 4>
SYNC_WORD_VALID = <Irq.SYNC_WORD_VALID: 8>
HEADER_VALID = <Irq.HEADER_VALID: 16>
HEADER_ERROR = <Irq.HEADER_ERROR: 32>
CRC_ERROR = <Irq.CRC_ERROR: 64>
CAD_DONE = <Irq.CAD_DONE: 128>
CAD_DETECTED = <Irq.CAD_DETECTED: 256>
TIMEOUT = <Irq.TIMEOUT: 512>
LR_FHSS_HOP = <Irq.LR_FHSS_HOP: 16384>
PacketStatus = <class 'builtins.Sx126xPacketStatus'>
Query = <class 'builtins.Sx126xQuery'>
RxBufferStatus = <class 'builtins.Sx126xRxBufferStatus'>
Status = <class 'builtins.Sx126xStatus'>
TxPower = <class 'builtins.Sx126xTxPower'>
def calibrate_image(low_hz: int, high_hz: int) -> bytes:
279def calibrate_image(low_hz: int, high_hz: int) -> bytes:
280    """Return CalibrateImage over a band.
281
282    :param low_hz: The lower edge of the band in hertz.
283    :param high_hz: The upper edge of the band in hertz.
284    :returns: The command bytes.
285    """
286    return _calibrate_image(low_hz, high_hz)

Return CalibrateImage over a band.

Parameters
  • low_hz: The lower edge of the band in hertz.
  • high_hz: The upper edge of the band in hertz. :returns: The command bytes.
def clear_irq_status(irq: int) -> bytes:
341def clear_irq_status(irq: int) -> bytes:
342    """Return ClearIrqStatus for a set of interrupts.
343
344    :param irq: The interrupts to clear, as :class:`Irq` bits.
345    :returns: The command bytes.
346    """
347    return _clear_irq_status(int(irq))

Return ClearIrqStatus for a set of interrupts.

Parameters
  • irq: The interrupts to clear, as Irq bits. :returns: The command bytes.
def device_errors(answer: bytes) -> DeviceError:
476def device_errors(answer: bytes) -> DeviceError:
477    """Decode a GetDeviceErrors answer.
478
479    :param answer: The two answer bytes.
480    :returns: The flagged errors.
481    :raises ValueError: If the answer is not two bytes.
482    """
483    return DeviceError(_device_errors(bytes(answer)))

Decode a GetDeviceErrors answer.

Parameters
  • answer: The two answer bytes. :returns: The flagged errors.
Raises
  • ValueError: If the answer is not two bytes.
def frequency_word(frequency_hz: int) -> int:
186def frequency_word(frequency_hz: int) -> int:
187    """Return the word SetRfFrequency takes for a frequency.
188
189    :param frequency_hz: The carrier frequency in hertz.
190    :returns: The frequency times 2^25 over the 32 MHz crystal, rounded to the nearest step.
191
192    >>> hex(frequency_word(868_100_000))
193    '0x3641999a'
194    """
195    return _frequency_word(frequency_hz)

Return the word SetRfFrequency takes for a frequency.

Parameters
  • frequency_hz: The carrier frequency in hertz. :returns: The frequency times 2^25 over the 32 MHz crystal, rounded to the nearest step.
>>> hex(frequency_word(868_100_000))
'0x3641999a'
def get_device_errors() -> Sx126xQuery:
429def get_device_errors() -> Query:
430    """Return GetDeviceErrors, answered by two bytes; decode them with :func:`device_errors`."""
431    return _get_device_errors()

Return GetDeviceErrors, answered by two bytes; decode them with device_errors().

def get_irq_status() -> Sx126xQuery:
409def get_irq_status() -> Query:
410    """Return GetIrqStatus, answered by two IRQ bytes; decode them with :func:`irq`."""
411    return _get_irq_status()

Return GetIrqStatus, answered by two IRQ bytes; decode them with irq().

def get_packet_status() -> Sx126xQuery:
419def get_packet_status() -> Query:
420    """Return GetPacketStatus, answered by three bytes; decode them with :func:`packet_status`."""
421    return _get_packet_status()

Return GetPacketStatus, answered by three bytes; decode them with packet_status().

def get_rssi_inst() -> Sx126xQuery:
424def get_rssi_inst() -> Query:
425    """Return GetRssiInst, answered by one byte; decode it with :func:`rssi_inst_dbm`."""
426    return _get_rssi_inst()

Return GetRssiInst, answered by one byte; decode it with rssi_inst_dbm().

def get_rx_buffer_status() -> Sx126xQuery:
414def get_rx_buffer_status() -> Query:
415    """Return GetRxBufferStatus, answered by two bytes; decode them with :func:`rx_buffer_status`."""
416    return _get_rx_buffer_status()

Return GetRxBufferStatus, answered by two bytes; decode them with rx_buffer_status().

def get_status() -> Sx126xQuery:
404def get_status() -> Query:
405    """Return GetStatus, answered by the status byte; decode it with :func:`status`."""
406    return _get_status()

Return GetStatus, answered by the status byte; decode it with status().

def image_calibration(low_hz: int, high_hz: int) -> bytes:
211def image_calibration(low_hz: int, high_hz: int) -> bytes:
212    """Return the two CalibrateImage codes that cover a band.
213
214    :param low_hz: The lower edge of the band in hertz.
215    :param high_hz: The upper edge of the band in hertz.
216    :returns: ``freq1`` and ``freq2``, 4 MHz steps that always cover the band.
217
218    >>> image_calibration(863_000_000, 870_000_000).hex()
219    'd7da'
220    """
221    return _image_calibration(low_hz, high_hz)

Return the two CalibrateImage codes that cover a band.

Parameters
  • low_hz: The lower edge of the band in hertz.
  • high_hz: The upper edge of the band in hertz. :returns: freq1 and freq2, 4 MHz steps that always cover the band.
>>> image_calibration(863_000_000, 870_000_000).hex()
'd7da'
def irq(answer: bytes) -> Irq:
466def irq(answer: bytes) -> Irq:
467    """Decode a GetIrqStatus answer.
468
469    :param answer: The two answer bytes.
470    :returns: The pending interrupts.
471    :raises ValueError: If the answer is not two bytes.
472    """
473    return Irq(_irq(bytes(answer)))

Decode a GetIrqStatus answer.

Parameters
  • answer: The two answer bytes. :returns: The pending interrupts.
Raises
  • ValueError: If the answer is not two bytes.
def llcc68_supports(link: LoraLink) -> bool:
515def llcc68_supports(link: LoraLink) -> bool:
516    """Report whether an LLCC68 supports a link's spreading factor at its bandwidth.
517
518    The LLCC68 takes the SX1262's commands but not all its settings: up to SF9 at 125 kHz,
519    SF10 at 250 kHz, and SF11 at 500 kHz, and no bandwidth below 125 kHz.
520
521    :param link: The link settings.
522    :returns: ``True`` when an LLCC68 can use the link.
523    """
524    return _llcc68_supports(link)

Report whether an LLCC68 supports a link's spreading factor at its bandwidth.

The LLCC68 takes the SX1262's commands but not all its settings: up to SF9 at 125 kHz, SF10 at 250 kHz, and SF11 at 500 kHz, and no bandwidth below 125 kHz.

Parameters
  • link: The link settings. :returns: True when an LLCC68 can use the link.
def packet_status(answer: bytes) -> Sx126xPacketStatus:
486def packet_status(answer: bytes) -> PacketStatus:
487    """Decode a LoRa GetPacketStatus answer.
488
489    :param answer: RssiPkt, SnrPkt, and SignalRssiPkt.
490    :returns: The three signal levels, exact to a hundredth of a decibel.
491    :raises ValueError: If the answer is not three bytes.
492    """
493    return _packet_status(bytes(answer))

Decode a LoRa GetPacketStatus answer.

Parameters
  • answer: RssiPkt, SnrPkt, and SignalRssiPkt. :returns: The three signal levels, exact to a hundredth of a decibel.
Raises
  • ValueError: If the answer is not three bytes.
def ramp_time_us(at_least_us: int) -> int:
224def ramp_time_us(at_least_us: int) -> int:
225    """Return the shortest amplifier ramp time the chip offers that lasts at least a duration.
226
227    :param at_least_us: The least ramp time wanted, in microseconds.
228    :returns: One of the eight ramp times of Table 13-41, in microseconds.
229    """
230    return _ramp_time_us(at_least_us)

Return the shortest amplifier ramp time the chip offers that lasts at least a duration.

Parameters
  • at_least_us: The least ramp time wanted, in microseconds. :returns: One of the eight ramp times of Table 13-41, in microseconds.
def read_buffer(offset: int, length: int) -> Sx126xQuery:
444def read_buffer(offset: int, length: int) -> Query:
445    """Return ReadBuffer for a run of the data buffer.
446
447    :param offset: Where in the buffer the first byte is.
448    :param length: How many bytes to read.
449    :returns: The query.
450    """
451    return _read_buffer(offset, length)

Return ReadBuffer for a run of the data buffer.

Parameters
  • offset: Where in the buffer the first byte is.
  • length: How many bytes to read. :returns: The query.
def read_register(address: int, length: int) -> Sx126xQuery:
434def read_register(address: int, length: int) -> Query:
435    """Return ReadRegister for a run of consecutive registers.
436
437    :param address: The first register's address.
438    :param length: How many registers to read.
439    :returns: The query.
440    """
441    return _read_register(address, length)

Return ReadRegister for a run of consecutive registers.

Parameters
  • address: The first register's address.
  • length: How many registers to read. :returns: The query.
def rssi_inst_dbm(byte: int) -> float:
506def rssi_inst_dbm(byte: int) -> float:
507    """Decode a GetRssiInst answer.
508
509    :param byte: RssiInst.
510    :returns: The signal power the receiver hears right now, in dBm.
511    """
512    return _rssi_inst_dbm(byte)

Decode a GetRssiInst answer.

Parameters
  • byte: RssiInst. :returns: The signal power the receiver hears right now, in dBm.
def rx_buffer_status(answer: bytes) -> Sx126xRxBufferStatus:
496def rx_buffer_status(answer: bytes) -> RxBufferStatus:
497    """Decode a GetRxBufferStatus answer.
498
499    :param answer: PayloadLengthRx and RxStartBufferPointer.
500    :returns: The payload length and where it starts in the data buffer.
501    :raises ValueError: If the answer is not two bytes.
502    """
503    return _rx_buffer_status(bytes(answer))

Decode a GetRxBufferStatus answer.

Parameters
  • answer: PayloadLengthRx and RxStartBufferPointer. :returns: The payload length and where it starts in the data buffer.
Raises
  • ValueError: If the answer is not two bytes.
def set_dio_irq_params(irq: int, dio1: int, dio2: int = 0, dio3: int = 0) -> bytes:
329def set_dio_irq_params(irq: int, dio1: int, dio2: int = 0, dio3: int = 0) -> bytes:
330    """Return SetDioIrqParams: which interrupts are enabled, and which DIO lines raise them.
331
332    :param irq: The interrupts to enable, as :class:`Irq` bits.
333    :param dio1: The interrupts routed to DIO1.
334    :param dio2: The interrupts routed to DIO2.
335    :param dio3: The interrupts routed to DIO3.
336    :returns: The command bytes.
337    """
338    return _set_dio_irq_params(int(irq), int(dio1), int(dio2), int(dio3))

Return SetDioIrqParams: which interrupts are enabled, and which DIO lines raise them.

Parameters
  • irq: The interrupts to enable, as Irq bits.
  • dio1: The interrupts routed to DIO1.
  • dio2: The interrupts routed to DIO2.
  • dio3: The interrupts routed to DIO3. :returns: The command bytes.
def set_lora_modulation_params(link: LoraLink) -> bytes:
308def set_lora_modulation_params(link: LoraLink) -> bytes:
309    """Return SetModulationParams for a LoRa link.
310
311    :param link: The link settings, from :mod:`pamoja.lora`.
312    :returns: The command bytes.
313    :raises PamojaError: If the link's bandwidth is not one the SX126x offers.
314    """
315    return _set_lora_modulation_params(link)

Return SetModulationParams for a LoRa link.

Parameters
  • link: The link settings, from pamoja.lora. :returns: The command bytes.
Raises
  • PamojaError: If the link's bandwidth is not one the SX126x offers.
def set_lora_packet_params(link: LoraLink, payload_len: int, invert_iq: bool) -> bytes:
318def set_lora_packet_params(link: LoraLink, payload_len: int, invert_iq: bool) -> bytes:
319    """Return SetPacketParams for a LoRa link and a payload.
320
321    :param link: The link settings, whose preamble, header, and CRC the frame uses.
322    :param payload_len: The payload length to send, or the most a receiver accepts.
323    :param invert_iq: Whether the IQ polarity is inverted, as LoRaWAN downlinks use.
324    :returns: The command bytes.
325    """
326    return _set_lora_packet_params(link, payload_len, invert_iq)

Return SetPacketParams for a LoRa link and a payload.

Parameters
  • link: The link settings, whose preamble, header, and CRC the frame uses.
  • payload_len: The payload length to send, or the most a receiver accepts.
  • invert_iq: Whether the IQ polarity is inverted, as LoRaWAN downlinks use. :returns: The command bytes.
def set_pa_config(power: Sx126xTxPower) -> bytes:
289def set_pa_config(power: TxPower) -> bytes:
290    """Return SetPaConfig for a power setting.
291
292    :param power: The settings from :func:`tx_power` or :func:`tx_power_under_ceiling`.
293    :returns: The command bytes.
294    """
295    return _set_pa_config(power)

Return SetPaConfig for a power setting.

Parameters
def set_packet_type_lora() -> bytes:
265def set_packet_type_lora() -> bytes:
266    """Return SetPacketType for LoRa, the first radio setting a configuration sends."""
267    return _set_packet_type_lora()

Return SetPacketType for LoRa, the first radio setting a configuration sends.

def set_rf_frequency(frequency_hz: int) -> bytes:
270def set_rf_frequency(frequency_hz: int) -> bytes:
271    """Return SetRfFrequency for a carrier frequency.
272
273    :param frequency_hz: The carrier frequency in hertz.
274    :returns: The command bytes.
275    """
276    return _set_rf_frequency(frequency_hz)

Return SetRfFrequency for a carrier frequency.

Parameters
  • frequency_hz: The carrier frequency in hertz. :returns: The command bytes.
def set_rx(timeout_us: int) -> bytes:
360def set_rx(timeout_us: int) -> bytes:
361    """Return SetRx with a timeout.
362
363    :param timeout_us: How long the chip listens for a packet to start, in microseconds;
364        ``0`` listens for one packet with no timeout.
365    :returns: The command bytes.
366    """
367    return _set_rx(timeout_us)

Return SetRx with a timeout.

Parameters
  • timeout_us: How long the chip listens for a packet to start, in microseconds; 0 listens for one packet with no timeout. :returns: The command bytes.
def set_rx_continuous() -> bytes:
370def set_rx_continuous() -> bytes:
371    """Return SetRx in continuous mode, receiving packet after packet until another command."""
372    return _set_rx_continuous()

Return SetRx in continuous mode, receiving packet after packet until another command.

def set_sleep(warm_start: bool) -> bytes:
375def set_sleep(warm_start: bool) -> bytes:
376    """Return SetSleep, without an RTC wake-up.
377
378    :param warm_start: Whether to keep the configuration in retention while asleep.
379    :returns: The command bytes.
380    """
381    return _set_sleep(warm_start)

Return SetSleep, without an RTC wake-up.

Parameters
  • warm_start: Whether to keep the configuration in retention while asleep. :returns: The command bytes.
def set_standby() -> bytes:
260def set_standby() -> bytes:
261    """Return SetStandby into STDBY_RC, which stops a transmission or a reception."""
262    return _set_standby()

Return SetStandby into STDBY_RC, which stops a transmission or a reception.

def set_tx(timeout_us: int) -> bytes:
350def set_tx(timeout_us: int) -> bytes:
351    """Return SetTx with a timeout.
352
353    :param timeout_us: How long the chip may transmit before it raises TIMEOUT, in
354        microseconds; ``0`` disables the timeout.
355    :returns: The command bytes.
356    """
357    return _set_tx(timeout_us)

Return SetTx with a timeout.

Parameters
  • timeout_us: How long the chip may transmit before it raises TIMEOUT, in microseconds; 0 disables the timeout. :returns: The command bytes.
def set_tx_params(power: Sx126xTxPower, ramp_us: int) -> bytes:
298def set_tx_params(power: TxPower, ramp_us: int) -> bytes:
299    """Return SetTxParams for a power setting and a ramp time.
300
301    :param power: The power settings.
302    :param ramp_us: The least amplifier ramp time wanted, in microseconds.
303    :returns: The command bytes.
304    """
305    return _set_tx_params(power, ramp_us)

Return SetTxParams for a power setting and a ramp time.

Parameters
  • power: The power settings.
  • ramp_us: The least amplifier ramp time wanted, in microseconds. :returns: The command bytes.
def status(byte: int) -> Sx126xStatus:
454def status(byte: int) -> Status:
455    """Decode a status byte.
456
457    :param byte: The status byte.
458    :returns: The chip's mode, how its last command went, and whether that was an error.
459
460    >>> status(0x2C).chip_mode
461    'StandbyRc'
462    """
463    return _status(byte)

Decode a status byte.

Parameters
  • byte: The status byte. :returns: The chip's mode, how its last command went, and whether that was an error.
>>> status(0x2C).chip_mode
'StandbyRc'
def timeout_steps(timeout_us: int) -> int:
198def timeout_steps(timeout_us: int) -> int:
199    """Return the 24-bit timeout word SetTx and SetRx take for a duration.
200
201    :param timeout_us: The duration in microseconds.
202    :returns: The number of 15.625 us steps; a nonzero duration never becomes the zero word
203        that disables the timeout.
204
205    >>> timeout_steps(1_000_000)
206    64000
207    """
208    return _timeout_steps(timeout_us)

Return the 24-bit timeout word SetTx and SetRx take for a duration.

Parameters
  • timeout_us: The duration in microseconds. :returns: The number of 15.625 us steps; a nonzero duration never becomes the zero word that disables the timeout.
>>> timeout_steps(1_000_000)
64000
def tx_power( amplifier: Amplifier | str, output_dbm: int) -> Sx126xTxPower:
233def tx_power(amplifier: Amplifier | str, output_dbm: int) -> TxPower:
234    """Choose the amplifier settings for an output power.
235
236    :param amplifier: The chip's amplifier.
237    :param output_dbm: The output power wanted at the antenna port, in dBm.
238    :returns: The configuration and the setting, clamped to what the amplifier allows.
239    :raises ValueError: If no amplifier goes by that name.
240    """
241    return _tx_power(Amplifier(amplifier).value, output_dbm)

Choose the amplifier settings for an output power.

Parameters
  • amplifier: The chip's amplifier.
  • output_dbm: The output power wanted at the antenna port, in dBm. :returns: The configuration and the setting, clamped to what the amplifier allows.
Raises
  • ValueError: If no amplifier goes by that name.
def tx_power_under_ceiling( amplifier: Amplifier | str, budget: LinkBudget, eirp_ceiling_dbm: float) -> Sx126xTxPower:
244def tx_power_under_ceiling(
245    amplifier: Amplifier | str, budget: LinkBudget, eirp_ceiling_dbm: float
246) -> TxPower:
247    """Choose the amplifier settings that keep a link's EIRP at or under a ceiling.
248
249    :param amplifier: The chip's amplifier.
250    :param budget: The link budget, whose transmitting antenna and cable apply.
251    :param eirp_ceiling_dbm: The EIRP limit, such as a channel plan's ceiling for the
252        frequency.
253    :returns: The configuration and the setting, rounded down to whole decibels so the EIRP
254        stays under the ceiling.
255    :raises ValueError: If no amplifier goes by that name.
256    """
257    return _tx_power_under_ceiling(Amplifier(amplifier).value, budget, eirp_ceiling_dbm)

Choose the amplifier settings that keep a link's EIRP at or under a ceiling.

Parameters
  • amplifier: The chip's amplifier.
  • budget: The link budget, whose transmitting antenna and cable apply.
  • eirp_ceiling_dbm: The EIRP limit, such as a channel plan's ceiling for the frequency. :returns: The configuration and the setting, rounded down to whole decibels so the EIRP stays under the ceiling.
Raises
  • ValueError: If no amplifier goes by that name.
def write_buffer(offset: int, payload: bytes) -> bytes:
394def write_buffer(offset: int, payload: bytes) -> bytes:
395    """Return a whole WriteBuffer transaction.
396
397    :param offset: Where in the data buffer the first byte goes.
398    :param payload: The bytes to write.
399    :returns: The opcode, the offset, and the payload.
400    """
401    return _write_buffer(offset, bytes(payload))

Return a whole WriteBuffer transaction.

Parameters
  • offset: Where in the data buffer the first byte goes.
  • payload: The bytes to write. :returns: The opcode, the offset, and the payload.
def write_register(address: int, values: bytes) -> bytes:
384def write_register(address: int, values: bytes) -> bytes:
385    """Return a whole WriteRegister transaction.
386
387    :param address: The first register's address, such as :data:`REGISTER_LORA_SYNC_WORD`.
388    :param values: The register values, one byte each.
389    :returns: The opcode, the address, and the values.
390    """
391    return _write_register(address, bytes(values))

Return a whole WriteRegister transaction.

Parameters
  • address: The first register's address, such as REGISTER_LORA_SYNC_WORD.
  • values: The register values, one byte each. :returns: The opcode, the address, and the values.