Example #1
0
def airborne_position(msg0, msg1, t0, t1):
    """Decode airborn position from a pair of even and odd position message
    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
    """

    msgbin0 = util.hex2bin(msg0)
    msgbin1 = util.hex2bin(msg1)

    # 131072 is 2^17, since CPR lat and lon are 17 bits each.
    cprlat_even = util.bin2int(msgbin0[54:71]) / 131072.0
    cprlon_even = util.bin2int(msgbin0[71:88]) / 131072.0
    cprlat_odd = util.bin2int(msgbin1[54:71]) / 131072.0
    cprlon_odd = util.bin2int(msgbin1[71:88]) / 131072.0

    air_d_lat_even = 360.0 / 60
    air_d_lat_odd = 360.0 / 59

    # compute latitude index 'j'
    j = util.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5)

    lat_even = float(air_d_lat_even * (j % 60 + cprlat_even))
    lat_odd = float(air_d_lat_odd * (j % 59 + cprlat_odd))

    if lat_even >= 270:
        lat_even = lat_even - 360

    if lat_odd >= 270:
        lat_odd = lat_odd - 360

    # check if both are in the same latidude zone, exit if not
    if _cprNL(lat_even) != _cprNL(lat_odd):
        return None

    # compute ni, longitude index m, and longitude
    if (t0 > t1):
        lat = lat_even
        nl = _cprNL(lat)
        ni = max(_cprNL(lat) - 0, 1)
        m = util.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_even)
    else:
        lat = lat_odd
        nl = _cprNL(lat)
        ni = max(_cprNL(lat) - 1, 1)
        m = util.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_odd)

    if lon > 180:
        lon = lon - 360

    return round(lat, 5), round(lon, 5)
Example #2
0
def callsign(msg):
    """Aircraft callsign
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        string: callsign
    """

    if typecode(msg) < 1 or typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)

    chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'
    msgbin = util.hex2bin(msg)
    csbin = msgbin[40:96]

    cs = ''
    cs += chars[util.bin2int(csbin[0:6])]
    cs += chars[util.bin2int(csbin[6:12])]
    cs += chars[util.bin2int(csbin[12:18])]
    cs += chars[util.bin2int(csbin[18:24])]
    cs += chars[util.bin2int(csbin[24:30])]
    cs += chars[util.bin2int(csbin[30:36])]
    cs += chars[util.bin2int(csbin[36:42])]
    cs += chars[util.bin2int(csbin[42:48])]

    # clean string, remove spaces and marks, if any.
    # cs = cs.replace('_', '')
    cs = cs.replace('#', '')
    return cs
Example #3
0
def callsign(msg):
    """Aircraft callsign
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        string: callsign
    """

    if typecode(msg) < 1 or typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)

    chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'
    msgbin = util.hex2bin(msg)
    csbin = msgbin[40:96]

    cs = ''
    cs += chars[util.bin2int(csbin[0:6])]
    cs += chars[util.bin2int(csbin[6:12])]
    cs += chars[util.bin2int(csbin[12:18])]
    cs += chars[util.bin2int(csbin[18:24])]
    cs += chars[util.bin2int(csbin[24:30])]
    cs += chars[util.bin2int(csbin[30:36])]
    cs += chars[util.bin2int(csbin[36:42])]
    cs += chars[util.bin2int(csbin[42:48])]

    # clean string, remove spaces and marks, if any.
    # cs = cs.replace('_', '')
    cs = cs.replace('#', '')
    return cs
Example #4
0
  def _generateRandomID(
      self,
      c1 = constants.CRYPTO_CHALLENGE_C1,
      c2 = constants.CRYPTO_CHALLENGE_C2):
    """Generates the NodeID by solving two cryptographic puzzles."""
    # Solve the static cryptographic puzzle.
    rsaKey = None
    p = 0x1 # non-zero value
    pub = None

    randomStream = Crypto.Random.new().read
    while not util.hasNZeroBitPrefix(p, c1):
      rsaKey = Crypto.PublicKey.RSA.generate(constants.RSA_BITS, randomStream)
      pub = str(rsaKey.n) + str(rsaKey.e)
      p = util.hsh2int(Crypto.Hash.SHA.new(Crypto.Hash.SHA.new(pub).digest()))

    # created correct NodeID
    self.rsaKey = rsaKey
    nodeID = Crypto.Hash.SHA.new(pub)

    # Solve the dynamic cryptographic puzzle.
    p, x = 0x1, None

    while not util.hasNZeroBitPrefix(p, c2):
      x = util.bin2int(util.generateRandomString(constants.ID_LENGTH))
      # This is madness!
      p = util.hsh2int(
          Crypto.Hash.SHA.new(
              util.int2bin(
                  (util.hsh2int(nodeID) ^ x))))

    # Found a correct value of X and nodeID
    self.x = x
    return nodeID.digest()
