Skip to content

Commit

Permalink
Finished configuration features and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cceremuga committed Apr 19, 2017
1 parent 84e2c72 commit c862b64
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 60 deletions.
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
![PyPacket](https://i.imgur.com/MZYHAFG.png "PyPacket")
<p align="center"><img src="https://i.imgur.com/MZYHAFG.png" /></p>

A simple CLI logger to receive and decode APRS packets via rtl_fm ([RTL-SDR](http://osmocom.org/projects/sdr/wiki/rtl-sdr)) and [multimon-ng](https://github.com/EliasOenal/multimon-ng). This project serves as an open source expirimental tool for research into the RF spectrum and APRS.
A simple CLI tool to receive, decode, log [APRS](http://www.aprs.org/) packets via rtl_fm ([RTL-SDR](http://osmocom.org/projects/sdr/wiki/rtl-sdr)) and [multimon-ng](https://github.com/EliasOenal/multimon-ng). This project serves as an open source expirimental tool for research into the RF spectrum and APRS.

[![Build Status](https://travis-ci.org/cceremuga/pypacket.svg?branch=master)](https://travis-ci.org/cceremuga/pypacket)

## Dependencies
## Requirements

Requires the following to be installed and configured on your system in order to run.
The following are required to be installed and configured on your system.

* Some form of Linux flavor. MacOS, possibly. Windows, doubtful.
* An RTL-SDR compatible device.
Expand All @@ -18,43 +18,44 @@ Requires the following to be installed and configured on your system in order to

## Configuration

The `config/configuration.json` file contains all of the current configuration options including frequency, gain, etc. More options will be added as needed.
The `config/configuration.json` file contains all of the configuration options including frequency, gain, etc. More options will be added as needed.

## Running

From the directory you've cloned the repository to, simply execute `python main.py`. The application will start and immediately begin listening on the configured frequency.
From the directory you've cloned the repository to, simply run `python main.py` in the shell of your choice. The application will start and immediately begin listening on the configured frequency.

Logged packets will be output to your terminal and written to a file in the `logs` directory.

## Recent Patch Notes

* 4/18/17
* Basic JSON-based configuration support.
* 4/18/2017 (v1.0)
* Improved RTL settings.
* Completed JSON configuration support.
* Improved logging.
* Resolved bug when logs directory did not exist.
* 4/17/17
* 4/17/2017 (v0.9)
* Logging runtime activities to file in the logs subdirectory.
* 4/2/17
* 4/2/2017 (v0.8)
* Start of unit tests.
* Travis CI integration.

## Current / Future Plans
## Feature Roadmap

* JSON configuration options for frequency, gain [in progress].
* APRS frame deserialization for human readability [future].
* Quality code coverage [future].
* Better documentation [future].
* Performance optimization [future].
* Simple TCP server (for use in Xastir etc.) [future].
* Custom IGate uploading [future].
* APRS frame deserialization for human readability [v2.0].
* Better documentation [v2.0].
* Performance optimization [v2.0].
* Simple TCP server (for use in Xastir etc.) [v3.0].
* Custom IGate uploading [v4.0].

## Contributing

You are welcome to contribute by submitting pull requests on GitHub as you see fit!
You are welcome to contribute by submitting pull requests on GitHub if you are interested in development.

Feature / enhancement requests may be submitted via GitHub issues.

## Credits

Thanks to the following projects / libraries for open source code / inspiration.
Thanks to the following projects / libraries for open source code / inspiration / Creative Commons resources.

* [pimultimonaprs](https://github.com/asdil12/pymultimonaprs)
* [The Noun Project](https://thenounproject.com/search/?q=radio%20tower&i=749293)
5 changes: 3 additions & 2 deletions config/configuration.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"radio": {
"rtl": {
"frequency": "144390000",
"gain": "49.6"
"gain": "49.6",
"sample_rate": "22050"
}
}
10 changes: 4 additions & 6 deletions pypacket/base/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ class Configuration:
def __init__(self):
self.data = {}
self.load()
self.validate()

def load(self):
with open(self.CONFIG_FILE_NAME) as json_data_file:
self.data = json.load(json_data_file)

def frequency(self):
return self.data['radio']['frequency']
return self.data['rtl']['frequency']

def gain(self):
return self.data['radio']['gain']
return self.data['rtl']['gain']

def validate(self):
pass
# TODO: Validate configuration.
def sample_rate(self):
return self.data['rtl']['sample_rate']
4 changes: 2 additions & 2 deletions pypacket/base/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def start(self):
self.log_handler.log_info('Starting rtl_fm subprocess.')

rtl_subprocess = subprocess.Popen(
['rtl_fm', '-f', self.config.frequency(), '-s', '22050', '-o', '4',
'-g', self.config.gain(), '-'],
['rtl_fm', '-M', 'fm', '-f', self.config.frequency(), '-s',
self.config.sample_rate(), '-l', '0', '-g', self.config.gain(), '-'],
stdout=subprocess.PIPE, stderr=open('/dev/null')
)

Expand Down
Empty file added tests/base/__init__.py
Empty file.
26 changes: 26 additions & 0 deletions tests/base/test_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from pypacket.base.configuration import Configuration

class TestConfiguration:
def test_frequency_expect_frequency(self, capsys):
test_configuration = Configuration()
expected_frequency = '144390000'

actual_frequency = test_configuration.frequency()

assert actual_frequency == expected_frequency

def test_sample_rate_expect_sample_rate(self, capsys):
test_configuration = Configuration()
expected_sample_rate = '22050'

actual_sample_rate = test_configuration.sample_rate()

assert actual_sample_rate == expected_sample_rate

def test_gain_expect_gain(self, capsys):
test_configuration = Configuration()
expected_gain = '49.6'

actual_gain = test_configuration.gain()

assert actual_gain == expected_gain
20 changes: 10 additions & 10 deletions tests/util/test_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

class TestColors:
def test_green_expect_green_value(self):
expectedColor = '\033[92m'
assert Colors.GREEN == expectedColor
expected_color = '\033[92m'
assert Colors.GREEN == expected_color

def test_yellow_expect_yellow_value(self):
expectedColor = '\033[93m'
assert Colors.YELLOW == expectedColor
expected_color = '\033[93m'
assert Colors.YELLOW == expected_color

def test_red_expect_red_value(self):
expectedColor = '\033[91m'
assert Colors.RED == expectedColor
expected_color = '\033[91m'
assert Colors.RED == expected_color

def test_reset_expect_reset_value(self):
expectedColor = '\033[0m'
assert Colors.RESET == expectedColor
expected_color = '\033[0m'
assert Colors.RESET == expected_color

def test_blue_expect_blue_value(self):
expectedColor = '\033[94m'
assert Colors.BLUE == expectedColor
expected_color = '\033[94m'
assert Colors.BLUE == expected_color
40 changes: 20 additions & 20 deletions tests/util/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,41 @@ class TestLogger:
PRINT_SUFFIX = '\n'

def test_log_info_expect_logged(self, capsys):
mockInfo = 'Hey, check out this info.'
expectedInfo = Colors.BLUE + Logger.SYS_PREFIX + Colors.RESET + \
mockInfo + self.PRINT_SUFFIX
mock_info = 'Hey, check out this info.'
expected_info = Colors.BLUE + Logger.SYS_PREFIX + Colors.RESET + \
mock_info + self.PRINT_SUFFIX

Logger().log_info(mockInfo)
Logger().log_info(mock_info)

out, err = capsys.readouterr()
assert out == expectedInfo
assert out == expected_info

def test_log_error_expect_logged(self, capsys):
mockError = 'Hey, check out this error.'
expectedError = Colors.RED + Logger.ERR_PREFIX + Colors.RESET + \
mockError + self.PRINT_SUFFIX
mock_error = 'Hey, check out this error.'
expected_error = Colors.RED + Logger.ERR_PREFIX + Colors.RESET + \
mock_error + self.PRINT_SUFFIX

Logger().log_error(mockError)
Logger().log_error(mock_error)

out, err = capsys.readouterr()
assert out == expectedError
assert out == expected_error

def test_log_warn_expect_logged(self, capsys):
mockWarn = 'Hey, check out this warning.'
expectedWarn = Colors.YELLOW + Logger.WRN_PREFIX + Colors.RESET + \
mockWarn + self.PRINT_SUFFIX
mock_warn = 'Hey, check out this warning.'
expected_warn = Colors.YELLOW + Logger.WRN_PREFIX + Colors.RESET + \
mock_warn + self.PRINT_SUFFIX

Logger().log_warn(mockWarn)
Logger().log_warn(mock_warn)

out, err = capsys.readouterr()
assert out == expectedWarn
assert out == expected_warn

def test_log_packet_expect_logged(self, capsys):
mockPacket = 'Hey, check out this packet.'
expectedPacket = Colors.GREEN + Logger.REC_PREFIX + Colors.RESET + \
mockPacket + self.PRINT_SUFFIX
mock_packet = 'Hey, check out this packet.'
expected_packet = Colors.GREEN + Logger.REC_PREFIX + Colors.RESET + \
mock_packet + self.PRINT_SUFFIX

Logger().log_packet(mockPacket)
Logger().log_packet(mock_packet)

out, err = capsys.readouterr()
assert out == expectedPacket
assert out == expected_packet

0 comments on commit c862b64

Please sign in to comment.