pyModeS 2.21__tar.gz → 2.22.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pymodes-2.21 → pymodes-2.22.0}/.github/workflows/build-publish.yml +15 -4
- {pymodes-2.21 → pymodes-2.22.0}/.gitignore +5 -0
- {pymodes-2.21 → pymodes-2.22.0}/PKG-INFO +8 -8
- {pymodes-2.21 → pymodes-2.22.0}/README.rst +7 -7
- {pymodes-2.21 → pymodes-2.22.0}/pyproject.toml +3 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/__init__.py +7 -13
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/c_common.pxd +3 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/c_common.pyx +20 -23
- pymodes-2.21/src/pyModeS/c_common.pyi → pymodes-2.22.0/src/pyModeS/common.pyi +8 -4
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/__init__.py +4 -7
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/adsb.py +54 -37
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/allcall.py +2 -6
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/__init__.py +1 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds05.py +2 -7
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds06.py +19 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds09.py +23 -20
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds44.py +5 -5
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds45.py +2 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds60.py +3 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds61.py +2 -6
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds62.py +2 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/commb.py +35 -35
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/ehs.py +17 -17
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/__init__.py +1 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/decode.pyi +0 -1
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/surv.py +1 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/uncertainty.py +1 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/uplink.py +8 -10
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/extra/rtlreader.py +4 -6
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/extra/tcpclient.py +12 -10
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/py_common.py +16 -14
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/streamer/decode.py +19 -12
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/streamer/modeslive.py +11 -8
- {pymodes-2.21 → pymodes-2.22.0}/tests/benchmark.py +2 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/sample_run_adsb.py +0 -1
- {pymodes-2.21 → pymodes-2.22.0}/tests/sample_run_commb.py +1 -1
- pymodes-2.22.0/tests/test_adsb.py +266 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/test_bds_inference.py +25 -0
- pymodes-2.22.0/tests/test_c_common.py +106 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/test_commb.py +2 -1
- pymodes-2.22.0/tests/test_common_contract.py +84 -0
- pymodes-2.22.0/tests/test_full.py +17 -0
- pymodes-2.22.0/tests/test_py_common.py +148 -0
- {pymodes-2.21 → pymodes-2.22.0}/uv.lock +435 -431
- pymodes-2.21/.github/dependabot.yml +0 -11
- pymodes-2.21/tests/test_adsb.py +0 -132
- pymodes-2.21/tests/test_c_common.py +0 -60
- pymodes-2.21/tests/test_py_common.py +0 -64
- {pymodes-2.21 → pymodes-2.22.0}/.coveragerc +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/LICENSE +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/Makefile +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/README.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/modeslive-screenshot.png +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/_templates/layout.html +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/conf.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/index.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/modules.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.c_common.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.common.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.acas.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.adsb.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.allcall.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds05.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds06.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds08.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds09.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds10.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds17.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds20.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds30.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds40.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds44.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds45.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds50.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds53.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.bds60.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.bds.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.commb.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.surv.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.uncertainty.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.decoder.uplink.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/source/pyModeS.rst +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/doc/warnings +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/hatch_build.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/.gitignore +0 -0
- pymodes-2.21/src/pyModeS/common.pyi → pymodes-2.22.0/src/pyModeS/c_common.pyi +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/acas.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds08.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds10.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds17.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds20.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds30.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds40.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds50.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/bds/bds53.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/els.py +3 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/core.c +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/core.h +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/core.pxd +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/decoder/flarm/decode.pyx +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/extra/__init__.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/extra/aero.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/py.typed +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/streamer/__init__.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/streamer/screen.py +3 -3
- {pymodes-2.21 → pymodes-2.22.0}/src/pyModeS/streamer/source.py +1 -1
- {pymodes-2.21 → pymodes-2.22.0}/tests/data/sample_data_adsb.csv +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/data/sample_data_commb_df20.csv +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/data/sample_data_commb_df21.csv +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/test_allcall.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/test_surv.py +0 -0
- {pymodes-2.21 → pymodes-2.22.0}/tests/test_tell.py +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
name: Build and publish pyModeS
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
6
7
|
workflow_dispatch:
|
|
7
8
|
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
8
12
|
env:
|
|
9
13
|
CIBW_BUILD: cp310* cp311* cp312* cp313*
|
|
10
14
|
CIBW_ARCHS_WINDOWS: auto64
|
|
@@ -59,7 +63,8 @@ jobs:
|
|
|
59
63
|
environment: pypi
|
|
60
64
|
permissions:
|
|
61
65
|
id-token: write
|
|
62
|
-
|
|
66
|
+
contents: write
|
|
67
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
63
68
|
steps:
|
|
64
69
|
- uses: actions/download-artifact@v4
|
|
65
70
|
with:
|
|
@@ -71,4 +76,10 @@ jobs:
|
|
|
71
76
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
72
77
|
with:
|
|
73
78
|
user: __token__
|
|
74
|
-
password: ${{ secrets.PYPI_API_TOKEN_PYMODES }}
|
|
79
|
+
password: ${{ secrets.PYPI_API_TOKEN_PYMODES }}
|
|
80
|
+
|
|
81
|
+
- name: Create GitHub Release
|
|
82
|
+
uses: softprops/action-gh-release@v2
|
|
83
|
+
with:
|
|
84
|
+
generate_release_notes: true
|
|
85
|
+
files: dist/*
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
tmp/
|
|
2
|
+
|
|
1
3
|
.DS_Store
|
|
2
4
|
|
|
3
5
|
# Byte-compiled / optimized / DLL files
|
|
@@ -53,6 +55,9 @@ coverage.xml
|
|
|
53
55
|
# Sphinx documentation
|
|
54
56
|
docs/_build/
|
|
55
57
|
|
|
58
|
+
# Local planning / brainstorming artifacts (not for publication)
|
|
59
|
+
docs/superpowers/
|
|
60
|
+
|
|
56
61
|
# PyBuilder
|
|
57
62
|
target/
|
|
58
63
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyModeS
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.22.0
|
|
4
4
|
Summary: Python Mode-S and ADS-B Decoder
|
|
5
5
|
Project-URL: homepage, https://mode-s.org
|
|
6
6
|
Project-URL: repository, https://github.com/junzis/pyModeS
|
|
@@ -123,7 +123,7 @@ If you want to make use of the (faster) c module, install ``pyModeS`` as follows
|
|
|
123
123
|
# development version
|
|
124
124
|
git clone https://github.com/junzis/pyModeS
|
|
125
125
|
cd pyModeS
|
|
126
|
-
|
|
126
|
+
uv sync --dev --all-extras
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
View live traffic (modeslive)
|
|
@@ -208,7 +208,6 @@ Core functions for ADS-B decoding
|
|
|
208
208
|
pms.adsb.position(msg_even, msg_odd, t_even, t_odd, lat_ref=None, lon_ref=None)
|
|
209
209
|
pms.adsb.airborne_position(msg_even, msg_odd, t_even, t_odd)
|
|
210
210
|
pms.adsb.surface_position(msg_even, msg_odd, t_even, t_odd, lat_ref, lon_ref)
|
|
211
|
-
pms.adsb.surface_velocity(msg)
|
|
212
211
|
|
|
213
212
|
pms.adsb.position_with_ref(msg, lat_ref, lon_ref)
|
|
214
213
|
pms.adsb.airborne_position_with_ref(msg, lat_ref, lon_ref)
|
|
@@ -219,17 +218,18 @@ Core functions for ADS-B decoding
|
|
|
219
218
|
# Typecode: 19
|
|
220
219
|
pms.adsb.velocity(msg) # Handles both surface & airborne messages
|
|
221
220
|
pms.adsb.speed_heading(msg) # Handles both surface & airborne messages
|
|
222
|
-
pms.adsb.
|
|
221
|
+
pms.adsb.surface_velocity(msg, source)
|
|
222
|
+
pms.adsb.airborne_velocity(msg, source)
|
|
223
223
|
|
|
224
224
|
|
|
225
225
|
Note: When you have a fix position of the aircraft, it is convenient to use `position_with_ref()` method to decode with only one position message (either odd or even). This works with both airborne and surface position messages. But the reference position shall be within 180NM (airborne) or 45NM (surface) of the true position.
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
Decode altitude replies in DF4 / DF20
|
|
229
|
-
|
|
228
|
+
Decode altitude replies in DF0 / DF4 / DF16 /DF20
|
|
229
|
+
**************************************************
|
|
230
230
|
.. code:: python
|
|
231
231
|
|
|
232
|
-
pms.common.altcode(msg) # Downlink format must be 4 or 20
|
|
232
|
+
pms.common.altcode(msg) # Downlink format must be 0, 4, 16 or 20
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
Decode identity replies in DF5 / DF21
|
|
@@ -305,7 +305,7 @@ To identify BDS 4,4 and 4,5 codes, you must set ``mrar`` argument to ``True`` in
|
|
|
305
305
|
|
|
306
306
|
.. code:: python
|
|
307
307
|
|
|
308
|
-
pms.bds.infer(msg
|
|
308
|
+
pms.bds.infer(msg, mrar=True)
|
|
309
309
|
|
|
310
310
|
Once the correct MRAR and MHR messages are identified, decode them as follows:
|
|
311
311
|
|
|
@@ -100,7 +100,7 @@ If you want to make use of the (faster) c module, install ``pyModeS`` as follows
|
|
|
100
100
|
# development version
|
|
101
101
|
git clone https://github.com/junzis/pyModeS
|
|
102
102
|
cd pyModeS
|
|
103
|
-
|
|
103
|
+
uv sync --dev --all-extras
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
View live traffic (modeslive)
|
|
@@ -185,7 +185,6 @@ Core functions for ADS-B decoding
|
|
|
185
185
|
pms.adsb.position(msg_even, msg_odd, t_even, t_odd, lat_ref=None, lon_ref=None)
|
|
186
186
|
pms.adsb.airborne_position(msg_even, msg_odd, t_even, t_odd)
|
|
187
187
|
pms.adsb.surface_position(msg_even, msg_odd, t_even, t_odd, lat_ref, lon_ref)
|
|
188
|
-
pms.adsb.surface_velocity(msg)
|
|
189
188
|
|
|
190
189
|
pms.adsb.position_with_ref(msg, lat_ref, lon_ref)
|
|
191
190
|
pms.adsb.airborne_position_with_ref(msg, lat_ref, lon_ref)
|
|
@@ -196,17 +195,18 @@ Core functions for ADS-B decoding
|
|
|
196
195
|
# Typecode: 19
|
|
197
196
|
pms.adsb.velocity(msg) # Handles both surface & airborne messages
|
|
198
197
|
pms.adsb.speed_heading(msg) # Handles both surface & airborne messages
|
|
199
|
-
pms.adsb.
|
|
198
|
+
pms.adsb.surface_velocity(msg, source)
|
|
199
|
+
pms.adsb.airborne_velocity(msg, source)
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
Note: When you have a fix position of the aircraft, it is convenient to use `position_with_ref()` method to decode with only one position message (either odd or even). This works with both airborne and surface position messages. But the reference position shall be within 180NM (airborne) or 45NM (surface) of the true position.
|
|
203
203
|
|
|
204
204
|
|
|
205
|
-
Decode altitude replies in DF4 / DF20
|
|
206
|
-
|
|
205
|
+
Decode altitude replies in DF0 / DF4 / DF16 /DF20
|
|
206
|
+
**************************************************
|
|
207
207
|
.. code:: python
|
|
208
208
|
|
|
209
|
-
pms.common.altcode(msg) # Downlink format must be 4 or 20
|
|
209
|
+
pms.common.altcode(msg) # Downlink format must be 0, 4, 16 or 20
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
Decode identity replies in DF5 / DF21
|
|
@@ -282,7 +282,7 @@ To identify BDS 4,4 and 4,5 codes, you must set ``mrar`` argument to ``True`` in
|
|
|
282
282
|
|
|
283
283
|
.. code:: python
|
|
284
284
|
|
|
285
|
-
pms.bds.infer(msg
|
|
285
|
+
pms.bds.infer(msg, mrar=True)
|
|
286
286
|
|
|
287
287
|
Once the correct MRAR and MHR messages are identified, decode them as follows:
|
|
288
288
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pyModeS"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.22.0"
|
|
4
4
|
description = "Python Mode-S and ADS-B Decoder"
|
|
5
5
|
authors = [{ name = "Junzi Sun", email = "git@junzis.com" }]
|
|
6
6
|
license = { text = "GNU GPL v3" }
|
|
@@ -27,8 +27,8 @@ homepage = "https://mode-s.org"
|
|
|
27
27
|
repository = "https://github.com/junzis/pyModeS"
|
|
28
28
|
issues = "https://github.com/junzis/pyModeS/issues"
|
|
29
29
|
|
|
30
|
-
[
|
|
31
|
-
dev
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
32
|
"mypy>=0.991",
|
|
33
33
|
"flake8>=5.0.0",
|
|
34
34
|
"black>=22.12.0",
|
|
@@ -8,25 +8,19 @@ except Exception:
|
|
|
8
8
|
from . import py_common as common # type: ignore
|
|
9
9
|
from .py_common import * # type: ignore
|
|
10
10
|
|
|
11
|
-
from .decoder import tell
|
|
12
|
-
from .
|
|
13
|
-
from .decoder import commb
|
|
14
|
-
from .decoder import allcall
|
|
15
|
-
from .decoder import surv
|
|
16
|
-
from .decoder import bds
|
|
17
|
-
from .extra import aero
|
|
18
|
-
from .extra import tcpclient
|
|
11
|
+
from .decoder import adsb, allcall, bds, commb, surv, tell
|
|
12
|
+
from .extra import aero, tcpclient
|
|
19
13
|
|
|
20
14
|
__all__ = [
|
|
21
|
-
"common",
|
|
22
|
-
"tell",
|
|
23
15
|
"adsb",
|
|
24
|
-
"
|
|
16
|
+
"aero",
|
|
25
17
|
"allcall",
|
|
26
|
-
"surv",
|
|
27
18
|
"bds",
|
|
28
|
-
"
|
|
19
|
+
"commb",
|
|
20
|
+
"common",
|
|
21
|
+
"surv",
|
|
29
22
|
"tcpclient",
|
|
23
|
+
"tell",
|
|
30
24
|
]
|
|
31
25
|
|
|
32
26
|
|
|
@@ -15,14 +15,14 @@ cpdef long floor(double x)
|
|
|
15
15
|
cpdef str icao(str msg)
|
|
16
16
|
cpdef bint is_icao_assigned(str icao)
|
|
17
17
|
|
|
18
|
-
cpdef
|
|
18
|
+
cpdef object typecode(str msg)
|
|
19
19
|
cpdef int cprNL(double lat)
|
|
20
20
|
|
|
21
21
|
cpdef str idcode(str msg)
|
|
22
22
|
cpdef str squawk(str binstr)
|
|
23
23
|
|
|
24
|
-
cpdef
|
|
25
|
-
cpdef
|
|
24
|
+
cpdef object altcode(str msg)
|
|
25
|
+
cpdef object altitude(str binstr)
|
|
26
26
|
|
|
27
27
|
cpdef str data(str msg)
|
|
28
28
|
cpdef bint allzeros(str msg)
|
|
@@ -97,7 +97,7 @@ cpdef long crc(str msg, bint encode=False):
|
|
|
97
97
|
msg (string): 28 bytes hexadecimal message string
|
|
98
98
|
encode (bool): True to encode the date only and return the checksum
|
|
99
99
|
Returns:
|
|
100
|
-
int: message checksum, or
|
|
100
|
+
int: message checksum, or parity bits (encoder)
|
|
101
101
|
|
|
102
102
|
"""
|
|
103
103
|
# the CRC generator
|
|
@@ -183,34 +183,33 @@ cpdef bint is_icao_assigned(str icao):
|
|
|
183
183
|
|
|
184
184
|
cdef long icaoint = hex2int(icao)
|
|
185
185
|
|
|
186
|
-
if 0x200000
|
|
186
|
+
if 0x200000 <= icaoint <= 0x27FFFF:
|
|
187
187
|
return False # AFI
|
|
188
|
-
if 0x280000
|
|
188
|
+
if 0x280000 <= icaoint <= 0x28FFFF:
|
|
189
189
|
return False # SAM
|
|
190
|
-
if 0x500000
|
|
190
|
+
if 0x500000 <= icaoint <= 0x5FFFFF:
|
|
191
191
|
return False # EUR, NAT
|
|
192
|
-
if 0x600000
|
|
192
|
+
if 0x600000 <= icaoint <= 0x67FFFF:
|
|
193
193
|
return False # MID
|
|
194
|
-
if 0x680000
|
|
194
|
+
if 0x680000 <= icaoint <= 0x6F0000:
|
|
195
195
|
return False # ASIA
|
|
196
|
-
if 0x900000
|
|
196
|
+
if 0x900000 <= icaoint <= 0x9FFFFF:
|
|
197
197
|
return False # NAM, PAC
|
|
198
|
-
if 0xB00000
|
|
198
|
+
if 0xB00000 <= icaoint <= 0xBFFFFF:
|
|
199
199
|
return False # CAR
|
|
200
|
-
if 0xD00000
|
|
200
|
+
if 0xD00000 <= icaoint <= 0xDFFFFF:
|
|
201
201
|
return False # future
|
|
202
|
-
if 0xF00000
|
|
202
|
+
if 0xF00000 <= icaoint <= 0xFFFFFF:
|
|
203
203
|
return False # future
|
|
204
204
|
|
|
205
205
|
return True
|
|
206
206
|
|
|
207
207
|
@cython.boundscheck(False)
|
|
208
208
|
@cython.wraparound(False)
|
|
209
|
-
cpdef
|
|
209
|
+
cpdef object typecode(str msg):
|
|
210
210
|
"""Type code of ADS-B message"""
|
|
211
211
|
if df(msg) not in (17, 18):
|
|
212
|
-
return
|
|
213
|
-
# return None
|
|
212
|
+
return None
|
|
214
213
|
|
|
215
214
|
cdef str tcbin = hex2bin(msg[8:10])
|
|
216
215
|
return bin2int(tcbin[0:5])
|
|
@@ -282,18 +281,17 @@ cpdef str squawk(str binstr):
|
|
|
282
281
|
|
|
283
282
|
@cython.boundscheck(False)
|
|
284
283
|
@cython.wraparound(False)
|
|
285
|
-
cpdef
|
|
284
|
+
cpdef object altcode(str msg):
|
|
286
285
|
"""Compute the altitude."""
|
|
287
286
|
if df(msg) not in [0, 4, 16, 20]:
|
|
288
287
|
raise RuntimeError("Message must be Downlink Format 0, 4, 16, or 20.")
|
|
289
288
|
|
|
290
|
-
|
|
291
|
-
return alt
|
|
289
|
+
return altitude(hex2bin(msg)[19:32])
|
|
292
290
|
|
|
293
291
|
|
|
294
292
|
@cython.boundscheck(False)
|
|
295
293
|
@cython.wraparound(False)
|
|
296
|
-
cpdef
|
|
294
|
+
cpdef object altitude(str binstr):
|
|
297
295
|
|
|
298
296
|
if len(binstr) != 13 or not set(binstr).issubset(set("01")):
|
|
299
297
|
raise RuntimeError("Input must be 13 bits binary string")
|
|
@@ -304,20 +302,20 @@ cpdef int altitude(str binstr):
|
|
|
304
302
|
cdef char Mbit = binstr[6]
|
|
305
303
|
cdef char Qbit = binstr[8]
|
|
306
304
|
|
|
307
|
-
|
|
305
|
+
alt = None
|
|
308
306
|
cdef bytearray vbin
|
|
309
307
|
cdef bytearray _graybytes = bytearray(11)
|
|
310
308
|
cdef unsigned char[:] graybytes = _graybytes
|
|
311
309
|
|
|
312
310
|
if bin2int(binstr) == 0:
|
|
313
311
|
# altitude unknown or invalid
|
|
314
|
-
|
|
312
|
+
return None
|
|
315
313
|
|
|
316
314
|
elif Mbit == 48: # unit in ft, "0" -> 48
|
|
317
315
|
if Qbit == 49: # 25ft interval, "1" -> 49
|
|
318
316
|
vbin = _mbin[:6] + _mbin[7:8] + _mbin[9:]
|
|
319
317
|
alt = bin2int(vbin.decode()) * 25 - 1000
|
|
320
|
-
if Qbit == 48: # 100ft interval, above
|
|
318
|
+
if Qbit == 48: # 100ft interval, above 50187.5ft, "0" -> 48
|
|
321
319
|
graybytes[8] = mbin[0]
|
|
322
320
|
graybytes[2] = mbin[1]
|
|
323
321
|
graybytes[9] = mbin[2]
|
|
@@ -341,7 +339,7 @@ cpdef int altitude(str binstr):
|
|
|
341
339
|
return alt
|
|
342
340
|
|
|
343
341
|
|
|
344
|
-
cpdef
|
|
342
|
+
cpdef object gray2alt(str codestr):
|
|
345
343
|
cdef str gc500 = codestr[:8]
|
|
346
344
|
cdef int n500 = gray2int(gc500)
|
|
347
345
|
|
|
@@ -350,8 +348,7 @@ cpdef int gray2alt(str codestr):
|
|
|
350
348
|
cdef int n100 = gray2int(gc100)
|
|
351
349
|
|
|
352
350
|
if n100 in [0, 5, 6]:
|
|
353
|
-
return
|
|
354
|
-
#return None
|
|
351
|
+
return None
|
|
355
352
|
|
|
356
353
|
if n100 == 7:
|
|
357
354
|
n100 = 5
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
def hex2bin(hexstr: str) -> str: ...
|
|
2
4
|
def bin2int(binstr: str) -> int: ...
|
|
3
5
|
def hex2int(hexstr: str) -> int: ...
|
|
@@ -5,14 +7,16 @@ def bin2hex(binstr: str) -> str: ...
|
|
|
5
7
|
def df(msg: str) -> int: ...
|
|
6
8
|
def crc(msg: str, encode: bool = False) -> int: ...
|
|
7
9
|
def floor(x: float) -> float: ...
|
|
8
|
-
def icao(msg: str) -> str: ...
|
|
10
|
+
def icao(msg: str) -> Optional[str]: ...
|
|
9
11
|
def is_icao_assigned(icao: str) -> bool: ...
|
|
10
|
-
def typecode(msg: str) -> int: ...
|
|
12
|
+
def typecode(msg: str) -> Optional[int]: ...
|
|
11
13
|
def cprNL(lat: float) -> int: ...
|
|
12
14
|
def idcode(msg: str) -> str: ...
|
|
13
15
|
def squawk(binstr: str) -> str: ...
|
|
14
|
-
def altcode(msg: str) -> int: ...
|
|
15
|
-
def altitude(binstr: str) -> int: ...
|
|
16
|
+
def altcode(msg: str) -> Optional[int]: ...
|
|
17
|
+
def altitude(binstr: str) -> Optional[int]: ...
|
|
18
|
+
def gray2alt(binstr: str) -> Optional[int]: ...
|
|
19
|
+
def gray2int(binstr: str) -> int: ...
|
|
16
20
|
def data(msg: str) -> str: ...
|
|
17
21
|
def allzeros(msg: str) -> bool: ...
|
|
18
22
|
def wrongstatus(data: str, sb: int, msb: int, lsb: int) -> bool: ...
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
def tell(msg: str) -> None:
|
|
2
|
-
from .. import
|
|
2
|
+
from .. import adsb, bds, commb, common
|
|
3
3
|
|
|
4
4
|
def _print(label, value, unit=None):
|
|
5
5
|
print("%28s: " % label, end="")
|
|
@@ -132,7 +132,7 @@ def tell(msg: str) -> None:
|
|
|
132
132
|
_print("TCAS/ACAS RA", tcas_ra_types[tcas_ra])
|
|
133
133
|
_print("Emergency status", emergency_types[emergency_status])
|
|
134
134
|
else:
|
|
135
|
-
alt, alt_source = adsb.selected_altitude(msg)
|
|
135
|
+
alt, alt_source = adsb.selected_altitude(msg)
|
|
136
136
|
baro = adsb.baro_pressure_setting(msg)
|
|
137
137
|
hdg = adsb.selected_heading(msg)
|
|
138
138
|
autopilot = adsb.autopilot(msg)
|
|
@@ -149,9 +149,7 @@ def tell(msg: str) -> None:
|
|
|
149
149
|
)
|
|
150
150
|
_print("Selected Heading", hdg, "°")
|
|
151
151
|
if not (common.bin2int((common.hex2bin(msg)[32:])[46]) == 0):
|
|
152
|
-
_print(
|
|
153
|
-
"Autopilot", types_29[autopilot] if autopilot else None
|
|
154
|
-
)
|
|
152
|
+
_print("Autopilot", types_29[autopilot] if autopilot else None)
|
|
155
153
|
_print("VNAV mode", types_29[vnav] if vnav else None)
|
|
156
154
|
_print(
|
|
157
155
|
"Altitude hold mode",
|
|
@@ -220,8 +218,7 @@ def tell(msg: str) -> None:
|
|
|
220
218
|
if BDS == "BDS44":
|
|
221
219
|
_print("Wind speed", commb.wind44(msg)[0], "knots")
|
|
222
220
|
_print("Wind direction", commb.wind44(msg)[1], "degrees")
|
|
223
|
-
_print("Temperature
|
|
224
|
-
_print("Temperature 2", commb.temp44(msg)[1], "Celsius")
|
|
221
|
+
_print("Temperature", commb.temp44(msg), "Celsius")
|
|
225
222
|
_print("Pressure", commb.p44(msg), "hPa")
|
|
226
223
|
_print("Humidity", commb.hum44(msg), "%")
|
|
227
224
|
_print("Turbulence", commb.turb44(msg))
|
|
@@ -14,6 +14,7 @@ The ADS-B module also imports functions from the following modules:
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
from datetime import datetime
|
|
17
|
+
from typing import Literal, overload
|
|
17
18
|
|
|
18
19
|
from .. import common
|
|
19
20
|
from . import uncertainty
|
|
@@ -48,52 +49,52 @@ from .bds.bds62 import (
|
|
|
48
49
|
__all__ = [
|
|
49
50
|
"airborne_position",
|
|
50
51
|
"airborne_position_with_ref",
|
|
52
|
+
"airborne_velocity",
|
|
53
|
+
"altitude",
|
|
51
54
|
"altitude05",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
+
"altitude_diff",
|
|
56
|
+
"altitude_hold_mode",
|
|
57
|
+
"approach_mode",
|
|
58
|
+
"autopilot",
|
|
59
|
+
"baro_pressure_setting",
|
|
55
60
|
"callsign",
|
|
56
61
|
"category",
|
|
57
|
-
"
|
|
58
|
-
"altitude_diff",
|
|
62
|
+
"df",
|
|
59
63
|
"emergency_squawk",
|
|
60
64
|
"emergency_state",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
65
|
+
"emergency_status",
|
|
66
|
+
"horizontal_mode",
|
|
63
67
|
"icao",
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"position_with_ref",
|
|
67
|
-
"altitude",
|
|
68
|
-
"velocity",
|
|
69
|
-
"speed_heading",
|
|
70
|
-
"oe_flag",
|
|
71
|
-
"version",
|
|
72
|
-
"nuc_p",
|
|
73
|
-
"nuc_v",
|
|
74
|
-
"nic_v1",
|
|
75
|
-
"nic_v2",
|
|
76
|
-
"nic_s",
|
|
77
|
-
"nic_a_c",
|
|
78
|
-
"nic_b",
|
|
68
|
+
"is_emergency",
|
|
69
|
+
"lnav_mode",
|
|
79
70
|
"nac_p",
|
|
80
71
|
"nac_v",
|
|
81
|
-
"
|
|
72
|
+
"nic_a_c",
|
|
73
|
+
"nic_b",
|
|
74
|
+
"nic_s",
|
|
75
|
+
"nic_v1",
|
|
76
|
+
"nic_v2",
|
|
77
|
+
"nuc_p",
|
|
78
|
+
"nuc_v",
|
|
79
|
+
"oe_flag",
|
|
80
|
+
"position",
|
|
81
|
+
"position_with_ref",
|
|
82
82
|
"selected_altitude",
|
|
83
|
-
"target_altitude",
|
|
84
|
-
"vertical_mode",
|
|
85
|
-
"horizontal_mode",
|
|
86
83
|
"selected_heading",
|
|
84
|
+
"sil",
|
|
85
|
+
"speed_heading",
|
|
86
|
+
"surface_position",
|
|
87
|
+
"surface_position_with_ref",
|
|
88
|
+
"surface_velocity",
|
|
89
|
+
"target_altitude",
|
|
87
90
|
"target_angle",
|
|
88
|
-
"baro_pressure_setting",
|
|
89
|
-
"autopilot",
|
|
90
|
-
"vnav_mode",
|
|
91
|
-
"altitude_hold_mode",
|
|
92
|
-
"approach_mode",
|
|
93
|
-
"lnav_mode",
|
|
94
91
|
"tcas_operational",
|
|
95
92
|
"tcas_ra",
|
|
96
|
-
"
|
|
93
|
+
"typecode",
|
|
94
|
+
"velocity",
|
|
95
|
+
"version",
|
|
96
|
+
"vertical_mode",
|
|
97
|
+
"vnav_mode",
|
|
97
98
|
]
|
|
98
99
|
|
|
99
100
|
|
|
@@ -195,7 +196,7 @@ def position_with_ref(msg: str, lat_ref: float, lon_ref: float) -> tuple[float,
|
|
|
195
196
|
raise RuntimeError("incorrect or inconsistent message types")
|
|
196
197
|
|
|
197
198
|
|
|
198
|
-
def altitude(msg: str) -> None |
|
|
199
|
+
def altitude(msg: str) -> None | int:
|
|
199
200
|
"""Decode aircraft altitude.
|
|
200
201
|
|
|
201
202
|
Args:
|
|
@@ -219,9 +220,25 @@ def altitude(msg: str) -> None | float:
|
|
|
219
220
|
return altitude05(msg)
|
|
220
221
|
|
|
221
222
|
|
|
223
|
+
@overload
|
|
224
|
+
def velocity(
|
|
225
|
+
msg: str, source: Literal[False] = False
|
|
226
|
+
) -> None | tuple[None | float, None | float, None | int, str]: ...
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@overload
|
|
230
|
+
def velocity(
|
|
231
|
+
msg: str, source: Literal[True]
|
|
232
|
+
) -> None | tuple[None | float, None | float, None | int, str, str, str | None]: ...
|
|
233
|
+
|
|
234
|
+
|
|
222
235
|
def velocity(
|
|
223
236
|
msg: str, source: bool = False
|
|
224
|
-
) ->
|
|
237
|
+
) -> (
|
|
238
|
+
None
|
|
239
|
+
| tuple[None | float, None | float, None | int, str]
|
|
240
|
+
| tuple[None | float, None | float, None | int, str, str, str | None]
|
|
241
|
+
):
|
|
225
242
|
"""Calculate the speed, heading, and vertical rate
|
|
226
243
|
(handles both airborne or surface message).
|
|
227
244
|
|
|
@@ -232,7 +249,7 @@ def velocity(
|
|
|
232
249
|
If set to True, the function will return six value instead of four.
|
|
233
250
|
|
|
234
251
|
Returns:
|
|
235
|
-
|
|
252
|
+
float, float, int, string, [string], [string]:
|
|
236
253
|
- Speed (kt)
|
|
237
254
|
- Angle (degree), either ground track or heading
|
|
238
255
|
- Vertical rate (ft/min)
|
|
@@ -325,7 +342,7 @@ def nuc_p(msg: str) -> tuple[int, None | float, None | int, None | int]:
|
|
|
325
342
|
"""
|
|
326
343
|
tc = typecode(msg)
|
|
327
344
|
|
|
328
|
-
if tc is None or tc < 5 or tc
|
|
345
|
+
if tc is None or tc < 5 or tc == 19 or tc > 22:
|
|
329
346
|
raise RuntimeError(
|
|
330
347
|
"%s: Not a surface position message (5<TC<8), \
|
|
331
348
|
airborne position message (8<TC<19), \
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Decode all-call reply messages, with downlink format 11
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
from __future__ import annotations
|
|
6
|
+
|
|
7
7
|
from typing import Callable, TypeVar
|
|
8
8
|
|
|
9
9
|
from .. import common
|
|
@@ -13,7 +13,6 @@ F = Callable[[str], T]
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _checkdf(func: F[T]) -> F[T]:
|
|
16
|
-
|
|
17
16
|
"""Ensure downlink format is 11."""
|
|
18
17
|
|
|
19
18
|
def wrapper(msg: str) -> T:
|
|
@@ -82,10 +81,7 @@ def capability(msg: str) -> tuple[int, None | str]:
|
|
|
82
81
|
elif ca == 5:
|
|
83
82
|
text = "level 2 transponder, ability to set CA to 7, airborne"
|
|
84
83
|
elif ca == 6:
|
|
85
|
-
text =
|
|
86
|
-
"evel 2 transponder, ability to set CA to 7, "
|
|
87
|
-
"either airborne or ground"
|
|
88
|
-
)
|
|
84
|
+
text = "evel 2 transponder, ability to set CA to 7, either airborne or ground"
|
|
89
85
|
elif ca == 7:
|
|
90
86
|
text = (
|
|
91
87
|
"Downlink Request value is not 0, "
|
|
@@ -39,9 +39,7 @@ from . import ( # noqa: F401
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def is50or60(
|
|
43
|
-
msg: str, spd_ref: float, trk_ref: float, alt_ref: float
|
|
44
|
-
) -> Optional[str]:
|
|
42
|
+
def is50or60(msg: str, spd_ref: float, trk_ref: float, alt_ref: float) -> Optional[str]:
|
|
45
43
|
"""Use reference ground speed and trk to determine BDS50 and DBS60.
|
|
46
44
|
|
|
47
45
|
Args:
|
|
@@ -149,11 +149,6 @@ def altitude(msg: str) -> None | int:
|
|
|
149
149
|
|
|
150
150
|
if tc < 19:
|
|
151
151
|
altcode = altbin[0:6] + "0" + altbin[6:]
|
|
152
|
-
|
|
153
|
-
if alt != -999999:
|
|
154
|
-
return alt
|
|
155
|
-
else:
|
|
156
|
-
# return None if altitude is invalid
|
|
157
|
-
return None
|
|
152
|
+
return common.altitude(altcode)
|
|
158
153
|
else:
|
|
159
|
-
return common.bin2int(altbin) * 3.28084
|
|
154
|
+
return int(common.bin2int(altbin) * 3.28084)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
from datetime import datetime
|
|
10
|
+
from typing import Literal, overload
|
|
10
11
|
|
|
11
12
|
from ... import common
|
|
12
13
|
|
|
@@ -138,9 +139,24 @@ def surface_position_with_ref(
|
|
|
138
139
|
return lat, lon
|
|
139
140
|
|
|
140
141
|
|
|
142
|
+
@overload
|
|
143
|
+
def surface_velocity(
|
|
144
|
+
msg: str, source: Literal[False] = False
|
|
145
|
+
) -> tuple[None | float, None | float, int, str]: ...
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@overload
|
|
149
|
+
def surface_velocity(
|
|
150
|
+
msg: str, source: Literal[True]
|
|
151
|
+
) -> tuple[None | float, None | float, int, str, str, str | None]: ...
|
|
152
|
+
|
|
153
|
+
|
|
141
154
|
def surface_velocity(
|
|
142
155
|
msg: str, source: bool = False
|
|
143
|
-
) ->
|
|
156
|
+
) -> (
|
|
157
|
+
tuple[None | float, None | float, int, str]
|
|
158
|
+
| tuple[None | float, None | float, int, str, str, str | None]
|
|
159
|
+
):
|
|
144
160
|
"""Decode surface velocity from a surface position message
|
|
145
161
|
|
|
146
162
|
Args:
|
|
@@ -150,7 +166,7 @@ def surface_velocity(
|
|
|
150
166
|
If set to True, the function will return six value instead of four.
|
|
151
167
|
|
|
152
168
|
Returns:
|
|
153
|
-
|
|
169
|
+
float, float, int, string, [string], [string]:
|
|
154
170
|
- Speed (kt)
|
|
155
171
|
- Angle (degree), ground track
|
|
156
172
|
- Vertical rate, always 0
|
|
@@ -189,6 +205,6 @@ def surface_velocity(
|
|
|
189
205
|
spd = kts_lb[i - 1] + (mov - mov_lb[i - 1]) * step[i - 1]
|
|
190
206
|
|
|
191
207
|
if source:
|
|
192
|
-
return spd, trk, 0, "GS", "TRUE_NORTH", None
|
|
208
|
+
return spd, trk, 0, "GS", "TRUE_NORTH", None
|
|
193
209
|
else:
|
|
194
210
|
return spd, trk, 0, "GS"
|