Example #5
0
def typecode(msg):
    """Type code of ADS-B message
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: type code number
    """
    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[32:37])
Example #6
0
def typecode(msg):
    """Type code of ADS-B message
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: type code number
    """
    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[32:37])
Example #7
0
 def _verifyID(self, nodeID, x):
   '''Verifies if a user's ID has been generated using the '''
   p1 = util.hsh2int(Crypto.Hash.SHA.new(nodeID))
   p2 = util.hsh2int(Crypto.Hash.SHA.new(
       util.int2bin((util.bin2int(nodeID) ^ x))))
   # check preceeding c_i bits in P1 and P2 using sharesXPrefices.
   return (
       util.hasNZeroBitPrefix(p1, constants.CRYPTO_CHALLENGE_C1) and
       util.hasNZeroBitPrefix(p2, constants.CRYPTO_CHALLENGE_C2))
Example #8
0
def pbaro(msg):
    """Barometric pressure setting
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        float: pressure in millibar
    """
    d = util.hex2bin(data(msg))
    p = util.bin2int(d[27:39]) * 0.1 + 800    # millibar
    return p
Example #9
0
def gs(msg):
    """Aircraft ground speed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        int: ground speed in knots
    """
    d = util.hex2bin(data(msg))
    spd = util.bin2int(d[24:34]) * 2    # kts
    return spd
Example #10
0
def alt_fms(msg):
    """Selected altitude, FMS
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        int: altitude in feet
    """
    d = util.hex2bin(data(msg))
    alt = util.bin2int(d[14:26]) * 16  # ft
    return alt
Example #11
0
def alt_fms(msg):
    """Selected altitude, FMS
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        int: altitude in feet
    """
    d = util.hex2bin(data(msg))
    alt = util.bin2int(d[14:26]) * 16    # ft
    return alt
Example #12
0
def gs(msg):
    """Aircraft ground speed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        int: ground speed in knots
    """
    d = util.hex2bin(data(msg))
    spd = util.bin2int(d[24:34]) * 2  # kts
    return spd
Example #13
0
def mach(msg):
    """Aircraft MACH number
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        float: MACH number
    """
    d = util.hex2bin(data(msg))
    mach = util.bin2int(d[24:34]) * 2.048 / 512.0
    return round(mach, 3)
Example #14
0
def ias(msg):
    """Indicated airspeed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: indicated airspeed in knots
    """
    d = util.hex2bin(data(msg))
    ias = util.bin2int(d[13:23])  # kts
    return ias
Example #15
0
def mach(msg):
    """Aircraft MACH number
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        float: MACH number
    """
    d = util.hex2bin(data(msg))
    mach = util.bin2int(d[24:34]) * 2.048 / 512.0
    return round(mach, 3)
Example #16
0
def pbaro(msg):
    """Barometric pressure setting
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        float: pressure in millibar
    """
    d = util.hex2bin(data(msg))
    p = util.bin2int(d[27:39]) * 0.1 + 800  # millibar
    return p
Example #17
0
def ias(msg):
    """Indicated airspeed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: indicated airspeed in knots
    """
    d = util.hex2bin(data(msg))
    ias = util.bin2int(d[13:23])    # kts
    return ias
Example #18
0
def tas(msg):
    """Aircraft true airspeed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        int: true airspeed in knots
    """
    d = util.hex2bin(data(msg))
    spd = util.bin2int(d[46:56]) * 2  # kts
    return spd
Example #19
0
def tas(msg):
    """Aircraft true airspeed
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        int: true airspeed in knots
    """
    d = util.hex2bin(data(msg))
    spd = util.bin2int(d[46:56]) * 2   # kts
    return spd
