Compare commits
3 Commits
adsb_encod
...
v2.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228306dd5f | ||
|
|
1c6b39322f | ||
|
|
9dde1b63d6 |
5
Makefile
5
Makefile
@@ -8,11 +8,12 @@ ext:
|
||||
python setup.py build_ext --inplace
|
||||
|
||||
test:
|
||||
python setup.py build_ext --inplace
|
||||
python -m pytest tests
|
||||
|
||||
clean:
|
||||
find pyModeS/decoder -type f -name '*.c' -delete
|
||||
find pyModeS/decoder -type f -name '*.so' -delete
|
||||
find pyModeS -type f -name '*.c' -delete
|
||||
find pyModeS -type f -name '*.so' -delete
|
||||
find . | grep -E "(__pycache__|\.pyc|\.pyo$$)" | xargs rm -rf
|
||||
rm -rf *.egg-info
|
||||
rm -rf .pytest_cache
|
||||
|
||||
@@ -5,8 +5,8 @@ try:
|
||||
from . import c_common as common
|
||||
from .c_common import *
|
||||
except:
|
||||
from . import common
|
||||
from .common import *
|
||||
from . import py_common as common
|
||||
from .py_common import *
|
||||
|
||||
from .decoder import tell
|
||||
from .decoder import adsb
|
||||
|
||||
@@ -5,7 +5,8 @@ cdef unsigned char int_to_char(unsigned char i)
|
||||
|
||||
cpdef str hex2bin(str hexstr)
|
||||
cpdef long bin2int(str binstr)
|
||||
cpdef long hex2int(str binstr)
|
||||
cpdef long hex2int(str hexstr)
|
||||
cpdef str bin2hex(str binstr)
|
||||
|
||||
cpdef unsigned char df(str msg)
|
||||
cpdef long crc(str msg, bint encode=*)
|
||||
|
||||
@@ -66,6 +66,11 @@ cpdef long hex2int(str hexstr):
|
||||
cumul = 16*cumul + char_to_int(v_hexstr[i])
|
||||
return cumul
|
||||
|
||||
@cython.boundscheck(False)
|
||||
cpdef str bin2hex(str binstr):
|
||||
return "{0:X}".format(int(binstr, 2))
|
||||
|
||||
|
||||
@cython.boundscheck(False)
|
||||
cpdef unsigned char df(str msg):
|
||||
"""Decode Downlink Format vaule, bits 1 to 5."""
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
from .bds.bds08 import me08
|
||||
from .bds.bds09 import me09
|
||||
from pyModeS import common
|
||||
|
||||
|
||||
def encode_adsb(**kwargs):
|
||||
"""Encode ADS-B message.
|
||||
|
||||
Args:
|
||||
icao (string): Transponder ICAO address (6 hexdigits)
|
||||
capability (int): Transponder capability, between 0 and 7
|
||||
typecode (int): Typecode, less than 32
|
||||
|
||||
callsign (string): Callsign (6 hexdigits)
|
||||
category (int): Aircraft category, between 0 and 7, Default to 0.
|
||||
|
||||
speed (int): Speed in knots.
|
||||
angle (float): Track angle or heading angle in degrees.
|
||||
vertical_rate (int): vertical rate in feet/minute
|
||||
intent_change (int): Intent change flag, 0 or 1. Default to 0.
|
||||
ifr_capability (int): IFR capability flag, 0 or 1. Default to 1.
|
||||
navigation_quality (int): NUC (ver 0) or NACv (ver 1, 2), between 0 and 7.
|
||||
Default to 0.
|
||||
supersonic (bool): Is this a supersonic flight? Default to False.
|
||||
speed_type (str): Speed type: GS, IAS, or TAS. Default to GS.
|
||||
vertical_rate_source (str): GNSS or BARO. Default to BARO.
|
||||
gnss_baro_alt_diff (int): Different between GNSS and barometric altitude in feet.
|
||||
Negative value indicates GNSS altitude below barometric altitude. Default to 0
|
||||
|
||||
Returns:
|
||||
string: 28 hexdigits raw message
|
||||
|
||||
"""
|
||||
tc = kwargs.get("typecode")
|
||||
|
||||
if 1 <= tc <= 4:
|
||||
me = me08(**kwargs)
|
||||
elif tc == 19:
|
||||
me = me09(**kwargs)
|
||||
|
||||
msg = _constuct(**dict(kwargs, me=me))
|
||||
return msg
|
||||
|
||||
|
||||
def _constuct(**kwargs):
|
||||
icao = kwargs.get("icao")
|
||||
me = kwargs.get("me")
|
||||
capability = kwargs.get("capability", 6)
|
||||
|
||||
if icao is None or len(icao) != 6:
|
||||
raise Exception("Transponder address must be 6 hexadecimal characters.")
|
||||
|
||||
if me is None or len(me) != 14:
|
||||
raise Exception("Message be 14 hexadecimal characters.")
|
||||
|
||||
if capability > 6:
|
||||
raise Exception("Transponder capability must be smaller than 7.")
|
||||
|
||||
header_bin = "10001" + "{0:03b}".format(capability)
|
||||
header_hex = "{0:02X}".format(int(header_bin, 2))
|
||||
|
||||
msg = header_hex + icao + me + "000000"
|
||||
|
||||
pi = common.crc(msg, encode=True)
|
||||
pi_hex = "{0:06X}".format(pi)
|
||||
|
||||
msg = msg[:-6] + pi_hex
|
||||
return msg
|
||||
@@ -1,5 +0,0 @@
|
||||
# ------------------------------------------
|
||||
# BDS 0,5
|
||||
# ADS-B TC=9-18
|
||||
# Airborn position
|
||||
# ------------------------------------------
|
||||
@@ -1,5 +0,0 @@
|
||||
# ------------------------------------------
|
||||
# BDS 0,6
|
||||
# ADS-B TC=5-8
|
||||
# Surface position
|
||||
# ------------------------------------------
|
||||
@@ -1,40 +0,0 @@
|
||||
# ------------------------------------------
|
||||
# BDS 0,8
|
||||
# ADS-B TC=1-4
|
||||
# Aircraft identitification and category
|
||||
# ------------------------------------------
|
||||
|
||||
from pyModeS import common
|
||||
|
||||
charmap = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######"
|
||||
|
||||
|
||||
def me08(callsign, **kwargs):
|
||||
cs = callsign
|
||||
tc = kwargs.get("typecode")
|
||||
cat = kwargs.get("category", 0)
|
||||
|
||||
if len(cs) > 8:
|
||||
raise Exception("callsign must contain less than 9 characters")
|
||||
|
||||
if tc > 4:
|
||||
raise Exception("typecode must be less 5")
|
||||
|
||||
if cat > 7:
|
||||
raise Exception("category must be less 8")
|
||||
|
||||
if not cs.isalnum():
|
||||
raise Exception("callsign must only contain alphanumeric characters")
|
||||
|
||||
cs = "{:<8}".format(cs.upper())
|
||||
|
||||
idx = [charmap.index(c) for c in cs]
|
||||
me_bin = (
|
||||
"{0:05b}".format(tc)
|
||||
+ "{0:03b}".format(cat)
|
||||
+ "".join("{0:06b}".format(i) for i in idx)
|
||||
)
|
||||
|
||||
me_hex = "{0:04X}".format(int(me_bin, 2))
|
||||
|
||||
return me_hex
|
||||
@@ -1,119 +0,0 @@
|
||||
# ------------------------------------------
|
||||
# BDS 0,9
|
||||
# ADS-B TC=19
|
||||
# Aircraft Airborn velocity
|
||||
# ------------------------------------------
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def me09(speed, angle, vertical_rate, **kwargs):
|
||||
spd = speed
|
||||
agl = angle
|
||||
vr = vertical_rate
|
||||
|
||||
tc = kwargs.get("typecode")
|
||||
intent = kwargs.get("intent_change", 0)
|
||||
ifr = kwargs.get("ifr_capability", 1)
|
||||
navq = kwargs.get("navigation_quality", 0)
|
||||
supersonic = kwargs.get("supersonic", False)
|
||||
spd_type = kwargs.get("speed_type", "gs").lower()
|
||||
vr_source = kwargs.get("vertical_rate_source", "baro").lower()
|
||||
alt_diff = kwargs.get("gnss_baro_alt_diff", 0)
|
||||
|
||||
if tc != 19:
|
||||
raise Exception("Typecode must be 19.")
|
||||
|
||||
if intent not in (0, 1):
|
||||
raise Exception("Intent change flag must be 0 or 1.")
|
||||
|
||||
if ifr not in (0, 1):
|
||||
raise Exception("IFR capability flag must be 0 or 1.")
|
||||
|
||||
if type(supersonic) != bool:
|
||||
raise Exception("Subsonic flag must be True or False.")
|
||||
|
||||
if navq > 7:
|
||||
raise Exception("Navigation quality indicator must be smaller than 8.")
|
||||
|
||||
if spd_type not in ["gs", "tas"]:
|
||||
raise Exception("Speed type must be 'gs', 'ias', or 'tas'.")
|
||||
|
||||
if vr_source not in ["baro", "gnss"]:
|
||||
raise Exception("Vertical rate source must be 'baro' or 'gnss'.")
|
||||
|
||||
me_bin = ""
|
||||
|
||||
# typecode
|
||||
me_bin += "{0:05b}".format(tc)
|
||||
|
||||
# sub-type
|
||||
if supersonic:
|
||||
if spd_type == "gs":
|
||||
me_bin += "010"
|
||||
else:
|
||||
me_bin += "100"
|
||||
else:
|
||||
if spd_type == "gs":
|
||||
me_bin += "001"
|
||||
else:
|
||||
me_bin += "011"
|
||||
|
||||
# intent, ifr, navigation quality
|
||||
me_bin += str(intent) + str(ifr) + "{0:03b}".format(navq)
|
||||
|
||||
# speed and angle part
|
||||
if spd_type == "gs":
|
||||
vx = spd * np.sin(np.radians(agl))
|
||||
vy = spd * np.cos(np.radians(agl))
|
||||
|
||||
if supersonic:
|
||||
vx /= 4
|
||||
vy /= 4
|
||||
|
||||
vx = int(round(vx))
|
||||
vy = int(round(vy))
|
||||
|
||||
sew = "0" if vx >= 0 else "1"
|
||||
sns = "0" if vy >= 0 else "1"
|
||||
vew = "{0:010b}".format(min(abs(vx), 1023) + 1)
|
||||
vns = "{0:010b}".format(min(abs(vy), 1023) + 1)
|
||||
|
||||
me_bin += sew + vew + sns + vns
|
||||
|
||||
elif spd_type == "ias" or spd_type == "tas":
|
||||
hdg = int(round(agl * 1024 / 360))
|
||||
hdg = min(hdg, 1023)
|
||||
|
||||
air_type = "1" if spd_type == "tas" else "0"
|
||||
|
||||
if supersonic:
|
||||
spd /= 4
|
||||
|
||||
spd = min(int(round(spd)), 1023)
|
||||
|
||||
me_bin += "1" + "{0:010b}".format(hdg) + air_type + "{0:010b}".format(spd)
|
||||
|
||||
# vertical rate source
|
||||
me_bin += "1" if vr_source == "baro" else "0"
|
||||
|
||||
# vertical rate
|
||||
me_bin += "0" if vr > 0 else "1"
|
||||
vr = int(round((abs(vr) / 64 + 1)))
|
||||
vr = min(vr, 511)
|
||||
me_bin += "{0:09b}".format(vr)
|
||||
|
||||
# reserved
|
||||
me_bin += "00"
|
||||
|
||||
# altitude difference
|
||||
me_bin += "1" if alt_diff < 0 else "0"
|
||||
alt_diff = int(round(abs(alt_diff) / 25 + 1))
|
||||
alt_diff = min(alt_diff, 127)
|
||||
me_bin += "{0:07b}".format(alt_diff)
|
||||
print(me_bin)
|
||||
|
||||
# convert to hexdigits
|
||||
me_hex = "{0:04X}".format(int(me_bin, 2))
|
||||
|
||||
return me_hex
|
||||
@@ -19,6 +19,11 @@ def bin2int(binstr):
|
||||
return int(binstr, 2)
|
||||
|
||||
|
||||
def bin2hex(binstr):
|
||||
"""Convert a binary string to hexdecimal string."""
|
||||
return "{0:X}".format(int(binstr, 2))
|
||||
|
||||
|
||||
def df(msg):
|
||||
"""Decode Downlink Format value, bits 1 to 5."""
|
||||
dfbin = hex2bin(msg[:2])
|
||||
79
setup.py
79
setup.py
@@ -8,20 +8,12 @@ Steps for deploying a new version:
|
||||
1. Increase the version number
|
||||
2. remove the old deployment under [dist] and [build] folder
|
||||
3. run: python setup.py sdist
|
||||
run: python setup.py bdist_wheel --universal
|
||||
4. twine upload dist/*
|
||||
"""
|
||||
|
||||
# Always prefer setuptools over distutils
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
# Compile some parts
|
||||
from setuptools.extension import Extension
|
||||
from Cython.Build import cythonize
|
||||
|
||||
extensions = [Extension("pyModeS.c_common", ["pyModeS/c_common.pyx"])]
|
||||
|
||||
|
||||
# To use a consistent encoding
|
||||
from codecs import open
|
||||
from os import path
|
||||
@@ -32,78 +24,37 @@ here = path.abspath(path.dirname(__file__))
|
||||
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
|
||||
long_description = f.read()
|
||||
|
||||
setup(
|
||||
|
||||
details = dict(
|
||||
name="pyModeS",
|
||||
# Versions should comply with PEP440. For a discussion on single-sourcing
|
||||
# the version across setup.py and the project code, see
|
||||
# https://packaging.python.org/en/latest/single_source_version.html
|
||||
version="2.5",
|
||||
version="2.8",
|
||||
description="Python Mode-S and ADS-B Decoder",
|
||||
long_description=long_description,
|
||||
# The project's main homepage.
|
||||
url="https://github.com/junzis/pyModeS",
|
||||
# Author details
|
||||
author="Junzi Sun",
|
||||
author_email="j.sun-1@tudelft.nl",
|
||||
# Choose your license
|
||||
license="GNU GPL v3",
|
||||
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||
classifiers=[
|
||||
# How mature is this project? Common values are
|
||||
# 3 - Alpha
|
||||
# 4 - Beta
|
||||
# 5 - Production/Stable
|
||||
"Development Status :: 4 - Beta",
|
||||
# Indicate who your project is intended for
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
# Pick your license as you wish (should match "license" above)
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
# Specify the Python versions you support here. In particular, ensure
|
||||
# that you indicate whether you support Python 2, Python 3 or both.
|
||||
# "Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 3",
|
||||
],
|
||||
ext_modules=cythonize(extensions),
|
||||
# What does your project relate to?
|
||||
keywords="Mode-S ADS-B EHS ELS Comm-B",
|
||||
# You can just specify the packages manually here if your project is
|
||||
# simple. Or you can use find_packages().
|
||||
packages=find_packages(exclude=["contrib", "docs", "tests"]),
|
||||
# Alternatively, if you want to distribute just a my_module.py, uncomment
|
||||
# this:
|
||||
# py_modules=["my_module"],
|
||||
# List run-time dependencies here. These will be installed by pip when
|
||||
# your project is installed. For an analysis of "install_requires" vs pip's
|
||||
# requirements files see:
|
||||
# https://packaging.python.org/en/latest/requirements.html
|
||||
install_requires=["numpy", "pyzmq", "pyrtlsdr"],
|
||||
# List additional groups of dependencies here (e.g. development
|
||||
# dependencies). You can install these using the following syntax,
|
||||
# for example:
|
||||
# $ pip install -e .[dev,test]
|
||||
# extras_require={
|
||||
# 'dev': ['check-manifest'],
|
||||
# 'test': ['coverage'],
|
||||
# },
|
||||
# If there are data files included in your packages that need to be
|
||||
# installed, specify them here. If using Python 2.6 or less, then these
|
||||
# have to be included in MANIFEST.in as well.
|
||||
# package_data={
|
||||
# 'sample': ['package_data.dat'],
|
||||
# },
|
||||
# Although 'package_data' is the preferred approach, in some case you may
|
||||
# need to place data files outside of your packages. See:
|
||||
# http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa
|
||||
# In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
|
||||
# data_files=[('my_data', ['data/data_file'])],
|
||||
# To provide executable scripts, use entry points in preference to the
|
||||
# "scripts" keyword. Entry points provide cross-platform support and allow
|
||||
# pip to create the appropriate form of executable for the target platform.
|
||||
# entry_points={
|
||||
# 'console_scripts': [
|
||||
# 'sample=sample:main',
|
||||
# ],
|
||||
# },
|
||||
package_data={"pyModeS": ["*.pyx", "*.pxd"]},
|
||||
scripts=["pyModeS/streamer/modeslive"],
|
||||
)
|
||||
|
||||
try:
|
||||
from setuptools.extension import Extension
|
||||
from Cython.Build import cythonize
|
||||
|
||||
extensions = [Extension("pyModeS.c_common", ["pyModeS/c_common.pyx"])]
|
||||
|
||||
setup(**dict(details, ext_modules=cythonize(extensions)))
|
||||
|
||||
except:
|
||||
setup(**details)
|
||||
|
||||
@@ -1,58 +1,62 @@
|
||||
try:
|
||||
from pyModeS.decoder import c_common as common
|
||||
|
||||
def test_conversions():
|
||||
assert common.hex2bin("6E406B") == "011011100100000001101011"
|
||||
|
||||
def test_crc_decode():
|
||||
|
||||
assert common.crc("8D406B902015A678D4D220AA4BDA") == 0
|
||||
assert common.crc("8d8960ed58bf053cf11bc5932b7d") == 0
|
||||
assert common.crc("8d45cab390c39509496ca9a32912") == 0
|
||||
assert common.crc("8d74802958c904e6ef4ba0184d5c") == 0
|
||||
assert common.crc("8d4400cd9b0000b4f87000e71a10") == 0
|
||||
assert common.crc("8d4065de58a1054a7ef0218e226a") == 0
|
||||
|
||||
assert common.crc("c80b2dca34aa21dd821a04cb64d4") == 10719924
|
||||
assert common.crc("a800089d8094e33a6004e4b8a522") == 4805588
|
||||
assert common.crc("a8000614a50b6d32bed000bbe0ed") == 5659991
|
||||
assert common.crc("a0000410bc900010a40000f5f477") == 11727682
|
||||
assert common.crc("8d4ca251204994b1c36e60a5343d") == 16
|
||||
assert common.crc("b0001718c65632b0a82040715b65") == 353333
|
||||
|
||||
def test_crc_encode():
|
||||
parity = common.crc("8D406B902015A678D4D220AA4BDA", encode=True)
|
||||
assert parity == 11160538
|
||||
|
||||
def test_icao():
|
||||
assert common.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
|
||||
assert common.icao("A0001839CA3800315800007448D9") == "400940"
|
||||
assert common.icao("A000139381951536E024D4CCF6B5") == "3C4DD2"
|
||||
assert common.icao("A000029CFFBAA11E2004727281F1") == "4243D0"
|
||||
|
||||
def test_modes_altcode():
|
||||
assert common.altcode("A02014B400000000000000F9D514") == 32300
|
||||
|
||||
def test_modes_idcode():
|
||||
assert common.idcode("A800292DFFBBA9383FFCEB903D01") == "1346"
|
||||
|
||||
def test_graycode_to_altitude():
|
||||
assert common.gray2alt("00000000010") == -1000
|
||||
assert common.gray2alt("00000001010") == -500
|
||||
assert common.gray2alt("00000011011") == -100
|
||||
assert common.gray2alt("00000011010") == 0
|
||||
assert common.gray2alt("00000011110") == 100
|
||||
assert common.gray2alt("00000010011") == 600
|
||||
assert common.gray2alt("00000110010") == 1000
|
||||
assert common.gray2alt("00001001001") == 5800
|
||||
assert common.gray2alt("00011100100") == 10300
|
||||
assert common.gray2alt("01100011010") == 32000
|
||||
assert common.gray2alt("01110000100") == 46300
|
||||
assert common.gray2alt("01010101100") == 50200
|
||||
assert common.gray2alt("11011110100") == 73200
|
||||
assert common.gray2alt("10000000011") == 126600
|
||||
assert common.gray2alt("10000000001") == 126700
|
||||
from pyModeS import c_common
|
||||
|
||||
|
||||
except:
|
||||
pass
|
||||
def test_conversions():
|
||||
assert c_common.hex2bin("6E") == "01101110"
|
||||
assert c_common.bin2hex("01101110") == "6E"
|
||||
assert c_common.bin2hex("1101110") == "6E"
|
||||
|
||||
|
||||
def test_crc_decode():
|
||||
|
||||
assert c_common.crc("8D406B902015A678D4D220AA4BDA") == 0
|
||||
assert c_common.crc("8d8960ed58bf053cf11bc5932b7d") == 0
|
||||
assert c_common.crc("8d45cab390c39509496ca9a32912") == 0
|
||||
assert c_common.crc("8d74802958c904e6ef4ba0184d5c") == 0
|
||||
assert c_common.crc("8d4400cd9b0000b4f87000e71a10") == 0
|
||||
assert c_common.crc("8d4065de58a1054a7ef0218e226a") == 0
|
||||
|
||||
assert c_common.crc("c80b2dca34aa21dd821a04cb64d4") == 10719924
|
||||
assert c_common.crc("a800089d8094e33a6004e4b8a522") == 4805588
|
||||
assert c_common.crc("a8000614a50b6d32bed000bbe0ed") == 5659991
|
||||
assert c_common.crc("a0000410bc900010a40000f5f477") == 11727682
|
||||
assert c_common.crc("8d4ca251204994b1c36e60a5343d") == 16
|
||||
assert c_common.crc("b0001718c65632b0a82040715b65") == 353333
|
||||
|
||||
|
||||
def test_crc_encode():
|
||||
parity = c_common.crc("8D406B902015A678D4D220AA4BDA", encode=True)
|
||||
assert parity == 11160538
|
||||
|
||||
|
||||
def test_icao():
|
||||
assert c_common.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
|
||||
assert c_common.icao("A0001839CA3800315800007448D9") == "400940"
|
||||
assert c_common.icao("A000139381951536E024D4CCF6B5") == "3C4DD2"
|
||||
assert c_common.icao("A000029CFFBAA11E2004727281F1") == "4243D0"
|
||||
|
||||
|
||||
def test_modes_altcode():
|
||||
assert c_common.altcode("A02014B400000000000000F9D514") == 32300
|
||||
|
||||
|
||||
def test_modes_idcode():
|
||||
assert c_common.idcode("A800292DFFBBA9383FFCEB903D01") == "1346"
|
||||
|
||||
|
||||
def test_graycode_to_altitude():
|
||||
assert c_common.gray2alt("00000000010") == -1000
|
||||
assert c_common.gray2alt("00000001010") == -500
|
||||
assert c_common.gray2alt("00000011011") == -100
|
||||
assert c_common.gray2alt("00000011010") == 0
|
||||
assert c_common.gray2alt("00000011110") == 100
|
||||
assert c_common.gray2alt("00000010011") == 600
|
||||
assert c_common.gray2alt("00000110010") == 1000
|
||||
assert c_common.gray2alt("00001001001") == 5800
|
||||
assert c_common.gray2alt("00011100100") == 10300
|
||||
assert c_common.gray2alt("01100011010") == 32000
|
||||
assert c_common.gray2alt("01110000100") == 46300
|
||||
assert c_common.gray2alt("01010101100") == 50200
|
||||
assert c_common.gray2alt("11011110100") == 73200
|
||||
assert c_common.gray2alt("10000000011") == 126600
|
||||
assert c_common.gray2alt("10000000001") == 126700
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
from pyModeS import common
|
||||
|
||||
|
||||
def test_conversions():
|
||||
assert common.hex2bin("6E406B") == "011011100100000001101011"
|
||||
|
||||
|
||||
def test_crc_decode():
|
||||
assert common.crc_legacy("8D406B902015A678D4D220AA4BDA") == 0
|
||||
|
||||
assert common.crc("8D406B902015A678D4D220AA4BDA") == 0
|
||||
assert common.crc("8d8960ed58bf053cf11bc5932b7d") == 0
|
||||
assert common.crc("8d45cab390c39509496ca9a32912") == 0
|
||||
assert common.crc("8d49d3d4e1089d00000000744c3b") == 0
|
||||
assert common.crc("8d74802958c904e6ef4ba0184d5c") == 0
|
||||
assert common.crc("8d4400cd9b0000b4f87000e71a10") == 0
|
||||
assert common.crc("8d4065de58a1054a7ef0218e226a") == 0
|
||||
|
||||
assert common.crc("c80b2dca34aa21dd821a04cb64d4") == 10719924
|
||||
assert common.crc("a800089d8094e33a6004e4b8a522") == 4805588
|
||||
assert common.crc("a8000614a50b6d32bed000bbe0ed") == 5659991
|
||||
assert common.crc("a0000410bc900010a40000f5f477") == 11727682
|
||||
assert common.crc("8d4ca251204994b1c36e60a5343d") == 16
|
||||
assert common.crc("b0001718c65632b0a82040715b65") == 353333
|
||||
|
||||
|
||||
def test_crc_encode():
|
||||
parity = common.crc("8D406B902015A678D4D220AA4BDA", encode=True)
|
||||
assert parity == 11160538
|
||||
|
||||
|
||||
def test_icao():
|
||||
assert common.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
|
||||
assert common.icao("A0001839CA3800315800007448D9") == "400940"
|
||||
assert common.icao("A000139381951536E024D4CCF6B5") == "3C4DD2"
|
||||
assert common.icao("A000029CFFBAA11E2004727281F1") == "4243D0"
|
||||
|
||||
|
||||
def test_modes_altcode():
|
||||
assert common.altcode("A02014B400000000000000F9D514") == 32300
|
||||
|
||||
|
||||
def test_modes_idcode():
|
||||
assert common.idcode("A800292DFFBBA9383FFCEB903D01") == "1346"
|
||||
|
||||
|
||||
def test_graycode_to_altitude():
|
||||
assert common.gray2alt("00000000010") == -1000
|
||||
assert common.gray2alt("00000001010") == -500
|
||||
assert common.gray2alt("00000011011") == -100
|
||||
assert common.gray2alt("00000011010") == 0
|
||||
assert common.gray2alt("00000011110") == 100
|
||||
assert common.gray2alt("00000010011") == 600
|
||||
assert common.gray2alt("00000110010") == 1000
|
||||
assert common.gray2alt("00001001001") == 5800
|
||||
assert common.gray2alt("00011100100") == 10300
|
||||
assert common.gray2alt("01100011010") == 32000
|
||||
assert common.gray2alt("01110000100") == 46300
|
||||
assert common.gray2alt("01010101100") == 50200
|
||||
assert common.gray2alt("11011110100") == 73200
|
||||
assert common.gray2alt("10000000011") == 126600
|
||||
assert common.gray2alt("10000000001") == 126700
|
||||
@@ -1,23 +0,0 @@
|
||||
from pyModeS import encoder
|
||||
|
||||
|
||||
def test_identification():
|
||||
msg = encoder.encode_adsb(
|
||||
icao="406B90", typecode=4, capability=5, category=0, callsign="EZY85MH"
|
||||
)
|
||||
assert msg == "8D406B902015A678D4D220AA4BDA"
|
||||
|
||||
|
||||
def test_speed():
|
||||
msg = encoder.encode_adsb(
|
||||
icao="485020",
|
||||
typecode=19,
|
||||
capability=5,
|
||||
speed_type="gs",
|
||||
speed=159,
|
||||
angle=182.88,
|
||||
vertical_rate=-832,
|
||||
vertical_rate_source="gnss",
|
||||
gnss_baro_alt_diff=550,
|
||||
)
|
||||
assert msg == "8D485020994409940838175B284F"
|
||||
64
tests/test_py_common.py
Normal file
64
tests/test_py_common.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from pyModeS import py_common
|
||||
|
||||
|
||||
def test_conversions():
|
||||
assert py_common.hex2bin("6E") == "01101110"
|
||||
assert py_common.bin2hex("01101110") == "6E"
|
||||
assert py_common.bin2hex("1101110") == "6E"
|
||||
|
||||
|
||||
def test_crc_decode():
|
||||
assert py_common.crc_legacy("8D406B902015A678D4D220AA4BDA") == 0
|
||||
|
||||
assert py_common.crc("8D406B902015A678D4D220AA4BDA") == 0
|
||||
assert py_common.crc("8d8960ed58bf053cf11bc5932b7d") == 0
|
||||
assert py_common.crc("8d45cab390c39509496ca9a32912") == 0
|
||||
assert py_common.crc("8d49d3d4e1089d00000000744c3b") == 0
|
||||
assert py_common.crc("8d74802958c904e6ef4ba0184d5c") == 0
|
||||
assert py_common.crc("8d4400cd9b0000b4f87000e71a10") == 0
|
||||
assert py_common.crc("8d4065de58a1054a7ef0218e226a") == 0
|
||||
|
||||
assert py_common.crc("c80b2dca34aa21dd821a04cb64d4") == 10719924
|
||||
assert py_common.crc("a800089d8094e33a6004e4b8a522") == 4805588
|
||||
assert py_common.crc("a8000614a50b6d32bed000bbe0ed") == 5659991
|
||||
assert py_common.crc("a0000410bc900010a40000f5f477") == 11727682
|
||||
assert py_common.crc("8d4ca251204994b1c36e60a5343d") == 16
|
||||
assert py_common.crc("b0001718c65632b0a82040715b65") == 353333
|
||||
|
||||
|
||||
def test_crc_encode():
|
||||
parity = py_common.crc("8D406B902015A678D4D220AA4BDA", encode=True)
|
||||
assert parity == 11160538
|
||||
|
||||
|
||||
def test_icao():
|
||||
assert py_common.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
|
||||
assert py_common.icao("A0001839CA3800315800007448D9") == "400940"
|
||||
assert py_common.icao("A000139381951536E024D4CCF6B5") == "3C4DD2"
|
||||
assert py_common.icao("A000029CFFBAA11E2004727281F1") == "4243D0"
|
||||
|
||||
|
||||
def test_modes_altcode():
|
||||
assert py_common.altcode("A02014B400000000000000F9D514") == 32300
|
||||
|
||||
|
||||
def test_modes_idcode():
|
||||
assert py_common.idcode("A800292DFFBBA9383FFCEB903D01") == "1346"
|
||||
|
||||
|
||||
def test_graycode_to_altitude():
|
||||
assert py_common.gray2alt("00000000010") == -1000
|
||||
assert py_common.gray2alt("00000001010") == -500
|
||||
assert py_common.gray2alt("00000011011") == -100
|
||||
assert py_common.gray2alt("00000011010") == 0
|
||||
assert py_common.gray2alt("00000011110") == 100
|
||||
assert py_common.gray2alt("00000010011") == 600
|
||||
assert py_common.gray2alt("00000110010") == 1000
|
||||
assert py_common.gray2alt("00001001001") == 5800
|
||||
assert py_common.gray2alt("00011100100") == 10300
|
||||
assert py_common.gray2alt("01100011010") == 32000
|
||||
assert py_common.gray2alt("01110000100") == 46300
|
||||
assert py_common.gray2alt("01010101100") == 50200
|
||||
assert py_common.gray2alt("11011110100") == 73200
|
||||
assert py_common.gray2alt("10000000011") == 126600
|
||||
assert py_common.gray2alt("10000000001") == 126700
|
||||
Reference in New Issue
Block a user