|
|
|
import time
|
|
|
|
|
|
|
|
import gex
|
|
|
|
import sx_fsk as sx
|
|
|
|
|
|
|
|
|
|
|
|
# we're demonstrating the use of the GFSK mode of the SX1278
|
|
|
|
# this is an example of how GEX can be used to control a peripheral module - in this case evaluating
|
|
|
|
# it for use in GEX remote
|
|
|
|
|
|
|
|
|
|
|
|
class LoRa:
|
|
|
|
def __init__(self,
|
|
|
|
rst: gex.DOut,
|
|
|
|
spi: gex.SPI, ssnum):
|
|
|
|
self.ss = ssnum
|
|
|
|
self.rst = rst
|
|
|
|
self.spi = spi
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self.rst.pulse_us(100, active=False)
|
|
|
|
time.sleep(0.005)
|
|
|
|
|
|
|
|
def rd(self, addr):
|
|
|
|
return self.spi.query(self.ss, [addr], 1)[0]
|
|
|
|
|
|
|
|
def wr(self, addr, value):
|
|
|
|
self.spi.write(self.ss, [addr | 0x80, value])
|
|
|
|
|
|
|
|
def rds(self, start, count=1):
|
|
|
|
return self.spi.query(self.ss, [start], count)
|
|
|
|
|
|
|
|
def wrs(self, start, values):
|
|
|
|
ba = bytearray()
|
|
|
|
ba.append(start | 0x80)
|
|
|
|
ba.extend(values)
|
|
|
|
self.spi.write(self.ss, ba)
|
|
|
|
|
|
|
|
def rmw(self, addr, keep, set):
|
|
|
|
""" rmw, first and-ing the register with mask and then oring with set """
|
|
|
|
val = self.rd(addr)
|
|
|
|
self.wr(addr, (val & keep) | set)
|
|
|
|
|
|
|
|
def waitModeSwitch(self):
|
|
|
|
while 0 == (self.rd(sx.REG_IRQFLAGS1) & sx.RF_IRQFLAGS1_MODEREADY):
|
|
|
|
time.sleep(0.001)
|
|
|
|
|
|
|
|
def waitSent(self):
|
|
|
|
while 0 == (self.rd(sx.REG_IRQFLAGS2) & sx.RF_IRQFLAGS2_PACKETSENT):
|
|
|
|
time.sleep(0.001)
|
|
|
|
|
|
|
|
def fsk_set_defaults(self):
|
|
|
|
# Set default values (semtech patches: * in DS)
|
|
|
|
self.rmw(sx.REG_RXCONFIG,
|
|
|
|
sx.RF_RXCONFIG_RXTRIGER_MASK,
|
|
|
|
sx.RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT)
|
|
|
|
|
|
|
|
self.wr(sx.REG_PREAMBLEDETECT,
|
|
|
|
sx.RF_PREAMBLEDETECT_DETECTOR_ON |
|
|
|
|
sx.RF_PREAMBLEDETECT_DETECTORSIZE_2 |
|
|
|
|
sx.RF_PREAMBLEDETECT_DETECTORTOL_10)
|
|
|
|
|
|
|
|
self.rmw(sx.REG_OSC, sx.RF_OSC_CLKOUT_MASK, sx.RF_OSC_CLKOUT_OFF)
|
|
|
|
|
|
|
|
self.rmw(sx.REG_FIFOTHRESH,
|
|
|
|
sx.RF_FIFOTHRESH_TXSTARTCONDITION_MASK,
|
|
|
|
sx.RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY)
|
|
|
|
|
|
|
|
self.rmw(sx.REG_IMAGECAL,
|
|
|
|
sx.RF_IMAGECAL_AUTOIMAGECAL_MASK,
|
|
|
|
sx.RF_IMAGECAL_AUTOIMAGECAL_OFF)
|
|
|
|
|
|
|
|
def configure_for_fsk(self, address):
|
|
|
|
self.rmw(sx.REG_OPMODE,
|
|
|
|
sx.RF_OPMODE_LONGRANGEMODE_MASK & sx.RF_OPMODE_MODULATIONTYPE_MASK & sx.RF_OPMODE_MASK,
|
|
|
|
sx.RF_OPMODE_LONGRANGEMODE_OFF |
|
|
|
|
sx.RF_OPMODE_MODULATIONTYPE_FSK |
|
|
|
|
sx.RF_OPMODE_STANDBY)
|
|
|
|
self.waitModeSwitch()
|
|
|
|
|
|
|
|
self.fsk_set_defaults()
|
|
|
|
self.wr(sx.REG_NODEADRS, address)
|
|
|
|
self.wr(sx.REG_BROADCASTADRS, 0xFF)
|
|
|
|
# use whitening and force address matching
|
|
|
|
self.rmw(sx.REG_PACKETCONFIG1,
|
|
|
|
sx.RF_PACKETCONFIG1_DCFREE_MASK & sx.RF_PACKETCONFIG1_ADDRSFILTERING_MASK,
|
|
|
|
sx.RF_PACKETCONFIG1_DCFREE_WHITENING |
|
|
|
|
sx.RF_PACKETCONFIG1_ADDRSFILTERING_NODEBROADCAST)
|
|
|
|
|
|
|
|
self.wr(sx.REG_RXCONFIG,
|
|
|
|
sx.RF_RXCONFIG_AFCAUTO_ON |
|
|
|
|
sx.RF_RXCONFIG_AGCAUTO_ON |
|
|
|
|
sx.RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT)
|
|
|
|
|
|
|
|
XTAL_FREQ = 32000000
|
|
|
|
FREQ_STEP = 61.03515625
|
|
|
|
FSK_FDEV = 60000 # Hz NOTE: originally: 25000, seems to help increasing
|
|
|
|
FSK_DATARATE = 200000 # bps - originally 50000
|
|
|
|
|
|
|
|
MAX_RFPOWER = 0 # 0-7 boost - this doesnt seem to have a huge impact
|
|
|
|
|
|
|
|
FSK_PREAMBLE_LENGTH = 5 # Same for Tx and Rx
|
|
|
|
|
|
|
|
fdev = round(FSK_FDEV / FREQ_STEP)
|
|
|
|
self.wr(sx.REG_FDEVMSB, fdev >> 8)
|
|
|
|
self.wr(sx.REG_FDEVLSB, fdev & 0xFF)
|
|
|
|
|
|
|
|
datarate = round(XTAL_FREQ / FSK_DATARATE)
|
|
|
|
print("dr=%d"%datarate)
|
|
|
|
self.wr(sx.REG_BITRATEMSB, datarate >> 8)
|
|
|
|
self.wr(sx.REG_BITRATELSB, datarate & 0xFF)
|
|
|
|
|
|
|
|
preamblelen = FSK_PREAMBLE_LENGTH
|
|
|
|
self.wr(sx.REG_PREAMBLEMSB, preamblelen >> 8)
|
|
|
|
self.wr(sx.REG_PREAMBLELSB, preamblelen & 0xFF)
|
|
|
|
|
|
|
|
# bandwidths - 1 MHz
|
|
|
|
self.wr(sx.REG_RXBW, 0x0A) # FSK_BANDWIDTH
|
|
|
|
self.wr(sx.REG_AFCBW, 0x0A) # FSK_AFC_BANDWIDTH
|
|
|
|
|
|
|
|
# max payload len to rx
|
|
|
|
self.wr(sx.REG_PAYLOADLENGTH, 0xFF)
|
|
|
|
|
|
|
|
self.rmw(sx.REG_PARAMP, 0x9F, 0x40) # enable gauss 0.5
|
|
|
|
|
|
|
|
# pick the sync word size
|
|
|
|
self.rmw(sx.REG_SYNCCONFIG,
|
|
|
|
sx.RF_SYNCCONFIG_SYNCSIZE_MASK,
|
|
|
|
sx.RF_SYNCCONFIG_SYNCSIZE_3)
|
|
|
|
|
|
|
|
# sync word (network ID)
|
|
|
|
self.wrs(sx.REG_SYNCVALUE1, [
|
|
|
|
0xe7, 0x3d, 0xfa, 0x01, 0x5e, 0xa1, 0xc9, 0x98 # something random
|
|
|
|
])
|
|
|
|
|
|
|
|
# enable LNA boost (?)
|
|
|
|
self.rmw(sx.REG_LNA,
|
|
|
|
sx.RF_LNA_BOOST_MASK,
|
|
|
|
sx.RF_LNA_BOOST_ON)
|
|
|
|
|
|
|
|
# experiments with the pa config
|
|
|
|
self.rmw(sx.REG_PACONFIG,
|
|
|
|
sx.RF_PACONFIG_PASELECT_MASK|0x8F, # max power mask
|
|
|
|
sx.RF_PACONFIG_PASELECT_PABOOST | MAX_RFPOWER<<4)
|
|
|
|
|
|
|
|
# we could also possibly adjust the Tx power
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gex.Client(gex.TrxRawUSB()) as client:
|
|
|
|
spi = gex.SPI(client, 'spi')
|
|
|
|
rst1 = gex.DOut(client, 'rst1')
|
|
|
|
rst2 = gex.DOut(client, 'rst2')
|
|
|
|
|
|
|
|
a = LoRa(rst1, spi, 0)
|
|
|
|
b = LoRa(rst2, spi, 1)
|
|
|
|
|
|
|
|
# reset the two transceivers to ensure they start in a defined state
|
|
|
|
a.reset()
|
|
|
|
b.reset()
|
|
|
|
|
|
|
|
# go to sleep mode, select FSK
|
|
|
|
a.configure_for_fsk(0x33)
|
|
|
|
b.configure_for_fsk(0x44)
|
|
|
|
|
|
|
|
print("Devices configured")
|
|
|
|
|
|
|
|
for j in range(0, 240):
|
|
|
|
if(j>0 and j%60==0):
|
|
|
|
print()
|
|
|
|
|
|
|
|
# --- Send a message from 1 to 2 ---
|
|
|
|
msg = [
|
|
|
|
51, # len
|
|
|
|
0x44, # address
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, j
|
|
|
|
]
|
|
|
|
|
|
|
|
a.wrs(sx.REG_FIFO, msg)
|
|
|
|
|
|
|
|
b.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_RECEIVER)
|
|
|
|
# time.sleep(0.005)
|
|
|
|
|
|
|
|
# trigger A
|
|
|
|
a.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_TRANSMITTER)
|
|
|
|
a.waitModeSwitch()
|
|
|
|
a.waitSent()
|
|
|
|
# time.sleep(0.02)
|
|
|
|
|
|
|
|
# print("a irq flags = ", ["0x%02x"%x for x in a.rds(sx.REG_IRQFLAGS1, 2)])
|
|
|
|
# print("b irq flags = ", ["0x%02x"%x for x in b.rds(sx.REG_IRQFLAGS1, 2)])
|
|
|
|
|
|
|
|
rxd = [b.rd(sx.REG_FIFO) for x in range(0,len(msg))]
|
|
|
|
if rxd == msg:
|
|
|
|
print("\x1b[32;1m+\x1b[0m", end="", flush=True)
|
|
|
|
else:
|
|
|
|
print("\x1b[31m-\x1b[0m", end="", flush=True)
|
|
|
|
#
|
|
|
|
# for i in range(0,8):
|
|
|
|
# print("0x%02x" % rxd[i],end=" ")
|
|
|
|
# print()
|
|
|
|
# print()
|
|
|
|
print()
|
|
|
|
|
|
|
|
# good night
|
|
|
|
a.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_SLEEP)
|
|
|
|
b.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_SLEEP)
|
|
|
|
|
|
|
|
|