Example #20
0
def velocity(msg):
    """Calculate the speed, heading, and vertical rate
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        (int, float, int, string): speed (kt), heading (degree),
            rate of climb/descend (ft/min), and speed type
            ('GS' for ground speed, 'AS' for airspeed)
    """

    if typecode(msg) != 19:
        raise RuntimeError("%s: Not a airborne velocity message" % msg)

    msgbin = util.hex2bin(msg)

    subtype = util.bin2int(msgbin[37:40])

    if subtype in (1, 2):
        v_ew_sign = util.bin2int(msgbin[45])
        v_ew = util.bin2int(msgbin[46:56]) - 1       # east-west velocity

        v_ns_sign = util.bin2int(msgbin[56])
        v_ns = util.bin2int(msgbin[57:67]) - 1       # north-south velocity

        v_we = -1*v_ew if v_ew_sign else v_ew
        v_sn = -1*v_ns if v_ns_sign else v_ns

        spd = math.sqrt(v_sn*v_sn + v_we*v_we)  # unit in kts

        hdg = math.atan2(v_we, v_sn)
        hdg = math.degrees(hdg)                 # convert to degrees
        hdg = hdg if hdg >= 0 else hdg + 360    # no negative val

        tag = 'GS'

    else:
        hdg = util.bin2int(msgbin[46:56]) / 1024.0 * 360.0
        spd = util.bin2int(msgbin[57:67])

        tag = 'AS'

    vr_sign = util.bin2int(msgbin[68])
    vr = util.bin2int(msgbin[68:77])             # vertical rate
    rocd = -1*vr if vr_sign else vr         # rate of climb/descend

    return int(spd), round(hdg, 1), int(rocd), tag
Example #21
0
def surface_velocity(msg):
    """Decode surface velocity from from a surface position message
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        (int, float, int, string): speed (kt), heading (degree),
            rate of climb/descend (ft/min), and speed type
            ('GS' for ground speed, 'AS' for airspeed)
    """

    if typecode(msg) < 5 or typecode(msg) > 8:
        raise RuntimeError("%s: Not a surface message, expecting 5<TC<8" % msg)

    msgbin = util.hex2bin(msg)

    # heading
    hdg_status = int(msgbin[44])
    if hdg_status == 1:
        hdg = util.bin2int(msgbin[45:52]) * 360.0 / 128.0
        hdg = round(hdg, 1)
    else:
        hdg = None

    # ground movment / speed
    mov = util.bin2int(msgbin[37:44])

    if mov == 0 or mov > 124:
        spd = None
    elif mov == 1:
        spd = 0
    elif mov == 124:
        spd = 175
    else:
        movs = [2, 9, 13, 39, 94, 109, 124]
        kts = [0.125, 1, 2, 15, 70, 100, 175]
        i = next(m[0] for m in enumerate(movs) if m[1] > mov)
        step = (kts[i] - kts[i - 1]) * 1.0 / (movs[i] - movs[i - 1])
        spd = kts[i - 1] + (mov - movs[i - 1]) * step
        spd = round(spd, 2)

    return spd, hdg, 0, 'GS'
Example #22
0
def velocity(msg):
    """Calculate the speed, heading, and vertical rate
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        (int, float, int, string): speed (kt), heading (degree),
            rate of climb/descend (ft/min), and speed type
            ('GS' for ground speed, 'AS' for airspeed)
    """

    if typecode(msg) != 19:
        raise RuntimeError("%s: Not a airborne velocity message" % msg)

    msgbin = util.hex2bin(msg)

    subtype = util.bin2int(msgbin[37:40])

    if subtype in (1, 2):
        v_ew_sign = util.bin2int(msgbin[45])
        v_ew = util.bin2int(msgbin[46:56]) - 1  # east-west velocity

        v_ns_sign = util.bin2int(msgbin[56])
        v_ns = util.bin2int(msgbin[57:67]) - 1  # north-south velocity

        v_we = -1 * v_ew if v_ew_sign else v_ew
        v_sn = -1 * v_ns if v_ns_sign else v_ns

        spd = math.sqrt(v_sn * v_sn + v_we * v_we)  # unit in kts

        hdg = math.atan2(v_we, v_sn)
        hdg = math.degrees(hdg)  # convert to degrees
        hdg = hdg if hdg >= 0 else hdg + 360  # no negative val

        tag = 'GS'

    else:
        hdg = util.bin2int(msgbin[46:56]) / 1024.0 * 360.0
        spd = util.bin2int(msgbin[57:67])

        tag = 'AS'

    vr_sign = util.bin2int(msgbin[68])
    vr = util.bin2int(msgbin[68:77])  # vertical rate
    rocd = -1 * vr if vr_sign else vr  # rate of climb/descend

    return int(spd), round(hdg, 1), int(rocd), tag
