diff --git a/docs/archive b/docs/archive index 6e45b9a2f..26e821e7d 160000 --- a/docs/archive +++ b/docs/archive @@ -1 +1 @@ -Subproject commit 6e45b9a2f57b59e663b39b8a14582bc8a310b55b +Subproject commit 26e821e7d022c043c0af9c5ab9616afa2078e194 diff --git a/software/glasgow/applet/radio/sx1276/__init__.py b/software/glasgow/applet/radio/sx1276/__init__.py new file mode 100644 index 000000000..60319b2ef --- /dev/null +++ b/software/glasgow/applet/radio/sx1276/__init__.py @@ -0,0 +1,141 @@ +# Ref: SX1276/77/78/79 - 137 MHz to 1020 MHz Low Power Long Range Transceiver Datasheet +# Ref: https://www.semtech.com/products/wireless-rf/lora-connect/sx1276#documentation +# Accession: G00086 + +import math +import asyncio +import logging +from amaranth import * + +from ....support.logging import * +from ....arch.sx1276 import * +from ...interface.spi_controller import SPIControllerSubtarget, SPIControllerInterface +from ... import * + + +class RadioSX1276Error(GlasgowAppletError): + pass + + +class RadioSX1276Subtarget(Elaboratable): + def __init__(self, spi_subtarget, reset_t, dut_reset): + self.spi_subtarget = spi_subtarget + self.reset_t = reset_t + self.dut_reset = dut_reset + + def elaborate(self, platform): + m = Module() + + m.submodules.spi_subtarget = self.spi_subtarget + + m.d.comb += [ + self.reset_t.o.eq(~self.dut_reset), + self.reset_t.oe.eq(1), + ] + + return m + + +class RadioSX1276Interface: + def __init__(self, interface, logger, device, addr_dut_reset): + self.lower = interface + self._logger = logger + self._level = logging.DEBUG if self._logger.name == __name__ else logging.TRACE + self._device = device + self._addr_dut_reset = addr_dut_reset + + def _log(self, message, *args) -> None: + self._logger.log(self._level, "SX1276: " + message, *args) + + async def _set_reset(self, reset) -> None: + await self._device.write_register(self._addr_dut_reset, int(reset)) + + async def reset(self) -> None: + self._log("reset") + await self.lower.synchronize() + await self._set_reset(True) + await self.lower.delay_us(100) # TODO: reference DS + await self.lower.synchronize() + await self._set_reset(False) + await self.lower.delay_us(500) # TODO: reference DS + await self.lower.synchronize() + + async def read_register(self, address: int, *, length=1) -> int: + assert address in range(0x7f) and length >= 1 + await self.lower.write([(0<<7)|address], hold_ss=True) + value = int.from_bytes(await self.lower.read(length), byteorder="big") + self._log("read register [%02x]=<%.*x>", address, length * 2, value) + return value + + async def write_register(self, address: int, value: int, *, length=1) -> None: + assert address in range(0x7f) and isinstance(value, int) and length >= 1 + self._log("write register [%02x]=<%.*x>", address, length * 2, value) + await self.lower.write([(1<<7)|address, *value.to_bytes(length)]) + + async def identify(self): + version = await self.read_register(Addr.RegVersion) + self._log("version=%02x", version) + if version != Version.ProductionRevision: + raise RadioSX1276Error(f"incorrect version {version:#x} returned by device") + return version + + +class RadioSX1276Applet(GlasgowApplet): + logger = logging.getLogger(__name__) + help = "transmit and receive using SX1276/7/8/9 RF PHYs" + description = """ + Transmit and receive packets using the SX1276/7/8/9 RF PHYs. SX1276 is the base device, while + SX1277/8/9 are the lower cost, reduced functionality, interface compatible versions of the same. + + [TODO: expand] + """ + + __pins = ("cs", "sck", "copi", "cipo", "reset", "dio0") + + @classmethod + def add_build_arguments(cls, parser, access): + access.add_build_arguments(parser) + + access.add_pin_argument(parser, "cs", required=True, default=True) + access.add_pin_argument(parser, "sck", required=True, default=True) + access.add_pin_argument(parser, "copi", required=True, default=True) + access.add_pin_argument(parser, "cipo", required=True, default=True) + access.add_pin_argument(parser, "reset", required=False, default=True) + access.add_pin_argument(parser, "dio0", required=False, default=True) # currently unused + + parser.add_argument( + "-f", "--frequency", metavar="FREQ", type=int, default=1000, + help="set SPI frequency to FREQ kHz (default: %(default)s)") + + def build(self, target, args): + dut_reset, self.__addr_dut_reset = target.registers.add_rw(1) + + self.mux_interface = iface = target.multiplexer.claim_interface(self, args) + pads = iface.get_pads(args, pins=self.__pins) + + spi_subtarget = SPIControllerSubtarget( + pads=pads, + out_fifo=iface.get_out_fifo(), + in_fifo=iface.get_in_fifo(), + period_cyc=math.ceil(target.sys_clk_freq / (args.frequency * 1000)), + delay_cyc=math.ceil(target.sys_clk_freq / 1e6), + sck_idle=0, + sck_edge="rising", + cs_active=0, + ) + sx1276_subtarget = RadioSX1276Subtarget(spi_subtarget, pads.reset_t, dut_reset) + return iface.add_subtarget(sx1276_subtarget) + + async def run(self, device, args): + iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args) + spi_iface = SPIControllerInterface(iface, self.logger) + sx1276_iface = RadioSX1276Interface(spi_iface, self.logger, device, + self.__addr_dut_reset) + return sx1276_iface + +# ------------------------------------------------------------------------------------------------- + +class RadioSX1276AppletTestCase(GlasgowAppletTestCase, applet=RadioSX1276Applet): + @synthesis_test + def test_build(self): + self.assertBuilds() diff --git a/software/glasgow/arch/sx1276/__init__.py b/software/glasgow/arch/sx1276/__init__.py new file mode 100644 index 000000000..649c78648 --- /dev/null +++ b/software/glasgow/arch/sx1276/__init__.py @@ -0,0 +1,619 @@ +# Ref: SX1276/77/78/79 - 137 MHz to 1020 MHz Low Power Long Range Transceiver Datasheet +# Ref: https://www.semtech.com/products/wireless-rf/lora-connect/sx1276#documentation +# Accession: G00086 + +import enum + +from ...support.bitstruct import * + + +__all__ = [ + "Addr", + "Version", +] + + +class Addr(enum.IntEnum): + # Mode-independent registers. + RegFifo = 0x00 + RegOpMode = 0x01 + # --- 0x02 - 0x05 --- + RegFrfMsb = 0x06 + RegFrfMid = 0x07 + RegFrfLsb = 0x08 + RegPaConfig = 0x09 + RegPaRamp = 0x0a + RegOcp = 0x0b + RegLna = 0x0c + # --- 0x0d - 0x3f --- + RegDioMapping1 = 0x40 + RegDioMapping2 = 0x41 + RegVersion = 0x42 + # --- 0x43 - 0x4a --- + RegTcxo = 0x4b + # --- 0x4c - 0x4c --- + RegPaDac = 0x4d + # --- 0x4f - 0x5a --- + RegFormerTemp = 0x5b + # --- 0x5c - 0x60 --- + RegAgcRef = 0x61 + RegAgcThresh1 = 0x62 + RegAgcThresh2 = 0x63 + RegAgcThresh3 = 0x64 + # --- 0x65 - 0x6f --- + RegPll = 0x70 + + # LoRa mode specific registers. + RegFifoAddrPtr = 0x0d + RegFifoTxBaseAddr = 0x0e + RegFifoRxBaseAddr = 0x0f + RegFifoRxCurrentAddr = 0x10 + RegIrqFlagsMask = 0x11 + RegIrqFlags = 0x12 + RegRxNbBytes = 0x13 + RegRxHeaderCntValueMsb = 0x14 + RegRxHeaderCntValueLsb = 0x15 + RegRxPacketCntValueMsb = 0x16 + RegRxPacketCntValueLsb = 0x17 + RegModemStat = 0x18 + RegPktSnrValue = 0x19 + RegPktRssiValue = 0x1a + RegRssiValue_LoRa = 0x1b + RegHopChannel = 0x1c + RegModemConfig1 = 0x1d + RegModemConfig2 = 0x1e + # MSB is bytes [1:0] of MODEM_CONFIG_2 + RegSymbTimeoutLsb = 0x1f + RegPreambleMsb_LoRa = 0x20 + RegPreambleLsb_LoRa = 0x21 + RegPayloadLength_LoRa = 0x22 + RegMaxPayloadLength = 0x23 + RegHopPeriod = 0x24 + RegFifoRxByteAddr = 0x25 + RegModemConfig3 = 0x26 + RegFeiMsb_LoRa = 0x28 + RegFeiMid = 0x29 + RegFeiLsb_LoRa = 0x2a + RegRssiWideband = 0x2c + # Note: RegIfFreq is referred to inconsistently in the datasheet. + # RESERVED - 0x2d + # RESERVED - 0x2e + RegIfFreq1 = 0x2f + RegIfFreq2 = 0x30 + RegDetectOptimize = 0x31 + # RESERVED - 0x32 + RegInvertIQ = 0x33 + # RESERVED - 0x34 + # RESERVED - 0x35 + RegHighBwOptimize1 = 0x36 + RegDetectionThreshold = 0x37 + # RESERVED - 0x38 + RegSyncWord = 0x39 + RegHighBwOptimize2 = 0x3a + RegInvertIQ2 = 0x3b + + # FSK/OOK modde specific registers. + RegBitrateMsb = 0x02 + RegBitrateLsb = 0x03 + RegFdevMsb = 0x04 + RegFdevLsb = 0x05 + # --- 0x06 - 0x0c --- SHARED + RegRxConfig = 0x0d + RegRssiConfig = 0x0e + RegRssiCollision = 0x0f + RegRssiThresh = 0x10 + RegRssiValue_FSK = 0x11 + RegRxBw = 0x12 + RegAfcBw = 0x13 + RegOokPeak = 0x14 + RegOokFix = 0x15 + RegOokAvg = 0x16 + # --- 0x17 - 0x19 --- RESERVED + RegAfcFei = 0x1a + RegAfcMsb = 0x1b + RegAfcLsb = 0x1c + RegFeiMsb_FSK = 0x1d + RegFeiLsb_FSK = 0x1e + RegPreambleDetect = 0x1f + RegRxTimeout1 = 0x20 + RegRxTimeout2 = 0x21 + RegRxTimeout3 = 0x22 + RegRxDelay = 0x23 + RegOsc = 0x24 + RegPreambleMsb_FSK = 0x25 + RegPreambleLsb_FSK = 0x26 + RegSyncConfig = 0x27 + RegSyncValue1 = 0x28 + RegSyncValue2 = 0x29 + RegSyncValue3 = 0x2a + RegSyncValue4 = 0x2b + RegSyncValue5 = 0x2c + RegSyncValue6 = 0x2d + RegSyncValue7 = 0x2e + RegSyncValue8 = 0x2f + RegPacketConfig1 = 0x30 + RegPacketConfig2 = 0x31 + RegPayloadLength_FSK = 0x32 + RegNodeAdrs = 0x33 + RegBroadcastAdrs = 0x34 + RegFifoThresh = 0x35 + RegSeqConfig1 = 0x36 + RegSeqConfig2 = 0x37 + RegTimerResol = 0x38 + RegTimer1Coef = 0x39 + RegTimer2Coef = 0x3a + RegImageCal = 0x3b + RegTemp = 0x3c + RegLowBat = 0x3d + RegIrqFlags1 = 0x3e + RegIrqFlags2 = 0x3f + # --- 0x40 - 0x43 --- SHARED + RegPllHop = 0x44 + # --- 0x45 - 0x5c --- SHARED + RegBitRateFrac = 0x5d + +# --- Mode-independent registers ------------------------------------------------------------------ + +# RegOpMode(0x01) +class Mode(enum.IntEnum): + Sleep = 0b000 + Stdby = 0b001 + FSTx = 0b010 + Tx = 0b011 + FSRx = 0b100 + Rx = 0b101 + +class ModulationType(enum.IntEnum): + FSK = 0b00 + OOK = 0b01 + +class LongRangeMode(enum.IntEnum): + FSK_OOK = 0b0 + LoRa = 0b1 + +RegOpMode = bitstruct("RegOpMode", 8, [ + ("Mode", 3), + ("LowFrequencyModeOn", 1), # if 1 then access to lf mode registers (0x61 - 0x73) + (None, 1), + ("ModulationType", 2), + ("LongRangeMode", 1), # only modifiable in sleep mode +]) + +# RegFrMsb(0x06) +# RegFrMid(0x07) +# RegFrLsb(0x08) + +# RegPaConfig(0x09) +class PaSelect(enum.IntEnum): + PA_BOOST = 0b1 + RFO = 0b0 + +RegPaConfig = bitstruct("RegPaConfig", 8, [ + ("OutputPower", 4), + ("MaxPower", 3), + ("PaSelect", 1), +]) + +# RegPaRamp(0x0a) +RegPaRamp = bitstruct("RegPaRamp", 8, [ + ("PaRamp", 4), + (None, 1), + ("ModulationShaping", 2), # Unused in LoRa mode. + (None, 1), +]) + +# RegOcp(0x0b) +RegOcp = bitstruct("RegOcp", 8, [ + ("OcpTrim", 5), + ("OcpOn", 1), + (None, 2), +]) + +# RegLna(0x0c) +class LnaBoostHf(enum.IntEnum): + ON = 0b11 + OFF = 0b00 + +class LnaGain(enum.IntEnum): + G1 = 0b001 + G2 = 0b010 + G3 = 0b011 + G4 = 0b100 + G5 = 0b101 + G6 = 0b110 + +RegLna = bitstruct("RegLna", 8, [ + ("LnaBoostHf", 2), + (None, 1), + ("LnaBoostLf", 2), + ("LnaGain", 3), +]) + +# RegDioMapping1(0x40) +REG_DIO_MAPPING_1 = bitstruct("REG_DIO_MAPPING_1", 8, [ + ("Dio3Mapping", 2), + ("Dio2Mapping", 2), + ("Dio1Mapping", 2), + ("Dio0Mapping", 2), +]) + +# RegDioMapping2(0x41) +REG_DIO_MAPPING_2 = bitstruct("REG_DIO_MAPPING_2", 8, [ + ("MapPreambleDetect", 1), + (None, 3), + ("Dio5Mapping", 2), + ("Dio4Mapping", 2), +]) + +# RegVersion(0x42) +class Version(enum.IntEnum): + # A single specific value for this register is specified in the datasheet. + ProductionRevision = 0x12 + +# RegTcxo(0x4b) +RegTcxo = bitstruct("RegTcxo", 8, [ + (None, 4), + ("TcxoInputOn", 1), + (None, 3), +]) + +# RegPaDac(0x4d) +RegPaDac = bitstruct("RegPaDac", 8, [ + ("PaDac", 3), + (None, 5), +]) + +# RegFormerTemp(0x5b) + +# RegAgcRef(0x61) +RegAgcRef = bitstruct("RegAgcRef", 8, [ + ("AgcReferenceLevel", 6), + (None, 2), +]) + +# RegAgcThresh1(0x62) + +# RegAgcThresh2(0x63) + +# RegAgcThresh3(0x64) + +# RegPll(0x70) +RegPll = bitstruct("RegPll", 8, [ + (None, 6), + ("PllBandwidth", 2), +]) + +# --- LoRa mode specific registers ---------------------------------------------------------------- + +# RegFifoAddrPtr(0x0d) +# RegFifoTxBaseAddr(0x0e) +# RegFifoRxBaseAddr(0x0f) +# RegFifoRxCurrentAddr(0x10) + +# RegIrqFlagsMask(0x11) +RegIrqFlagsMask = bitstruct("RegIrqFlagsMask", 8, [ + ("CadDetectedMask", 1), + ("FhssChangeChannelMask", 1), + ("CadDoneMask", 1), + ("TxDoneMask", 1), + ("ValidHeaderMask", 1), + ("PayloadCrcErrorMask", 1), + ("RxDoneMask", 1), + ("RxTimeoutMask", 1), +]) + +# RegIrqFlags(0x12) +RegIrqFlags = bitstruct("RegIrqFlags", 8, [ + ("CadDetected", 1), + ("FhssChangeChannel", 1), + ("CadDone", 1), + ("TxDone", 1), + ("ValidHeader", 1), + ("PayloadCrcErrork", 1), + ("RxDone", 1), + ("RxTimeout", 1), +]) + +# RegRxNbBytes(0x13) +# RegRxHeaderCntValueMsb(0x14) +# RegRxHeaderCntValueLsb(0x15) +# RegRxPacketCntValueMsb(0x16) +# RegRxPacketCntValueLsb(0x17) + +# RegModemStat(0x18) +RegModemStat = bitstruct("RegModemStat", 8, [ + +]) + +# RegPktSnrValue(0x19) +# RegPktRssiValue(0x1a) +# RegRssiValue_LoRa(0x1b) +# RegHopChannel(0x1c) +# RegModemConfig1(0x1d) +# RegModemConfig2(0x1e) +# RegSymbTimeoutLsb(0x1f) +# RegPreambleMsb_LoRa(0x20) +# RegPreambleLsb_LoRa(0x21) +# RegPayloadLength_LoRa(0x22) +# RegMaxPayloadLength(0x23) +# RegHopPeriod(0x24) +# RegFifoRxByteAddr(0x25) +# RegModemConfig3(0x26) +# RegFeiMsb_LoRa(0x28) +# RegFeiMid(0x29) +# RegFeiLsb_LoRa(0x2a) +# RegRssiWideband(0x2c) +# RegIfFreq1(0x2f) +# RegIfFreq2(0x30) +# RegDetectOptimize(0x31) +# RegInvertIQ(0x33) +# RegHighBwOptimize1(0x36) +# RegDetectionThreshold(0x37) +# RegSyncWord(0x39) +# RegHighBwOptimize2(0x3a) +# RegInvertIQ2(0x3b) + +# --- FSK/OOK mode specific registers ------------------------------------------------------------- + +# RegBitrateMsb(0x02) +# RegBitrateLsb(0x03) + +# RegFdevMsb(0x04) +# RegFdevLsb(0x05) + +# RegRxConfig(0x0d) +RegRxConfig = bitstruct("RegRxConfig", 8, [ + ("RxTrigger", 3), # G00086 - Table 24 + ("AgcAutoOn", 1), + ("AfcAutoOn", 1), + ("RestartRxWithPllLock", 1), + ("RestartRxWithoutPllLock", 1), + ("RestartRxOnCollision", 1), +]) + +# RegRssiConfig(0x0e) +class RssiSmoothing(enum.IntEnum): + _2 = 0b000 + _4 = 0b001 + _8 = 0b010 + _16 = 0b011 + _32 = 0b100 + _64 = 0b101 + _128 = 0b110 + _256 = 0b111 + +RegRssiConfig = bitstruct("RegRssiConfig", 8, [ + ("RssiSmoothing", 3), + ("RssiOffset", 5), +]) + +# RegRssiCollision(0x0f) + +# RegRssiThresh(0x10) + +# RegRssiValue_FSK(0x11) + +# RegRxBw(0x12) +REG_RX_BW = bitstruct("REG_RX_BW", 8, [ + ("RxBwExp", 3), + ("RxBwMant", 2), + (None, 3), +]) + +# RegAfcBw(0x13) +REG_AFC_BW = bitstruct("REG_AFC_BW", 8, [ + ("RxBwExpAfc", 3), + ("RxBwMantAfc", 2), + (None, 3), +]) + +# RegOokPeak(0x14) +REG_OOK_PEAK = bitstruct("REG_OOK_PEAK", 8, [ + ("OokPeakTheshStep", 3), + ("OokThreshType", 2), + ("BitSyncOn", 1), + (None, 2), +]) + +# RegOokFix(0x15) + +# RegOokAvg(0x16) +REG_OOK_AVG = bitstruct("REG_OOK_AVG", 8, [ + ("OokAverageThreshFilt", 2), + ("OokAverageOffset", 2), + (None, 1), + ("OokPeakThreshDec", 3), +]) + +# RegAfcFei(0x1a) +REG_AFC_FEI = bitstruct("REG_AFC_FEI", 8, [ + ("AfcAutoClearOn", 1), + ("AfcClear", 1), + (None, 1), + (None, 1), + ("AgcStart", 1), + (None, 3), +]) + +# RegAfcMsb(0x1b) +# RegAfcLsb(0x1c) + +# RegFeiMsb_FSK(0x1d) +# RegFeiLsb_FSK(0x1e) + +# RegPreambleDetect(0x1f) +REG_PREAMBLE_DETECT = bitstruct("REG_PREAMBLE_DETECT", 8, [ + ("PreambleDetectorTol", 5), + ("PreambleDetectorSize", 2), + ("PreambleDetectorOn", 1), +]) + +# RegRxTimeout1(0x20) + +# RegRxTimeout2(0x21) + +# RegRxTimeout3(0x22) + +# RegRxDelay(0x23) + +# RegOsc(0x24) +class ClkOut(enum.IntEnum): + FXOSC = 0b000 + FXOSC_DIV_2 = 0b001 + FXOSC_DIV_4 = 0b010 + FXOSC_DIV_8 = 0b011 + FXOSC_DIV_16 = 0b100 + FXOSC_DIV_32 = 0b101 + RC = 0b110 + OFF = 0b111 + +RegOsc = bitstruct("RegOsc", 8, [ + ("ClkOut", 3), + ("RcCalStart", 1), + (None, 4), +]) + +# RegPreambleMsb_FSK(0x25) +# RegPreambleLsb_FSK(0x26) + +# RegSyncConfig(0x27) +class AutoRestartRxMode(enum.IntEnum): + OFF = 0b00 + ON_WITHOUT_RELOCK = 0b01 + ON = 0b10 + +RegSyncConfig = bitstruct("RegSyncConfig", 8, [ + ("SyncSize", 3), + (None, 1), + ("SyncOn", 1), + ("PreamblePolarity", 1), + ("AutoRestartRxMode", 2), +]) + +# RegSyncValue1(0x28) +# RegSyncValue2(0x29) +# RegSyncValue3(0x2a) +# RegSyncValue4(0x2b) +# RegSyncValue5(0x2c) +# RegSyncValue6(0x2d) +# RegSyncValue7(0x2e) +# RegSyncValue8(0x2f) + +# RegPacketConfig1(0x30) +RegPacketConfig1 = bitstruct("RegPacketConfig1", 8, [ + ("CrcWhiteningType", 1), + ("AddressFiltering", 2), + ("CrcAutoClearOff", 1), + ("CrcOn", 1), + ("DcFree", 2), + ("PacketFormat", 1), +]) + +# RegPacketConfig2(0x31) +RegPacketConfig2 = bitstruct("RegPacketConfig2", 8, [ + ("PayloadLength_MSB", 3), + ("BeaconOn", 1), + ("IoHomePowerFrame", 1), + ("IoHomeOn", 1), + ("DataMode", 1), + (None, 1), +]) + +# RegPayloadLength_FSK(0x32) + +# RegNodeAdrs(0x33) + +# RegBroadcastAdrs(0x34) + +# RegFifoThresh(0x35) +RegFifoThresh = bitstruct("RegFifoThresh", 8, [ + ("FifoThreshold", 6), + (None, 1), + ("TxStartCondition", 1), +]) + + +# RegSeqConfig1(0x36) +RegSeqConfig1 = bitstruct("RegSeqConfig1", 8, [ + ("FromTransmit", 1), + ("FromIdle", 1), + ("LowPowerSelection", 1), + ("FromStart", 2), + ("IdleMode", 1), + ("SequencerStop", 1), + ("SequencerStart", 1), +]) + +# RegSeqConfig2(0x37) +RegSeqConfig2 = bitstruct("RegSeqConfig2", 8, [ + ("FromPacketReceived", 3), + ("FromRxTimeout", 2), + ("FromReceive", 3), +]) + +# RegTimerResol(0x38) +RegTimerResol = bitstruct("RegTimerResol", 8, [ + ("Timer2Resolution", 2), + ("Timer1Resolution", 2), + (None, 4), +]) + +# RegTimer1Coef(0x39) + +# RegTimer2Coef(0x3a) + +# RegImageCal(0x3b) +RegImageCal = bitstruct("RegImageCal", 8, [ + ("TempMonitorOff", 1), + ("TempThreshold", 2), + ("TempChange", 1), + (None, 1), + ("ImageCalRunning", 1), + ("ImageCalStart", 1), + ("AutoImageCalOn", 1), +]) + +# RegTemp(0x3c) + +# RegLowBat(0x3d) +RegLowBat = bitstruct("RegLowBat", 8, [ + ("LowBatTrim", 3), + ("LowBatOn", 1), + (None, 4), +]) + +# RegIrqFlags1(0x3e) +RegIrqFlags1 = bitstruct("RegIrqFlags1", 8, [ + ("SyncAddressMatch", 1), + ("PreambleDetect", 1), + ("Timeout", 1), + ("Rssi", 1), + ("PllLock", 1), + ("TxReady", 1), + ("RxReady", 1), + ("ModeReady", 1), +]) + +# RegIrqFlags2(0x3f) +RegIrqFlags2 = bitstruct("RegIrqFlags2", 8, [ + ("LowBat", 1), + ("CrcOk", 1), + ("PayloadReady", 1), + ("PacketSent", 1), + ("FifoOverrun", 1), + ("FifoLevel", 1), + ("FifoEmpty", 1), + ("FifoFull", 1), +]) + +# RegPllHop(0x44) +RegPllHop = bitstruct("RegPllHop", 8, [ + (None, 7), + ("FastHopOn", 1), +]) + +# RegBitRateFrac(0x5d) +RegBitRateFrac = bitstruct("RegBitRateFrac", 8, [ + ("BitRateFrac", 4), + (None, 4), +]) diff --git a/software/pyproject.toml b/software/pyproject.toml index fc6dac3f0..bb548e2cc 100644 --- a/software/pyproject.toml +++ b/software/pyproject.toml @@ -102,6 +102,7 @@ video-vga-output = "glasgow.applet.video.vga_output:VGAOutputApplet" video-ws2812-output = "glasgow.applet.video.ws2812_output:VideoWS2812OutputApplet" radio-nrf24l01 = "glasgow.applet.radio.nrf24l01:RadioNRF24L01Applet" +radio-sx1276 = "glasgow.applet.radio.sx1276:RadioSX1276Applet" [project.urls] "Documentation" = "https://glasgow-embedded.org/"