'''
This module provides the :class:`whad.phy.connector.lora.LoRa` connector that wraps PHY's
default :class:`whad.phy.connector.Phy` connector and make it easier to receive
and send LoRa packets.
'''
from whad.device import WhadDevice
from whad.exceptions import UnsupportedCapability
from whad.phy.connector import Phy
from whad.phy.exceptions import InvalidParameter
[docs]
class LoRa(Phy):
'''LoRa modulation/demodulation connector.
'''
SYNCWORD_M2M = b'\x12'
SYNCWORD_LORAWAN = b'\x34'
domain = "lora"
def __init__(self, device: WhadDevice = None):
'''Initialization
'''
# Initialize our underlying Phy connector.
super().__init__(device)
# Make sure LoRa is supported by the device
if not self.can_use_lora():
raise UnsupportedCapability('SetLoRaModulation')
# Set LoRa default parameters
self.__spreading_factor = 7 # SF7
self.__coding_rate = 45 # Coding rate 4/5
self.__bandwidth = 125000 # 125 kHz
self.__preamble_length = 12 # Preamble length (in symbols)
self.__crc_enabled = False # CRC disabled by default
self.__explicit_mode = False # Explicit mode is disabled by default
self.__invert_iq = False # Invert IQ is disabled by default
self.__syncword = LoRa.SYNCWORD_M2M # LoRa M2M by default
##
# Getters for LoRa modulation parameters
##
@property
def sf(self):
'''Current spreading factor.
'''
return self.__spreading_factor
@sf.setter
def sf(self, value: int):
'''Spreading factor setter.
'''
if value in range(7, 13):
self.__spreading_factor = value
else:
raise InvalidParameter('sf')
@property
def cr(self):
'''Current coding rate.
'''
return self.__coding_rate
@cr.setter
def cr(self, value: int):
'''Coding rate setter.
'''
if value in range(45, 49):
self.__coding_rate = value
else:
raise InvalidParameter('cr')
@property
def bw(self):
'''Current bandwidth.
'''
return self.__bandwidth
@bw.setter
def bw(self, value: int):
'''Bandwidth setter.
'''
if value in [62500, 125000, 250000, 500000]:
self.__bandwidth = value
else:
raise InvalidParameter('bw')
@property
def preamble_length(self):
'''Current preamble size (in symbols).
'''
return self.__preamble_length
@preamble_length.setter
def preamble_length(self, value: int):
'''Preamble length setter.
'''
if value in range(0, 65536):
self.__preamble_length = value
else:
raise InvalidParameter('preamble')
@property
def crc_enabled(self):
'''Current CRC configuration.
'''
return self.__crc_enabled
[docs]
def enable_crc(self, enabled: bool):
'''Enable or disable CRC.
'''
self.__crc_enabled = enabled
@property
def explicit_mode(self):
'''Current packet type (check if Explicit mode is set)
'''
return self.__explicit_mode
[docs]
def enable_explicit_mode(self, enabled: bool):
'''Enable or disable explicit mode (variable packet length).
'''
self.__explicit_mode = enabled
@property
def invert_iq(self):
"""Current IQ inversion setting
"""
return self.__invert_iq
@invert_iq.setter
def invert_iq(self, enabled : bool):
"""Set IQ inversion.
"""
self.__invert_iq = enabled
@property
def syncword(self):
'''Current configured synchronization word.
'''
return self.__syncword
@syncword.setter
def syncword(self, syncword: bytes):
'''Set synchronization word.
:param syncword: new synchronization word
:type syncword: bytes
'''
self.__syncword = syncword
##
# LoRa start/stop
##
[docs]
def start(self):
'''Start device in LoRa mode (continuous RX)
'''
# Configure the device for LoRa modulation
self.set_lora(
self.__spreading_factor,
self.__coding_rate,
self.__bandwidth,
self.__preamble_length,
self.__crc_enabled,
self.__explicit_mode,
self.__invert_iq
)
# Set syncword
self.set_sync_word(self.__syncword)
# Start RX
super().start()