Example #23
0
def track(msg):
    """True track angle
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle in degrees to true north (from 0 to 360)
    """
    d = util.hex2bin(data(msg))
    sign = int(d[12])  # 1 -> west
    value = util.bin2int(d[13:23]) * 90 / 512.0  # degree
    angle = 360 - value if sign else value
    return round(angle, 1)
Example #24
0
def baro_vr(msg):
    """Vertical rate from barometric measurement
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: vertical rate in feet/minutes
    """
    d = util.hex2bin(data(msg))
    sign = d[35]  # 1 -> minus
    value = util.bin2int(d[36:45]) * 32  # feet/min
    roc = -1 * value if sign else value
    return roc
Example #25
0
def cprlon(msg):
    """CPR encoded longitude
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: encoded longitude
    """
    if typecode(msg) < 5 or typecode(msg) > 18:
        raise RuntimeError("%s: Not a position message" % msg)

    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[71:88])
Example #26
0
def category(msg):
    """Aircraft category number
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: category number
    """

    if typecode(msg) < 1 or typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)
    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[5:8])
Example #27
0
def heading(msg):
    """Megnetic heading of aircraft
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        float: heading in degrees to megnetic north (from 0 to 360)
    """
    d = util.hex2bin(data(msg))
    sign = int(d[1])  # 1 -> west
    value = util.bin2int(d[2:12]) * 90 / 512.0  # degree
    hdg = 360 - value if sign else value
    return round(hdg, 1)
Example #28
0
def rtrack(msg):
    """Track angle rate
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle rate in degrees/second
    """
    d = util.hex2bin(data(msg))
    sign = int(d[35])  # 1 -> minus
    value = util.bin2int(d[36:45]) * 8 / 256.0  # degree / sec
    angle = -1 * value if sign else value
    return round(angle, 3)
Example #29
0
def ins_vr(msg):
    """Vertical rate messured by onbard equiments (IRS, AHRS)
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: vertical rate in feet/minutes
    """
    d = util.hex2bin(data(msg))
    sign = d[46]  # 1 -> minus
    value = util.bin2int(d[47:56]) * 32  # feet/min
    roc = -1 * value if sign else value
    return roc
Example #30
0
def rtrack(msg):
    """Track angle rate
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle rate in degrees/second
    """
    d = util.hex2bin(data(msg))
    sign = int(d[35])    # 1 -> minus
    value = util.bin2int(d[36:45]) * 8 / 256.0    # degree / sec
    angle = -1 * value if sign else value
    return round(angle, 3)
Example #31
0
def track(msg):
    """True track angle
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle in degrees to true north (from 0 to 360)
    """
    d = util.hex2bin(data(msg))
    sign = int(d[12])   # 1 -> west
    value = util.bin2int(d[13:23]) * 90 / 512.0    # degree
    angle = 360 - value if sign else value
    return round(angle, 1)
Example #32
0
def category(msg):
    """Aircraft category number
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: category number
    """

    if typecode(msg) < 1 or typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)
    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[5:8])
Example #33
0
def baro_vr(msg):
    """Vertical rate from barometric measurement
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: vertical rate in feet/minutes
    """
    d = util.hex2bin(data(msg))
    sign = d[35]    # 1 -> minus
    value = util.bin2int(d[36:45]) * 32   # feet/min
    roc = -1*value if sign else value
    return roc
Example #34
0
def heading(msg):
    """Megnetic heading of aircraft
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        float: heading in degrees to megnetic north (from 0 to 360)
    """
    d = util.hex2bin(data(msg))
    sign = int(d[1])    # 1 -> west
    value = util.bin2int(d[2:12]) * 90 / 512.0  # degree
    hdg = 360 - value if sign else value
    return round(hdg, 1)
Example #35
0
def ins_vr(msg):
    """Vertical rate messured by onbard equiments (IRS, AHRS)
    Args:
        msg (String): 28 bytes hexadecimal message (BDS60) string
    Returns:
        int: vertical rate in feet/minutes
    """
    d = util.hex2bin(data(msg))
    sign = d[46]    # 1 -> minus
    value = util.bin2int(d[47:56]) * 32   # feet/min
    roc = -1*value if sign else value
    return roc
Example #36
0
def isBDS20(msg):
    """Check if a message is likely to be BDS code 2,0
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        bool: True or False
    """
    # status bit 1, 14, and 27
    d = util.hex2bin(data(msg))

    result = True

    if util.bin2int(d[0:4]) != 2 or util.bin2int(d[4:8]) != 0:
        result &= False

    cs = callsign(msg)

    if '#' in cs:
        result &= False

    return result
