27
27
adapted from the Radiohead library RF95 code from:
28
28
http: www.airspayce.com/mikem/arduino/RadioHead/
29
29
30
- * Author(s): Tony DiCola
30
+ * Author(s): Tony DiCola, Jerry Needell
31
31
"""
32
32
import time
33
33
import digitalio
120
120
_RH_RF95_PA_RAMP_2MS = const (0x01 )
121
121
_RH_RF95_PA_RAMP_1MS = const (0x02 )
122
122
_RH_RF95_PA_RAMP_500US = const (0x03 )
123
- _RH_RF95_PA_RAMP_250US = const (0x0 )
123
+ _RH_RF95_PA_RAMP_250US = const (0x04 )
124
124
_RH_RF95_PA_RAMP_125US = const (0x05 )
125
125
_RH_RF95_PA_RAMP_100US = const (0x06 )
126
126
_RH_RF95_PA_RAMP_62US = const (0x07 )
212
212
_RH_RF95_FXOSC = 32000000.0
213
213
214
214
# The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19
215
- _RH_RF95_FSTEP = (_RH_RF95_FXOSC // 524288 )
215
+ _RH_RF95_FSTEP = (_RH_RF95_FXOSC / 524288 )
216
216
217
217
# RadioHead specific compatibility constants.
218
218
_RH_BROADCAST_ADDRESS = const (0xFF )
@@ -266,7 +266,7 @@ class RFM9x:
266
266
# at least as large as the FIFO on the chip (256 bytes)! Keep this on the
267
267
# class level to ensure only one copy ever exists (with the trade-off that
268
268
# this is NOT re-entrant or thread safe code by design).
269
- _BUFFER = bytearray (256 )
269
+ _BUFFER = bytearray (10 )
270
270
271
271
class _RegisterBits :
272
272
# Class to simplify access to the many configuration bits avaialable
@@ -334,9 +334,10 @@ def __set__(self, obj, val):
334
334
rx_done = _RegisterBits (_RH_RF95_REG_12_IRQ_FLAGS , offset = 6 , bits = 1 )
335
335
336
336
def __init__ (self , spi , cs , reset , frequency , * , preamble_length = 8 ,
337
- high_power = True , baudrate = 10000000 ):
337
+ high_power = True , baudrate = 5000000 ):
338
338
self .high_power = high_power
339
339
# Device support SPI mode 0 (polarity & phase = 0) up to a max of 10mhz.
340
+ # Set Default Baudrate to 5MHz to avoid problems
340
341
self ._device = spi_device .SPIDevice (spi , cs , baudrate = baudrate ,
341
342
polarity = 0 , phase = 0 )
342
343
# Setup reset as a digital input (default state for reset line according
@@ -361,20 +362,23 @@ def __init__(self, spi, cs, reset, frequency, *, preamble_length=8,
361
362
raise RuntimeError ('Failed to configure radio for LoRa mode, check wiring!' )
362
363
except OSError :
363
364
raise RuntimeError ('Failed to communicate with radio, check wiring!' )
365
+ # clear default setting for access to LF registers if frequency > 525MHz
366
+ if frequency > 525 :
367
+ self .low_frequency_mode = 0
364
368
# Setup entire 256 byte FIFO
365
369
self ._write_u8 (_RH_RF95_REG_0E_FIFO_TX_BASE_ADDR , 0x00 )
366
370
self ._write_u8 (_RH_RF95_REG_0F_FIFO_RX_BASE_ADDR , 0x00 )
367
371
# Set mode idle
368
372
self .idle ()
369
- # Set modem config to RadioHead comaptible Bw125Cr45Sf128 mode.
373
+ # Set modem config to RadioHead compatible Bw125Cr45Sf128 mode.
370
374
# Note no sync word is set for LoRa mode either!
371
375
self ._write_u8 (_RH_RF95_REG_1D_MODEM_CONFIG1 , 0x72 ) # Fei msb?
372
376
self ._write_u8 (_RH_RF95_REG_1E_MODEM_CONFIG2 , 0x74 ) # Fei lsb?
373
377
self ._write_u8 (_RH_RF95_REG_26_MODEM_CONFIG3 , 0x00 ) # Preamble lsb?
374
378
# Set preamble length (default 8 bytes to match radiohead).
375
379
self .preamble_length = preamble_length
376
380
# Set frequency
377
- self .frequency = frequency
381
+ self .frequency_mhz = frequency
378
382
# Set TX power to low defaut, 13 dB.
379
383
self .tx_power = 13
380
384
@@ -494,6 +498,10 @@ def tx_power(self):
494
498
high power devices (RFM95/96/97/98, high_power=True) or -1 to 14 for low
495
499
power devices. Only integer power levels are actually set (i.e. 12.5
496
500
will result in a value of 12 dBm).
501
+ The actual maximum setting for high_power=True is 20dBm but for values > 20
502
+ the PA_BOOST will be enabled resulting in an additional gain of 3dBm.
503
+ The actual setting is reduced by 3dBm.
504
+ The reported value will reflect the reduced setting.
497
505
"""
498
506
if self .high_power :
499
507
return self .output_power + 5
@@ -505,14 +513,17 @@ def tx_power(self, val):
505
513
if self .high_power :
506
514
assert 5 <= val <= 23
507
515
# Enable power amp DAC if power is above 20 dB.
516
+ # Lower setting by 3db when PA_BOOST enabled - see Data Sheet Section 6.4
508
517
if val > 20 :
509
518
self .pa_dac = _RH_RF95_PA_DAC_ENABLE
519
+ val -= 3
510
520
else :
511
521
self .pa_dac = _RH_RF95_PA_DAC_DISABLE
512
522
self .pa_select = True
513
523
self .output_power = (val - 5 ) & 0x0F
514
524
else :
515
525
assert - 1 <= val <= 14
526
+ self .pa_select = False
516
527
self .max_power = 0b111 # Allow max power output.
517
528
self .output_power = (val + 1 ) & 0x0F
518
529
@@ -523,10 +534,11 @@ def rssi(self):
523
534
# Remember in LoRa mode the payload register changes function to RSSI!
524
535
return self ._read_u8 (_RH_RF95_REG_1A_PKT_RSSI_VALUE ) - 137
525
536
526
- def send (self , data ):
537
+ def send (self , data , timeout = 2. ):
527
538
"""Send a string of data using the transmitter. You can only send 252
528
539
bytes at a time (limited by chip's FIFO size and appended headers). Note
529
540
this appends a 4 byte header to be compatible with the RadioHead library.
541
+ The timeout is just to prevent a hang (arbitrarily set to 2 Seconds).
530
542
"""
531
543
# Disable pylint warning to not use length as a check for zero.
532
544
# This is a puzzling warning as the below code is clearly the most
@@ -551,16 +563,21 @@ def send(self, data):
551
563
self .transmit ()
552
564
# Wait for tx done interrupt with explicit polling (not ideal but
553
565
# best that can be done right now without interrupts).
554
- while not self .tx_done :
555
- pass
556
- # Clear interrupts.
557
- self ._write_u8 (_RH_RF95_REG_12_IRQ_FLAGS , 0xFF )
566
+ start = time .monotonic ()
567
+ timed_out = False
568
+ while not timed_out and not self .tx_done :
569
+ if (time .monotonic () - start ) >= timeout :
570
+ timed_out = True
558
571
# Go back to idle mode after transmit.
559
572
self .idle ()
573
+ # Clear interrupts.
574
+ self ._write_u8 (_RH_RF95_REG_12_IRQ_FLAGS , 0xFF )
575
+ if timed_out :
576
+ raise RuntimeError ('Timeout during packet send' )
560
577
561
- def receive (self , timeout_s = 0.5 , keep_listening = True ):
578
+ def receive (self , timeout = 0.5 , keep_listening = True ):
562
579
"""Wait to receive a packet from the receiver. Will wait for up to
563
- timeout_s amount of seconds for a packet to be received and decoded. If
580
+ timeout amount of seconds for a packet to be received and decoded. If
564
581
a packet is found the payload bytes are returned, otherwise None is
565
582
returned (which indicates the timeout elapsed with no reception). Note
566
583
this assumes a 4-byte header is prepended to the data for compatibilty
@@ -576,32 +593,34 @@ def receive(self, timeout_s=0.5, keep_listening=True):
576
593
# enough, however it's the best that can be done from Python without
577
594
# interrupt supports.
578
595
start = time .monotonic ()
579
- while not self .rx_done :
580
- if (time .monotonic () - start ) >= timeout_s :
581
- return None # Exceeded timeout.
582
- # Clear interrupt.
583
- self ._write_u8 (_RH_RF95_REG_12_IRQ_FLAGS , 0xFF )
596
+ timed_out = False
597
+ while not timed_out and not self .rx_done :
598
+ if (time .monotonic () - start ) >= timeout :
599
+ timed_out = True
584
600
# Payload ready is set, a packet is in the FIFO.
585
601
packet = None
586
- # Enter idle mode to stop receiving other packets.
587
- self .idle ()
588
- # Grab the length of the received packet and check it has at least 5
589
- # bytes to indicate the 4 byte header and at least 1 byte of user data.
590
- length = self ._read_u8 (_RH_RF95_REG_13_RX_NB_BYTES )
591
- if length < 5 :
592
- packet = None
593
- else :
594
- # Have a good packet, grab it from the FIFO.
595
- # Reset the fifo read ptr to the beginning of the packet.
596
- current_addr = self ._read_u8 (_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR )
597
- self ._write_u8 (_RH_RF95_REG_0D_FIFO_ADDR_PTR , current_addr )
598
- # Read the first 4 bytes to grab the header.
599
- self ._read_into (_RH_RF95_REG_00_FIFO , self ._BUFFER , length = 4 )
600
- length -= 4
601
- # Next read the remaining data into a result packet buffer.
602
- packet = bytearray (length )
603
- self ._read_into (_RH_RF95_REG_00_FIFO , packet )
604
- # Listen again if necessary and return the result packet.
602
+ if not timed_out :
603
+ # Grab the length of the received packet and check it has at least 5
604
+ # bytes to indicate the 4 byte header and at least 1 byte of user data.
605
+ length = self ._read_u8 (_RH_RF95_REG_13_RX_NB_BYTES )
606
+ if length < 5 :
607
+ packet = None
608
+ else :
609
+ # Have a good packet, grab it from the FIFO.
610
+ # Reset the fifo read ptr to the beginning of the packet.
611
+ current_addr = self ._read_u8 (_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR )
612
+ self ._write_u8 (_RH_RF95_REG_0D_FIFO_ADDR_PTR , current_addr )
613
+ packet = bytearray (length )
614
+ # Read the packet.
615
+ self ._read_into (_RH_RF95_REG_00_FIFO , packet )
616
+ # strip off the header
617
+ packet = packet [4 :]
618
+ # Listen again if necessary and return the result packet.
605
619
if keep_listening :
606
620
self .listen ()
621
+ else :
622
+ # Enter idle mode to stop receiving other packets.
623
+ self .idle ()
624
+ # Clear interrupt.
625
+ self ._write_u8 (_RH_RF95_REG_12_IRQ_FLAGS , 0xFF )
607
626
return packet
0 commit comments