diff --git a/pyModeS/c_decoder/adsb.pyx b/pyModeS/c_decoder/adsb.pyx
new file mode 100644
index 0000000..7f947fc
--- /dev/null
+++ b/pyModeS/c_decoder/adsb.pyx
@@ -0,0 +1,235 @@
+# Copyright (C) 2015 Junzi Sun (TU Delft)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# cython: language_level=3
+
+"""ADS-B Wrapper.
+
+The ADS-B wrapper also imports functions from the following modules:
+
+- pyModeS.decoder.bds.bds05
+ Functions: ``airborne_position``, ``airborne_position_with_ref``, ``altitude``
+- pyModeS.decoder.bds.bds06
+ Functions: ``surface_position``, ``surface_position_with_ref``, ``surface_velocity``
+- pyModeS.decoder.bds.bds08
+ Functions: ``category``, ``callsign``
+- pyModeS.decoder.bds.bds09
+ Functions: ``airborne_velocity``, ``altitude_diff``
+
+"""
+
+from libc.math cimport NAN as nan
+
+# from pyModeS.decoder.bds import bds05, bds06, bds09
+from .common cimport typecode, icao as c_icao, df, hex2bin, bin2int, char_to_int
+
+from .bds.bds05 import (
+ airborne_position,
+ airborne_position_with_ref,
+ altitude,
+)
+from .bds.bds06 import (
+ surface_position,
+ surface_position_with_ref,
+ surface_velocity,
+)
+from .bds.bds08 import category, callsign
+from pyModeS.decoder.bds.bds09 import airborne_velocity, altitude_diff
+
+def icao(bytes msg):
+ return c_icao(msg)
+
+def position(bytes msg0 not None, bytes msg1 not None, int t0, int t1, double lat_ref=nan, double lon_ref=nan):
+ """Decode position from a pair of even and odd position message
+ (works with both airborne and surface position messages)
+
+ Args:
+ msg0 (string): even message (28 bytes hexadecimal string)
+ msg1 (string): odd message (28 bytes hexadecimal string)
+ t0 (int): timestamps for the even message
+ t1 (int): timestamps for the odd message
+
+ Returns:
+ (float, float): (latitude, longitude) of the aircraft
+ """
+ cdef int tc0 = typecode(msg0)
+ cdef int tc1 = typecode(msg1)
+
+ if 5 <= tc0 <= 8 and 5 <= tc1 <= 8:
+ if (lat_ref != lat_ref) or (lon_ref != lon_ref):
+ raise RuntimeError(
+ "Surface position encountered, a reference \
+ position lat/lon required. Location of \
+ receiver can be used."
+ )
+ else:
+ return surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref)
+
+ elif 9 <= tc0 <= 18 and 9 <= tc1 <= 18:
+ # Airborne position with barometric height
+ return airborne_position(msg0, msg1, t0, t1)
+
+ elif 20 <= tc0 <= 22 and 20 <= tc1 <= 22:
+ # Airborne position with GNSS height
+ return airborne_position(msg0, msg1, t0, t1)
+
+ else:
+ raise RuntimeError("incorrect or inconsistant message types")
+
+
+def position_with_ref(bytes msg not None, double lat_ref, double lon_ref):
+ """Decode position with only one message,
+ knowing reference nearby location, such as previously
+ calculated location, ground station, or airport location, etc.
+ Works with both airborne and surface position messages.
+ The reference position shall be with in 180NM (airborne) or 45NM (surface)
+ of the true position.
+
+ Args:
+ msg (string): even message (28 bytes hexadecimal string)
+ lat_ref: previous known latitude
+ lon_ref: previous known longitude
+
+ Returns:
+ (float, float): (latitude, longitude) of the aircraft
+ """
+
+ cdef int tc = typecode(msg)
+
+ if 5 <= tc <= 8:
+ return surface_position_with_ref(msg, lat_ref, lon_ref)
+
+ elif 9 <= tc <= 18 or 20 <= tc <= 22:
+ return airborne_position_with_ref(msg, lat_ref, lon_ref)
+
+ else:
+ raise RuntimeError("incorrect or inconsistant message types")
+
+
+def altitude(bytes msg):
+ """Decode aircraft altitude
+
+ Args:
+ msg (string): 28 bytes hexadecimal message string
+
+ Returns:
+ int: altitude in feet
+ """
+
+ cdef int tc = typecode(msg)
+
+ if tc < 5 or tc == 19 or tc > 22:
+ raise RuntimeError("%s: Not a position message" % msg)
+
+ if tc >= 5 and tc <= 8:
+ # surface position, altitude 0
+ return 0
+
+ cdef bytearray msgbin = hex2bin(msg)
+ cdef int q = char_to_int(msgbin[47])
+ cdef int n
+ cdef double alt
+ if q:
+ n = bin2int(msgbin[40:47] + msgbin[48:52])
+ alt = n * 25 - 1000
+ return alt
+ else:
+ return nan
+
+
+def velocity(bytes msg, bint rtn_sources=False):
+ """Calculate the speed, heading, and vertical rate
+ (handles both airborne or surface message)
+
+ Args:
+ msg (string): 28 bytes hexadecimal message string
+ rtn_source (boolean): If the function will return
+ the sources for direction of travel and vertical
+ rate. This will change the return value from a four
+ element array to a six element array.
+
+ Returns:
+ (int, float, int, string, string, string): speed (kt),
+ ground track or heading (degree),
+ rate of climb/descent (ft/min), speed type
+ ('GS' for ground speed, 'AS' for airspeed),
+ direction source ('true_north' for ground track / true north
+ as refrence, 'mag_north' for magnetic north as reference),
+ rate of climb/descent source ('Baro' for barometer, 'GNSS'
+ for GNSS constellation).
+
+ In the case of surface messages, None will be put in place
+ for vertical rate and its respective sources.
+ """
+
+ cdef int tc = typecode(msg)
+
+ if 5 <= tc <= 8:
+ return surface_velocity(msg, rtn_sources)
+
+ elif tc == 19:
+ return airborne_velocity(msg, rtn_sources)
+
+ else:
+ raise RuntimeError(
+ "incorrect or inconsistant message types, expecting 4 4:
+ raise RuntimeError("%s: Not a identification message" % msg)
+
+ cdef bytearray msgbin = common.hex2bin(msg)
+ mebin = msgbin[32:87]
+ return common.bin2int(mebin[5:8])
+
+
+def callsign(bytes msg):
+ """Aircraft callsign
+
+ Args:
+ msg (string): 28 bytes hexadecimal message string
+
+ Returns:
+ string: callsign
+ """
+
+ cdef int tc = common.typecode(msg)
+ if tc < 1 or tc > 4:
+ raise RuntimeError("%s: Not a identification message" % msg)
+
+ cdef bytearray _chars = bytearray(
+ b"#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######"
+ )
+ cdef unsigned char[:] chars = _chars
+ cdef bytearray msgbin = common.hex2bin(msg)
+ cdef bytearray csbin = msgbin[40:96]
+
+ cdef bytearray _cs = bytearray(8)
+ cdef unsigned char[:] cs = _cs
+ cs[0] = chars[common.bin2int(csbin[0:6])]
+ cs[1] = chars[common.bin2int(csbin[6:12])]
+ cs[2] = chars[common.bin2int(csbin[12:18])]
+ cs[3] = chars[common.bin2int(csbin[18:24])]
+ cs[4] = chars[common.bin2int(csbin[24:30])]
+ cs[5] = chars[common.bin2int(csbin[30:36])]
+ cs[6] = chars[common.bin2int(csbin[36:42])]
+ cs[7] = chars[common.bin2int(csbin[42:48])]
+
+ # clean string, remove spaces and marks, if any.
+ # cs = cs.replace('_', '')
+ return _cs.decode().replace("#", "")
diff --git a/setup.py b/setup.py
index 103b162..ae17fca 100644
--- a/setup.py
+++ b/setup.py
@@ -24,6 +24,7 @@ extensions = [
Extension("pyModeS.c_decoder.adsb", ["pyModeS/c_decoder/adsb.pyx"]),
Extension("pyModeS.c_decoder.bds.bds05", ["pyModeS/c_decoder/bds/bds05.pyx"]),
Extension("pyModeS.c_decoder.bds.bds06", ["pyModeS/c_decoder/bds/bds06.pyx"]),
+ Extension("pyModeS.c_decoder.bds.bds08", ["pyModeS/c_decoder/bds/bds08.pyx"]),
]