Example #37
0
def cprlon(msg):
    """CPR encoded longitude
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: encoded longitude
    """
    if typecode(msg) < 5 or typecode(msg) > 18:
        raise RuntimeError("%s: Not a position message" % msg)

    msgbin = util.hex2bin(msg)
    return util.bin2int(msgbin[71:88])
Example #38
0
def isBDS20(msg):
    """Check if a message is likely to be BDS code 2,0
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        bool: True or False
    """
    # status bit 1, 14, and 27
    d = util.hex2bin(data(msg))

    result = True

    if util.bin2int(d[0:4]) != 2 or util.bin2int(d[4:8]) != 0:
        result &= False

    cs = callsign(msg)

    if '#' in cs:
        result &= False

    return result
Example #39
0
def roll(msg):
    """Aircraft roll angle
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle in degrees,
               negative->left wing down, positive->right wing down
    """
    d = util.hex2bin(data(msg))
    sign = int(d[1])  # 1 -> left wing down
    value = util.bin2int(d[2:11]) * 45 / 256.0  # degree
    angle = -1 * value if sign else value
    return round(angle, 1)
Example #40
0
def roll(msg):
    """Aircraft roll angle
    Args:
        msg (String): 28 bytes hexadecimal message (BDS50) string
    Returns:
        float: angle in degrees,
               negative->left wing down, positive->right wing down
    """
    d = util.hex2bin(data(msg))
    sign = int(d[1])    # 1 -> left wing down
    value = util.bin2int(d[2:11]) * 45 / 256.0    # degree
    angle = -1 * value if sign else value
    return round(angle, 1)
Example #41
0
def checkbits(data, sb, msb, lsb):
    """Check if the status bit and field bits are consistency. This Function
        is used for checking BDS code versions.
    """
    # status bit, most significant bit, least significant bit
    status = int(data[sb - 1])
    value = util.bin2int(data[msb - 1:lsb])

    if not status:
        if value != 0:
            return False

    return True
Example #42
0
def checkbits(data, sb, msb, lsb):
    """Check if the status bit and field bits are consistency. This Function
        is used for checking BDS code versions.
    """
    # status bit, most significant bit, least significant bit
    status = int(data[sb-1])
    value = util.bin2int(data[msb-1:lsb])

    if not status:
        if value != 0:
            return False

    return True
Example #43
0
def surface_position_with_ref(msg, lat_ref, lon_ref):
    """Decode surface position with only one message,
    knowing reference nearby location, such as previously calculated location,
    ground station, or airport location, etc. The reference position shall
    be with in 45NM 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
    """

    i = oe_flag(msg)
    d_lat = 90.0 / 59 if i else 90.0 / 60

    msgbin = util.hex2bin(msg)
    cprlat = util.bin2int(msgbin[54:71]) / 131072.0
    cprlon = util.bin2int(msgbin[71:88]) / 131072.0

    j = util.floor(lat_ref / d_lat) \
        + util.floor(0.5 + ((lat_ref % d_lat) / d_lat) - cprlat)

    lat = d_lat * (j + cprlat)

    ni = _cprNL(lat) - i

    if ni > 0:
        d_lon = 90.0 / ni
    else:
        d_lon = 90.0

    m = util.floor(lon_ref / d_lon) \
        + util.floor(0.5 + ((lon_ref % d_lon) / d_lon) - cprlon)

    lon = d_lon * (m + cprlon)

    return round(lat, 5), round(lon, 5)
Example #44
0
def isBDS40(msg):
    """Check if a message is likely to be BDS code 4,0
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        bool: True or False
    """
    # status bit 1, 14, and 27
    d = util.hex2bin(data(msg))

    result = True

    result = result & checkbits(d, 1, 2, 13) \
        & checkbits(d, 14, 15, 26) & checkbits(d, 27, 28, 39)

    # bits 40-47 and 52-53 shall all be zero
    if util.bin2int(d[39:47]) != 0:
        result &= False

    if util.bin2int(d[51:53]) != 0:
        result &= False

    return result
Example #45
0
def isBDS40(msg):
    """Check if a message is likely to be BDS code 4,0
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        bool: True or False
    """
    # status bit 1, 14, and 27
    d = util.hex2bin(data(msg))

    result = True

    result = result & checkbits(d, 1, 2, 13) \
        & checkbits(d, 14, 15, 26) & checkbits(d, 27, 28, 39)

    # bits 40-47 and 52-53 shall all be zero
    if util.bin2int(d[39:47]) != 0:
        result &= False

    if util.bin2int(d[51:53]) != 0:
        result &= False

    return result
