Skip to content

Commit

Permalink
0.4.0 (#9)
Browse files Browse the repository at this point in the history
* Update hookup.rst (#4): Changing the the Pi Pin for ID_SC in the documentation to be 28

* Adding to .gitignore and fixing the test readme

* Adding tests for RadioThreadSafe, and fixing a race condition that occurred when RadioThreadSafe called __exit__ before getting a chance to send all its acks. And adding a bunch of sleeps to the non-threadsafe tests because they suffer from the race condition too. Also refactored the Arduino test code.

* Adding documentation for threadsafe interface, along with example code

* Update README.md: Adding a badge for the docs

* Hopefully a shiny new pylint badge

* Cleaning up tests and adding coverage testing

* Adding test coverage for promiscuous mode and broadcasts, and fixing some bugs discovered by those tests

* Updating .gitignore to ignore coverage data files

* Updating test README.md to add instructions about how to generate coverage data

* pylint-ing the tests now too, and fixing some pylint issues with them

* Moving the order of broadcast testing

* Pylinting the examples now too

* Adding the ability to use BCM pin numbers instead of BOARD pin numbers, and corresponding tests.

* Preparing for 0.4.0 release

* Cosmetic formatting changes to the example code

Co-authored-by: Yanick H <[email protected]>
Co-authored-by: Jeremy Gillula <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2021
1 parent 7909056 commit ec42e7b
Show file tree
Hide file tree
Showing 32 changed files with 984 additions and 526 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/finish_pylint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import sys
import os

sys.exit(os.environ.get("linting_status", "failed") == "failed")
36 changes: 36 additions & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: pylint

on: [push]

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
- name: Analysing the code with pylint
id: pylint
run: python3 .github/workflows/run_pylint.py
- name: Generating badge
uses: schneegans/[email protected]
with:
auth: ${{ secrets.GIST_SECRET }}
gistID: 385e5dc0d1b4f63dffa3de2db8695a69
filename: test.json
label: pylint
message: ${{ steps.pylint.outputs.rating }}
color: ${{ steps.pylint.outputs.color }}
namedLogo: Python
style: flat
- name: Return final success code
env:
linting_status: ${{ steps.pylint.outputs.linting_status }}
run: python3 .github/workflows/finish_pylint.py
26 changes: 26 additions & 0 deletions .github/workflows/run_pylint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import sys
from glob import glob
from pylint.lint import Run

# Define thresholds: <3=red, <6=orange <8=yellow <9.5=green <10=brightgreen
thresholds = {3: 'red',
6: 'orange',
8: 'yellow',
9.5: 'green',
10: 'brightgreen'}

results = Run(['--disable=import-error,unused-wildcard-import,wildcard-import,line-too-long,invalid-name,missing-module-docstring,too-many-lines,too-many-instance-attributes,consider-using-f-string,too-many-locals,too-few-public-methods,too-many-branches,duplicate-code', 'RFM69'] + glob("tests/*.py") + glob("examples/*.py"), do_exit=False)

if results.linter.stats["fatal"] + results.linter.stats["error"] + results.linter.stats["warning"] > 0:
print("##[set-output name=rating]failing!")
print("##[set-output name=color]red")
print("##[set-output name=linting_status]failed")
else:
rating = results.linter.stats['global_note']
print("##[set-output name=rating]{:.2f}".format(rating))
for value in thresholds.keys():
if rating <= value:
print("##[set-output name=color]{}".format(thresholds[value]))
break
print("##[set-output name=linting_status]passed")
sys.exit(0)
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ __pycache__/
*.DS_Store
docs/build
*.vscode
\#*\#
*~
.coverage
.\#*

# Setuptools distribution folder.
/dist/
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.4.0
- Made the Radio class threadsafe, and added threadsafe methods for accessing packets
- Added testing for the threadsafe methods
- Added pylinting and made some cosmetic changes to get a good pylint score
- Added coverage testing via coveralls.io, and instructions for doing so

## 0.3.0
- Added support for sendListenModeBurst
- Made tests more configurable
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[![Documentation Status](https://readthedocs.org/projects/rpi-rfm69/badge/?version=latest)](https://rpi-rfm69.readthedocs.io/en/latest/?badge=latest)
[![pylint Status](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/jgillula/385e5dc0d1b4f63dffa3de2db8695a69/raw/test.json)](https://github.com/jgillula/rpi-rfm69/actions/workflows/pylint.yml)
[![Coverage Status](https://coveralls.io/repos/github/jgillula/rpi-rfm69/badge.svg)](https://coveralls.io/github/jgillula/rpi-rfm69)

# RFM69 Radio interface for the Raspberry Pi
This package provides a Python wrapper of the [LowPowerLabs RFM69 library](https://github.com/LowPowerLab/RFM69) and is largely based on the work of [Eric Trombly](https://github.com/etrombly/RFM69) who ported the library from C.

Expand Down
108 changes: 56 additions & 52 deletions RFM69/config.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,65 @@

from .registers import *

frfMSB = {RF69_315MHZ: RF_FRFMSB_315, RF69_433MHZ: RF_FRFMSB_433, RF69_868MHZ: RF_FRFMSB_868, RF69_915MHZ: RF_FRFMSB_915}
frfMID = {RF69_315MHZ: RF_FRFMID_315, RF69_433MHZ: RF_FRFMID_433, RF69_868MHZ: RF_FRFMID_868, RF69_915MHZ: RF_FRFMID_915}
frfLSB = {RF69_315MHZ: RF_FRFLSB_315, RF69_433MHZ: RF_FRFLSB_433, RF69_868MHZ: RF_FRFLSB_868, RF69_915MHZ: RF_FRFLSB_915}
frfMSB = {RF69_315MHZ: RF_FRFMSB_315, RF69_433MHZ: RF_FRFMSB_433,
RF69_868MHZ: RF_FRFMSB_868, RF69_915MHZ: RF_FRFMSB_915}
frfMID = {RF69_315MHZ: RF_FRFMID_315, RF69_433MHZ: RF_FRFMID_433,
RF69_868MHZ: RF_FRFMID_868, RF69_915MHZ: RF_FRFMID_915}
frfLSB = {RF69_315MHZ: RF_FRFLSB_315, RF69_433MHZ: RF_FRFLSB_433,
RF69_868MHZ: RF_FRFLSB_868, RF69_915MHZ: RF_FRFLSB_915}

# pylint: disable=missing-function-docstring
def get_config(freqBand, networkID):
return {
0x01: [REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY],
#no shaping
0x02: [REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00],
#default:4.8 KBPS
0x03: [REG_BITRATEMSB, RF_BITRATEMSB_55555],
0x04: [REG_BITRATELSB, RF_BITRATELSB_55555],
#default:5khz, (FDEV + BitRate/2 <= 500Khz)
0x05: [REG_FDEVMSB, RF_FDEVMSB_50000],
0x06: [REG_FDEVLSB, RF_FDEVLSB_50000],
0x01: [REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY],
#no shaping
0x02: [REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00],
#default:4.8 KBPS
0x03: [REG_BITRATEMSB, RF_BITRATEMSB_55555],
0x04: [REG_BITRATELSB, RF_BITRATELSB_55555],
#default:5khz, (FDEV + BitRate/2 <= 500Khz)
0x05: [REG_FDEVMSB, RF_FDEVMSB_50000],
0x06: [REG_FDEVLSB, RF_FDEVLSB_50000],

0x07: [REG_FRFMSB, frfMSB[freqBand]],
0x08: [REG_FRFMID, frfMID[freqBand]],
0x09: [REG_FRFLSB, frfLSB[freqBand]],
0x07: [REG_FRFMSB, frfMSB[freqBand]],
0x08: [REG_FRFMID, frfMID[freqBand]],
0x09: [REG_FRFLSB, frfLSB[freqBand]],

# looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
# +17dBm and +20dBm are possible on RFM69HW
# +13dBm formula: Pout=-18+OutputPower (with PA0 or PA1**)
# +17dBm formula: Pout=-14+OutputPower (with PA1 and PA2)**
# +20dBm formula: Pout=-11+OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
#0x11: [REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111],
#over current protection (default is 95mA)
#0x13: [REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95],
# looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
# +17dBm and +20dBm are possible on RFM69HW
# +13dBm formula: Pout=-18+OutputPower (with PA0 or PA1**)
# +17dBm formula: Pout=-14+OutputPower (with PA1 and PA2)**
# +20dBm formula: Pout=-11+OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
#0x11: [REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111],
#over current protection (default is 95mA)
#0x13: [REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95],

# RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4khz)
#//(BitRate < 2 * RxBw)
0x19: [REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2],
#for BR-19200: //* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
#DIO0 is the only IRQ we're using
0x25: [REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01],
#must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm
0x29: [REG_RSSITHRESH, 220],
#/* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
0x2e: [REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0],
#attempt to make this compatible with sync1 byte of RFM12B lib
0x2f: [REG_SYNCVALUE1, 0x2D],
#NETWORK ID
0x30: [REG_SYNCVALUE2, networkID],
0x37: [REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF |
RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF],
#in variable length mode: the max frame size, not used in TX
0x38: [REG_PAYLOADLENGTH, 66],
#* 0x39 */ { REG_NODEADRS, nodeID }, //turned off because we're not using address filtering
#TX on FIFO not empty
0x3C: [REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE],
#RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
0x3d: [REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF],
#for BR-19200: //* 0x3d */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
#* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode
# run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0
0x6F: [REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0],
0x00: [255, 0]
}
# RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4khz)
#//(BitRate < 2 * RxBw)
0x19: [REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2],
#for BR-19200: //* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
#DIO0 is the only IRQ we're using
0x25: [REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01],
#must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm
0x29: [REG_RSSITHRESH, 220],
#/* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
0x2e: [REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0],
#attempt to make this compatible with sync1 byte of RFM12B lib
0x2f: [REG_SYNCVALUE1, 0x2D],
#NETWORK ID
0x30: [REG_SYNCVALUE2, networkID],
0x37: [REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF |
RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF],
#in variable length mode: the max frame size, not used in TX
0x38: [REG_PAYLOADLENGTH, 66],
#* 0x39 */ { REG_NODEADRS, nodeID }, //turned off because we're not using address filtering
#TX on FIFO not empty
0x3C: [REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE],
#RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
0x3d: [REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF],
#for BR-19200: //* 0x3d */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
#* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode
# run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0
0x6F: [REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0],
0x00: [255, 0]
}
16 changes: 9 additions & 7 deletions RFM69/packet.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import json
from datetime import datetime

class Packet(object):
"""Object to represent received packet. Created internally and returned by radio when getPackets() is called.
class Packet:
"""Object to represent received packet. Created internally and
returned by radio when getPackets() is called.
Args:
receiver (int): Node ID of receiver
Expand All @@ -11,32 +12,33 @@ class Packet(object):
data (list): Raw transmitted data
"""

# Declare slots to reduce memory
__slots__ = 'received', 'receiver', 'sender', 'RSSI', 'data'

def __init__(self, receiver, sender, RSSI, data):
self.received = datetime.utcnow()
self.receiver = receiver
self.sender = sender
self.RSSI = RSSI
self.data = data

def to_dict(self, dateFormat=None):
"""Returns a dictionary representation of the class data"""
if dateFormat is None:
return_date = self.received
else:
return_date = datetime.strftime(self.received, dateFormat)
return dict(received=return_date, receiver=self.receiver, sender=self.sender, rssi=self.RSSI, data=self.data)
return dict(received=return_date, receiver=self.receiver,
sender=self.sender, rssi=self.RSSI, data=self.data)

@property
def data_string(self):
"""Returns the data as a string"""
return "".join([chr(letter) for letter in self.data])

def __str__(self):
return json.dumps(self.to_dict('%c'))

def __repr__(self):
return "Radio({}, {}, {}, [data])".format(self.receiver, self.sender, self.RSSI)

Loading

0 comments on commit ec42e7b

Please sign in to comment.