diff --git a/.gitignore b/.gitignore index c00201e..e993a91 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,6 @@ docs/_build/ # PyBuilder target/ + +# PyCharm +.idea/ diff --git a/README.rst b/README.rst index c8a2967..0da0716 100644 --- a/README.rst +++ b/README.rst @@ -109,3 +109,10 @@ Some helper functions: pms.hex2bin(msg) # convert hexadecimal string to binary string pms.hex2int(msg) # convert hexadecimal string to integer pms.bin2int(msg) # convert binary string to integer + +Developement +------------ +To run tests, run the following commands: +``` +$ tox +``` diff --git a/pyModeS/__init__.py b/pyModeS/__init__.py index 5be7b05..e69de29 100644 --- a/pyModeS/__init__.py +++ b/pyModeS/__init__.py @@ -1,5 +0,0 @@ -from __future__ import absolute_import, print_function, division - -from .util import * -from . import adsb -from . import ehs diff --git a/pyModeS/adsb.py b/pyModeS/adsb.py index b530f91..85cfa89 100644 --- a/pyModeS/adsb.py +++ b/pyModeS/adsb.py @@ -18,8 +18,7 @@ A python package for decoding ABS-D messages. """ import math -from . import util -from .util import crc +from pyModeS import util def df(msg): diff --git a/pyModeS/ehs.py b/pyModeS/ehs.py index 9a7a9df..b1446e8 100644 --- a/pyModeS/ehs.py +++ b/pyModeS/ehs.py @@ -17,8 +17,8 @@ A python package for decoding ModeS (DF20, DF21) messages. """ -from . import util -from .util import crc +from pyModeS import util +from pyModeS.util import crc def df(msg): diff --git a/tests/adsb_test.py b/tests/adsb_test.py new file mode 100644 index 0000000..75bc6cc --- /dev/null +++ b/tests/adsb_test.py @@ -0,0 +1,63 @@ +from pyModeS import adsb + + +# === TEST ADS-B package === + +def test_adsb_icao(): + assert adsb.icao("8D406B902015A678D4D220AA4BDA") == "406B90" + + +def test_adsb_category(): + assert adsb.category("8D406B902015A678D4D220AA4BDA") == 5 + + +def test_adsb_callsign(): + assert adsb.callsign("8D406B902015A678D4D220AA4BDA") == "EZY85MH_" + + +def test_adsb_position(): + pos = adsb.position("8D40058B58C901375147EFD09357", + "8D40058B58C904A87F402D3B8C59", + 1446332400, 1446332405) + assert pos == (49.81755, 6.08442) + + +def test_adsb_airborne_position_with_ref(): + pos = adsb.airborne_position_with_ref("8D40058B58C901375147EFD09357", + 49.0, 6.0) + assert pos == (49.82410, 6.06785) + pos = adsb.airborne_position_with_ref("8D40058B58C904A87F402D3B8C59", + 49.0, 6.0) + assert pos == (49.81755, 6.08442) + + +def test_adsb_surface_position_with_ref(): + pos = adsb.surface_position_with_ref("8FC8200A3AB8F5F893096B22B4A8", + -43.5, 172.5) + assert pos == (-43.48564, 175.87195) + + +def test_adsb_alt(): + assert adsb.altitude("8D40058B58C901375147EFD09357") == 39000 + + +def test_adsb_velocity(): + vgs = adsb.velocity("8D485020994409940838175B284F") + vas = adsb.velocity("8DA05F219B06B6AF189400CBC33F") + assert vgs == (159, 182.9, -14, 'GS') + assert vas == (376, 244.0, -37, 'AS') + + +def test_nic(): + assert adsb.nic('8D3C70A390AB11F55B8C57F65FE6') == 0 + assert adsb.nic('8DE1C9738A4A430B427D219C8225') == 1 + assert adsb.nic('8D44058880B50006B1773DC2A7E9') == 2 + assert adsb.nic('8D44058881B50006B1773DC2A7E9') == 3 + assert adsb.nic('8D4AB42A78000640000000FA0D0A') == 4 + assert adsb.nic('8D4405887099F5D9772F37F86CB6') == 5 + assert adsb.nic('8D4841A86841528E72D9B472DAC2') == 6 + assert adsb.nic('8D44057560B9760C0B840A51C89F') == 7 + assert adsb.nic('8D40621D58C382D690C8AC2863A7') == 8 + assert adsb.nic('8F48511C598D04F12CCF82451642') == 9 + assert adsb.nic('8DA4D53A50DBF8C6330F3B35458F') == 10 + assert adsb.nic('8D3C4ACF4859F1736F8E8ADF4D67') == 11 diff --git a/tests/decode_test_data.py b/tests/decode_test_data.py new file mode 100644 index 0000000..c925d4d --- /dev/null +++ b/tests/decode_test_data.py @@ -0,0 +1,75 @@ +# If you get import error run with ipython +from pyModeS import adsb +from pyModeS import ehs + + +# === Decode sample data file === + +def adsb_decode_all(n=None): + print "===== Decode all ADS-B sample data=====" + import csv + f = open('tests/adsb.csv', 'rt') + + msg0 = None + msg1 = None + + for i, r in enumerate(csv.reader(f)): + if n and i > n: + break + + ts = r[0] + m = r[1] + icao = adsb.icao(m) + tc = adsb.typecode(m) + if 1 <= tc <= 4: + print ts, m, icao, tc, adsb.category(m), adsb.callsign(m) + if tc == 19: + print ts, m, icao, tc, adsb.velocity(m) + if 5 <= tc <= 18: + if adsb.oe_flag(m): + msg1 = m + t1 = ts + else: + msg0 = m + t0 = ts + + if msg0 and msg1: + pos = adsb.position(msg0, msg1, t0, t1) + alt = adsb.altitude(m) + print ts, m, icao, tc, pos, alt + + +def ehs_decode_all(n=None): + print "===== Decode all Mode-S EHS sample data=====" + import csv + f = open('tests/ehs.csv', 'rt') + for i, r in enumerate(csv.reader(f)): + if n and i > n: + break + + ts = r[1] + m = r[2] + icao = ehs.icao(m) + vBDS = ehs.BDS(m) + + if vBDS: + if vBDS == "BDS20": + print ts, m, icao, vBDS, ehs.callsign(m) + + if vBDS == "BDS40": + print ts, m, icao, vBDS, ehs.alt_mcp(m), \ + ehs.alt_fms(m), ehs.pbaro(m) + + if vBDS == "BDS50": + print ts, m, icao, vBDS, ehs.roll(m), ehs.track(m), \ + ehs.gs(m), ehs.rtrack(m), ehs.tas(m) + + if vBDS == "BDS60": + print ts, m, icao, vBDS, ehs.heading(m), ehs.ias(m), \ + ehs.mach(m), ehs.baro_vr(m), ehs.ins_vr(m) + else: + print ts, m, icao, vBDS + +if __name__ == '__main__': + adsb_decode_all(100) + ehs_decode_all(100) diff --git a/tests/ehs_test.py b/tests/ehs_test.py new file mode 100644 index 0000000..9b6fbcc --- /dev/null +++ b/tests/ehs_test.py @@ -0,0 +1,42 @@ +from pyModeS import ehs + + +def test_ehs_icao(): + assert ehs.icao("A0001839CA3800315800007448D9") == '400940' + assert ehs.icao("A000139381951536E024D4CCF6B5") == '3C4DD2' + assert ehs.icao("A000029CFFBAA11E2004727281F1") == '4243D0' + + +def test_ehs_BDS(): + assert ehs.BDS("A0001838201584F23468207CDFA5") == 'BDS20' + assert ehs.BDS("A0001839CA3800315800007448D9") == 'BDS40' + assert ehs.BDS("A000139381951536E024D4CCF6B5") == 'BDS50' + assert ehs.BDS("A000029CFFBAA11E2004727281F1") == 'BDS60' + assert ehs.BDS("A0281838CAE9E12FA03FFF2DDDE5") is None + + +def test_ehs_BDS20_callsign(): + assert ehs.callsign("A000083E202CC371C31DE0AA1CCF") == 'KLM1017_' + assert ehs.callsign("A0001993202422F2E37CE038738E") == 'IBK2873_' + + +def test_ehs_BDS40_functions(): + assert ehs.alt_mcp("A000029C85E42F313000007047D3") == 3008 + assert ehs.alt_fms("A000029C85E42F313000007047D3") == 3008 + assert ehs.pbaro("A000029C85E42F313000007047D3") == 1020.0 + + +def test_ehs_BDS50_functions(): + assert ehs.roll("A000139381951536E024D4CCF6B5") == 2.1 + assert ehs.track("A000139381951536E024D4CCF6B5") == 114.3 + assert ehs.gs("A000139381951536E024D4CCF6B5") == 438 + assert ehs.rtrack("A000139381951536E024D4CCF6B5") == 0.125 + assert ehs.tas("A000139381951536E024D4CCF6B5") == 424 + + +def test_ehs_BDS60_functions(): + assert ehs.heading("A000029CFFBAA11E2004727281F1") == 180.9 + assert ehs.ias("A000029CFFBAA11E2004727281F1") == 336 + assert ehs.mach("A000029CFFBAA11E2004727281F1") == 0.48 + assert ehs.baro_vr("A000029CFFBAA11E2004727281F1") == 0 + assert ehs.ins_vr("A000029CFFBAA11E2004727281F1") == -3648 \ No newline at end of file diff --git a/tests/run.py b/tests/run.py deleted file mode 100644 index 5d9cbe3..0000000 --- a/tests/run.py +++ /dev/null @@ -1,202 +0,0 @@ -import os, sys, inspect -currentdir = os.path.dirname(os.path.abspath( - inspect.getfile(inspect.currentframe()))) -parentdir = os.path.dirname(currentdir) -sys.path.insert(0, parentdir) - -import pyModeS as pms -from pyModeS import adsb -from pyModeS import ehs -from pyModeS import util - - -# === TEST common functions === -def test_hex2bin(): - assert util.hex2bin('6E406B') == "011011100100000001101011" - - -def test_crc(): - # crc decoder - checksum = util.crc("8D406B902015A678D4D220AA4BDA") - assert checksum == "000000000000000000000000" - - # crc encoder - parity = util.crc("8D406B902015A678D4D220AA4BDA", encode=True) - assert util.hex2bin("AA4BDA") == parity - - -# === TEST ADS-B package === - -def test_adsb_icao(): - assert adsb.icao("8D406B902015A678D4D220AA4BDA") == "406B90" - - -def test_adsb_category(): - assert adsb.category("8D406B902015A678D4D220AA4BDA") == 5 - - -def test_adsb_callsign(): - assert adsb.callsign("8D406B902015A678D4D220AA4BDA") == "EZY85MH_" - - -def test_adsb_airborne_position(): - pos = adsb.airborne_position("8D40058B58C901375147EFD09357", - "8D40058B58C904A87F402D3B8C59", - 1446332400, 1446332405) - assert pos == (49.81755, 6.08442) - - -def test_adsb_airborne_position_with_ref(): - pos = adsb.airborne_position_with_ref("8D40058B58C901375147EFD09357", - 49.0, 6.0) - assert pos == (49.82410, 6.06785) - pos = adsb.airborne_position_with_ref("8D40058B58C904A87F402D3B8C59", - 49.0, 6.0) - assert pos == (49.81755, 6.08442) - - -def test_adsb_surface_position_with_ref(): - pos = adsb.surface_position_with_ref("8FC8200A3AB8F5F893096B22B4A8", - -43.5, 172.5) - assert pos == (-43.48564, 175.87195) - - -def test_adsb_alt(): - assert adsb.altitude("8D40058B58C901375147EFD09357") == 39000 - - -def test_adsb_velocity(): - vgs = adsb.velocity("8D485020994409940838175B284F") - vas = adsb.velocity("8DA05F219B06B6AF189400CBC33F") - assert vgs == (159, 182.9, -14, 'GS') - assert vas == (376, 244.0, -37, 'AS') - - -def test_nic(): - assert adsb.nic('8D3C70A390AB11F55B8C57F65FE6') == 0 - assert adsb.nic('8DE1C9738A4A430B427D219C8225') == 1 - assert adsb.nic('8D44058880B50006B1773DC2A7E9') == 2 - assert adsb.nic('8D44058881B50006B1773DC2A7E9') == 3 - assert adsb.nic('8D4AB42A78000640000000FA0D0A') == 4 - assert adsb.nic('8D4405887099F5D9772F37F86CB6') == 5 - assert adsb.nic('8D4841A86841528E72D9B472DAC2') == 6 - assert adsb.nic('8D44057560B9760C0B840A51C89F') == 7 - assert adsb.nic('8D40621D58C382D690C8AC2863A7') == 8 - assert adsb.nic('8F48511C598D04F12CCF82451642') == 9 - assert adsb.nic('8DA4D53A50DBF8C6330F3B35458F') == 10 - assert adsb.nic('8D3C4ACF4859F1736F8E8ADF4D67') == 11 - - -# === TEST Mode-S EHS package === - -def test_ehs_icao(): - assert ehs.icao("A0001839CA3800315800007448D9") == '400940' - assert ehs.icao("A000139381951536E024D4CCF6B5") == '3C4DD2' - assert ehs.icao("A000029CFFBAA11E2004727281F1") == '4243D0' - - -def test_ehs_BDS(): - assert ehs.BDS("A0001838201584F23468207CDFA5") == 'BDS20' - assert ehs.BDS("A0001839CA3800315800007448D9") == 'BDS40' - assert ehs.BDS("A000139381951536E024D4CCF6B5") == 'BDS50' - assert ehs.BDS("A000029CFFBAA11E2004727281F1") == 'BDS60' - assert ehs.BDS("A0281838CAE9E12FA03FFF2DDDE5") is None - - -def test_ehs_BDS20_callsign(): - assert ehs.callsign("A000083E202CC371C31DE0AA1CCF") == 'KLM1017_' - assert ehs.callsign("A0001993202422F2E37CE038738E") == 'IBK2873_' - - -def test_ehs_BDS40_functions(): - assert ehs.alt_mcp("A000029C85E42F313000007047D3") == 3008 - assert ehs.alt_fms("A000029C85E42F313000007047D3") == 3008 - assert ehs.pbaro("A000029C85E42F313000007047D3") == 1020.0 - - -def test_ehs_BDS50_functions(): - assert ehs.roll("A000139381951536E024D4CCF6B5") == 2.1 - assert ehs.track("A000139381951536E024D4CCF6B5") == 114.3 - assert ehs.gs("A000139381951536E024D4CCF6B5") == 438 - assert ehs.rtrack("A000139381951536E024D4CCF6B5") == 0.125 - assert ehs.tas("A000139381951536E024D4CCF6B5") == 424 - - -def test_ehs_BDS60_functions(): - assert ehs.heading("A000029CFFBAA11E2004727281F1") == 180.9 - assert ehs.ias("A000029CFFBAA11E2004727281F1") == 336 - assert ehs.mach("A000029CFFBAA11E2004727281F1") == 0.48 - assert ehs.baro_vr("A000029CFFBAA11E2004727281F1") == 0 - assert ehs.ins_vr("A000029CFFBAA11E2004727281F1") == -3648 - - -# === Decode sample data file === - -def adsb_decode_all(n=None): - print("===== Decode all ADS-B sample data=====") - import csv - f = open('adsb.csv', 'rt') - - msg0 = None - msg1 = None - - for i, r in enumerate(csv.reader(f)): - if n and i > n: - break - - ts = r[0] - m = r[1] - icao = adsb.icao(m) - tc = adsb.typecode(m) - if 1 <= tc <= 4: - print(ts, m, icao, tc, adsb.category(m), adsb.callsign(m)) - if tc == 19: - print(ts, m, icao, tc, adsb.velocity(m)) - if 5 <= tc <= 18: - if adsb.oe_flag(m): - msg1 = m - t1 = ts - else: - msg0 = m - t0 = ts - - if msg0 and msg1: - pos = adsb.position(msg0, msg1, t0, t1) - alt = adsb.altitude(m) - print(ts, m, icao, tc, pos, alt) - - -def ehs_decode_all(n=None): - print("===== Decode all Mode-S EHS sample data=====") - import csv - f = open('ehs.csv', 'rt') - for i, r in enumerate(csv.reader(f)): - if n and i > n: - break - - ts = r[1] - m = r[2] - icao = ehs.icao(m) - vBDS = ehs.BDS(m) - - if vBDS: - if vBDS == "BDS20": - print(ts, m, icao, vBDS, ehs.callsign(m)) - - if vBDS == "BDS40": - print(ts, m, icao, vBDS, ehs.alt_mcp(m), \ - ehs.alt_fms(m), ehs.pbaro(m)) - - if vBDS == "BDS50": - print(ts, m, icao, vBDS, ehs.roll(m), ehs.track(m), \ - ehs.gs(m), ehs.rtrack(m), ehs.tas(m)) - - if vBDS == "BDS60": - print(ts, m, icao, vBDS, ehs.heading(m), ehs.ias(m), \ - ehs.mach(m), ehs.baro_vr(m), ehs.ins_vr(m)) - else: - print(ts, m, icao, vBDS) - -if __name__ == '__main__': - adsb_decode_all(100) - ehs_decode_all(100) diff --git a/tests/util_test.py b/tests/util_test.py new file mode 100644 index 0000000..758bf4e --- /dev/null +++ b/tests/util_test.py @@ -0,0 +1,15 @@ +from pyModeS import util + + +def test_hex2bin(): + assert util.hex2bin('6E406B') == "011011100100000001101011" + + +def test_crc_decode(): + checksum = util.crc("8D406B902015A678D4D220AA4BDA") + assert checksum == "000000000000000000000000" + + +def test_crc_encode(): + parity = util.crc("8D406B902015A678D4D220AA4BDA", encode=True) + assert util.hex2bin("AA4BDA") == parity \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..8afc68f --- /dev/null +++ b/tox.ini @@ -0,0 +1,5 @@ +[tox] +envlist = py26,py27,py35 +[testenv] +deps=pytest +commands=py.test