Example #46
0
def icao(msg):
    """Calculate the ICAO address from an Mode-S message
        with DF4, DF5, DF20, DF21
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        String: ICAO address in 6 bytes hexadecimal string
    """

    if df(msg) not in (4, 5, 20, 21):
        # raise RuntimeError("Message DF must be in (4, 5, 20, 21)")
        return None

    c0 = util.bin2int(crc(msg, encode=True))
    c1 = util.hex2int(msg[-6:])
    icao = '%06X' % (c0 ^ c1)
    return icao
Example #47
0
def icao(msg):
    """Calculate the ICAO address from an Mode-S message
        with DF4, DF5, DF20, DF21
    Args:
        msg (String): 28 bytes hexadecimal message string
    Returns:
        String: ICAO address in 6 bytes hexadecimal string
    """

    if df(msg) not in (4, 5, 20, 21):
        # raise RuntimeError("Message DF must be in (4, 5, 20, 21)")
        return None

    c0 = util.bin2int(crc(msg, encode=True))
    c1 = util.hex2int(msg[-6:])
    icao = '%06X' % (c0 ^ c1)
    return icao
Example #48
0
def altitude(msg):
    """Decode aircraft altitude
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: altitude in feet
    """
    if typecode(msg) < 9 or typecode(msg) > 18:
        raise RuntimeError("%s: Not a position message" % msg)

    msgbin = util.hex2bin(msg)
    q = msgbin[47]
    if q:
        n = util.bin2int(msgbin[40:47]+msgbin[48:52])
        alt = n * 25 - 1000
        return alt
    else:
        return None
Example #49
0
def altitude(msg):
    """Decode aircraft altitude
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: altitude in feet
    """
    if typecode(msg) < 9 or typecode(msg) > 18:
        raise RuntimeError("%s: Not a position message" % msg)

    msgbin = util.hex2bin(msg)
    q = msgbin[47]
    if q:
        n = util.bin2int(msgbin[40:47] + msgbin[48:52])
        alt = n * 25 - 1000
        return alt
    else:
        return None
Example #50
0
def nic(msg):
    """Calculate NIC, navigation integrity category
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: NIC number (from 0 to 11), -1 if not applicable
    """
    if typecode(msg) < 9 or typecode(msg) > 18:
        raise RuntimeError(
            "%s: Not a airborne position message, expecting 8<TC<19" % msg)

    msgbin = util.hex2bin(msg)
    tc = typecode(msg)
    nic_sup_b = util.bin2int(msgbin[39])

    if tc in [0, 18, 22]:
        nic = 0
    elif tc == 17:
        nic = 1
    elif tc == 16:
        if nic_sup_b:
            nic = 3
        else:
            nic = 2
    elif tc == 15:
        nic = 4
    elif tc == 14:
        nic = 5
    elif tc == 13:
        nic = 6
    elif tc == 12:
        nic = 7
    elif tc == 11:
        if nic_sup_b:
            nic = 9
        else:
            nic = 8
    elif tc in [10, 21]:
        nic = 10
    elif tc in [9, 20]:
        nic = 11
    else:
        nic = -1
    return nic
Example #51
0
def nic(msg):
    """Calculate NIC, navigation integrity category
    Args:
        msg (string): 28 bytes hexadecimal message string
    Returns:
        int: NIC number (from 0 to 11), -1 if not applicable
    """
    if typecode(msg) < 9 or typecode(msg) > 18:
        raise RuntimeError("%s: Not a airborne position message" % msg)

    msgbin = util.hex2bin(msg)
    tc = typecode(msg)
    nic_sup_b = util.bin2int(msgbin[39])

    if tc in [0, 18, 22]:
        nic = 0
    elif tc == 17:
        nic = 1
    elif tc == 16:
        if nic_sup_b:
            nic = 3
        else:
            nic = 2
    elif tc == 15:
        nic = 4
    elif tc == 14:
        nic = 5
    elif tc == 13:
        nic = 6
    elif tc == 12:
        nic = 7
    elif tc == 11:
        if nic_sup_b:
            nic = 9
        else:
            nic = 8
    elif tc in [10, 21]:
        nic = 10
    elif tc in [9, 20]:
        nic = 11
    else:
        nic = -1
    return nic
Example #52
0
def callsign(msg):
    """Aircraft callsign
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        string: callsign, max. 8 chars
    """
    chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'

    d = util.hex2bin(data(msg))

    cs = ''
    cs += chars[util.bin2int(d[8:14])]
    cs += chars[util.bin2int(d[14:20])]
    cs += chars[util.bin2int(d[20:26])]
    cs += chars[util.bin2int(d[26:32])]
    cs += chars[util.bin2int(d[32:38])]
    cs += chars[util.bin2int(d[38:44])]
    cs += chars[util.bin2int(d[44:50])]
    cs += chars[util.bin2int(d[50:56])]

    return cs
Example #53
0
def altitude_diff(msg):
    """Decode the differece between GNSS and barometric altitude
    Args:
        msg (string): 28 bytes hexadecimal message string, TC=19
    Returns:
        int: Altitude difference in ft. Negative value indicates GNSS altitude
            below barometric altitude.
    """

    if typecode(msg) != 19:
        raise RuntimeError("incorrect message types, expecting TC=19")

    msgbin = util.hex2bin(msg)
    sign = -1 if int(msgbin[80]) else 1
    value = util.bin2int(msgbin[81:88])

    if value == 0 or value == 127:
        return None
    else:
        return sign * (value - 1) * 25  # in ft.
Example #54
0
def callsign(msg):
    """Aircraft callsign
    Args:
        msg (String): 28 bytes hexadecimal message (BDS40) string
    Returns:
        string: callsign, max. 8 chars
    """
    chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'

    d = util.hex2bin(data(msg))

    cs = ''
    cs += chars[util.bin2int(d[8:14])]
    cs += chars[util.bin2int(d[14:20])]
    cs += chars[util.bin2int(d[20:26])]
    cs += chars[util.bin2int(d[26:32])]
    cs += chars[util.bin2int(d[32:38])]
    cs += chars[util.bin2int(d[38:44])]
    cs += chars[util.bin2int(d[44:50])]
    cs += chars[util.bin2int(d[50:56])]

    return cs
Example #55
0
def position(msg0, msg1, t0, t1):
    """Decode position from the combination of even and odd position message
        131072 is 2^17, since CPR lat and lon are 17 bits each.
    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
    """
    if typecode(msg0) < 5 or typecode(msg0) > 18:
        raise RuntimeError("%s: Not a position message" % msg0)

    if typecode(msg1) < 5 or typecode(msg1) > 18:
        raise RuntimeError("%s: Not a position message" % msg1)

    msgbin0 = util.hex2bin(msg0)
    msgbin1 = util.hex2bin(msg1)

    cprlat_even = util.bin2int(msgbin0[54:71]) / 131072.0
    cprlon_even = util.bin2int(msgbin0[71:88]) / 131072.0
    cprlat_odd = util.bin2int(msgbin1[54:71]) / 131072.0
    cprlon_odd = util.bin2int(msgbin1[71:88]) / 131072.0

    air_d_lat_even = 360.0 / 60
    air_d_lat_odd = 360.0 / 59

    # compute latitude index 'j'
    j = int(math.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5))

    lat_even = float(air_d_lat_even * (j % 60 + cprlat_even))
    lat_odd = float(air_d_lat_odd * (j % 59 + cprlat_odd))

    if lat_even >= 270:
        lat_even = lat_even - 360

    if lat_odd >= 270:
        lat_odd = lat_odd - 360

    # check if both are in the same latidude zone, exit if not
    if _cprNL(lat_even) != _cprNL(lat_odd):
        return None

    # compute ni, longitude index m, and longitude
    if (t0 > t1):
        ni = _cprN(lat_even, 0)
        m = math.floor(cprlon_even * (_cprNL(lat_even)-1) -
                       cprlon_odd * _cprNL(lat_even) + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_even)
        lat = lat_even
    else:
        ni = _cprN(lat_odd, 1)
        m = math.floor(cprlon_even * (_cprNL(lat_odd)-1) -
                       cprlon_odd * _cprNL(lat_odd) + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_odd)
        lat = lat_odd

    if lon > 180:
        lon = lon - 360

    return round(lat, 5), round(lon, 5)
Example #56
0
def surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref):
    """Decode surface position from a pair of even and odd position message,
    the lat/lon of receiver must be provided to yield the correct solution.
    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
        lat_ref (float): latitude of the receiver
        lon_ref (float): longitude of the receiver
    Returns:
        (float, float): (latitude, longitude) of the aircraft
    """

    msgbin0 = util.hex2bin(msg0)
    msgbin1 = util.hex2bin(msg1)

    # 131072 is 2^17, since CPR lat and lon are 17 bits each.
    cprlat_even = util.bin2int(msgbin0[54:71]) / 131072.0
    cprlon_even = util.bin2int(msgbin0[71:88]) / 131072.0
    cprlat_odd = util.bin2int(msgbin1[54:71]) / 131072.0
    cprlon_odd = util.bin2int(msgbin1[71:88]) / 131072.0

    air_d_lat_even = 90.0 / 60
    air_d_lat_odd = 90.0 / 59

    # compute latitude index 'j'
    j = util.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5)

    # solution for north hemisphere
    lat_even_n = float(air_d_lat_even * (j % 60 + cprlat_even))
    lat_odd_n = float(air_d_lat_odd * (j % 59 + cprlat_odd))

    # solution for north hemisphere
    lat_even_s = lat_even_n - 90.0
    lat_odd_s = lat_odd_n - 90.0

    # chose which solution corrispondes to receiver location
    lat_even = lat_even_n if lat_ref > 0 else lat_even_s
    lat_odd = lat_odd_n if lat_ref > 0 else lat_odd_s

    # check if both are in the same latidude zone, rare but possible
    if _cprNL(lat_even) != _cprNL(lat_odd):
        return None

    # compute ni, longitude index m, and longitude
    if (t0 > t1):
        lat = lat_even
        nl = _cprNL(lat_even)
        ni = max(_cprNL(lat_even) - 0, 1)
        m = util.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
        lon = (90.0 / ni) * (m % ni + cprlon_even)
    else:
        lat = lat_odd
        nl = _cprNL(lat_odd)
        ni = max(_cprNL(lat_odd) - 1, 1)
        m = util.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
        lon = (90.0 / ni) * (m % ni + cprlon_odd)

    # four possible longitude solutions
    lons = [lon, lon + 90.0, lon + 180.0, lon + 270.0]

    # the closest solution to receiver is the correct one
    dls = [abs(lon_ref - l) for l in lons]
    imin = min(range(4), key=dls.__getitem__)
    lon = lons[imin]

    return round(lat, 5), round(lon, 5)
Example #57
0
def position(msg0, msg1, t0, t1):
    """Decode position from the combination of even and odd position message
        131072 is 2^17, since CPR lat and lon are 17 bits each.
    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
    """
    if typecode(msg0) < 5 or typecode(msg0) > 18:
        raise RuntimeError("%s: Not a position message" % msg0)

    if typecode(msg1) < 5 or typecode(msg1) > 18:
        raise RuntimeError("%s: Not a position message" % msg1)

    msgbin0 = util.hex2bin(msg0)
    msgbin1 = util.hex2bin(msg1)

    cprlat_even = util.bin2int(msgbin0[54:71]) / 131072.0
    cprlon_even = util.bin2int(msgbin0[71:88]) / 131072.0
    cprlat_odd = util.bin2int(msgbin1[54:71]) / 131072.0
    cprlon_odd = util.bin2int(msgbin1[71:88]) / 131072.0

    air_d_lat_even = 360.0 / 60
    air_d_lat_odd = 360.0 / 59

    # compute latitude index 'j'
    j = int(math.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5))

    lat_even = float(air_d_lat_even * (j % 60 + cprlat_even))
    lat_odd = float(air_d_lat_odd * (j % 59 + cprlat_odd))

    if lat_even >= 270:
        lat_even = lat_even - 360

    if lat_odd >= 270:
        lat_odd = lat_odd - 360

    # check if both are in the same latidude zone, exit if not
    if _cprNL(lat_even) != _cprNL(lat_odd):
        return None

    # compute ni, longitude index m, and longitude
    if (t0 > t1):
        ni = _cprN(lat_even, 0)
        m = math.floor(cprlon_even * (_cprNL(lat_even) - 1) -
                       cprlon_odd * _cprNL(lat_even) + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_even)
        lat = lat_even
    else:
        ni = _cprN(lat_odd, 1)
        m = math.floor(cprlon_even * (_cprNL(lat_odd) - 1) -
                       cprlon_odd * _cprNL(lat_odd) + 0.5)
        lon = (360.0 / ni) * (m % ni + cprlon_odd)
        lat = lat_odd

    if lon > 180:
        lon = lon - 360

    return round(lat, 5), round(lon, 5)