Exemplo n.º 1
0
    def message(self, msg):
        # Printout of statistics
        if self.signal_hup == 1:
            self.logstats()
            self.signal_hup = 0

        ret_dict = {}
        ret_dict['ret'] = 0
        ret_dict['type'] = ""

        self.msgs_curr_total = self.msgs_curr_total + 1

        if len(msg) == 26 or len(msg) == 40:
            # Some version of dump1090 have the 12 first characters used w/
            # some date (timestamp ?). E.g. sdbr245 feeding flightradar24.
            # Strip 12 first characters.
            msg = msg[12:]

        if len(msg) < 28:  # Message length 112 bits
            self.msgs_curr_short = self.msgs_curr_short + 1
        else:
            self.msgs_curr_len28 = self.msgs_curr_len28 + 1

        ret_dict['crc'] = self.check_msg(msg)
        if ret_dict['crc']:
            self.parity_check_ok = self.parity_check_ok + 1
        else:
            self.parity_check_ko = self.parity_check_ko + 1

        # Do not manage messages with bad CRC
        if ret_dict['crc'] is not True:
            raise ValueError("CrcKO")

        dfmt = common.df(msg)
        ret_dict['dfmt'] = dfmt
        self.df[dfmt] = self.df[dfmt] + 1

        ret_dict['ic'] = common.icao(msg)

        if dfmt in [17, 18]:  # Downlink format 17 or 18
            tc = common.typecode(msg)
            ret_dict['tc'] = tc
            self.tc[tc] = self.tc[tc] + 1

            lat_ref = float(self.params["lat"])
            long_ref = float(self.params["long"])

            if tc == 4:  # Aircraft identification
                self.msgs_discovered = self.msgs_discovered + 1
                ret_dict['type'] = "CS"
                ret_dict['cs'] = adsb.callsign(msg)
                ca = adsb_ca(msg)
                ret_dict['ca'] = ca_msg[ca]
                self.ca[ca] = self.ca[ca] + 1
            elif 9 <= tc <= 18:
                self.msgs_discovered = self.msgs_discovered + 1
                ret_dict['type'] = "LB"
                ret_dict['altb'] = adsb.altitude(msg)
                (lat, long) = adsb.position_with_ref(msg, lat_ref, long_ref)
                ret_dict['lat'] = lat
                ret_dict['long'] = long
            elif tc == 19:
                self.msgs_discovered = self.msgs_discovered + 1
                ret_dict['type'] = "VH"
                _dict = adsb.velocity(msg)
                if _dict is None:
                    raise ValueError("AdsbVelocity")
                (ret_dict['speed'], ret_dict['head'], ret_dict['rocd'],
                 var) = _dict
                if ret_dict['head'] is None:
                    raise ValueError("AdsbHeading")
                if ret_dict['rocd'] is None:
                    raise ValueError("AdsbRocd")
            elif 20 <= tc <= 22:
                self.msgs_discovered = self.msgs_discovered + 1
                ret_dict['type'] = "LG"
                ret_dict['altg'] = adsb.altitude(msg)
                (lat, long) = adsb.position_with_ref(msg, lat_ref, long_ref)
                ret_dict['lat'] = lat
                ret_dict['long'] = long
        elif dfmt in [5, 21]:
            self.msgs_discovered = self.msgs_discovered + 1
            ret_dict['type'] = "SQ"
            ret_dict['sq'] = common.idcode(msg)

        if dfmt in [0, 4, 16, 20]:
            self.msgs_discovered = self.msgs_discovered + 1
            ret_dict['type'] = "AL"
            _alt = common.altcode(msg)
            alt = _alt if _alt is not None else 0
            ret_dict['alt'] = alt

        return ret_dict
Exemplo n.º 2
0
def test_adsb_position_with_ref():
    pos = adsb.position_with_ref("8D40058B58C901375147EFD09357", 49.0, 6.0)
    assert pos == (49.82410, 6.06785)
    pos = adsb.position_with_ref("8FC8200A3AB8F5F893096B000000", -43.5, 172.5)
    assert pos == (-43.48564, 172.53942)
Exemplo n.º 3
0
  def _parse(self, msg_ascii):
    if not msg_ascii or msg_ascii[0] != '*':
      raise ValueError

    msg_hex = msg_ascii[1:].split(';', 1)[0]

    try:
      icao = adsb.icao(msg_hex).lower()
      downlink_format = df(msg_hex)
      type_code = adsb.typecode(msg_hex)
    except:
      raise ValueError

    # version 0 is assumed, so populate it on initialisation
    ac_data = self.positions.get(icao, {"version": 0})

    if downlink_format == 17 or downlink_format == 18:
      # An aircraft airborne position message has downlink format 17 (or 18) with
      # type code from 9 to 18 (baro altitude) or 20 to 22 (GNSS altitude)
      # ref https://mode-s.org/decode/adsb/airborne-position.html
      if ac_data.get("version", None) == 1 and ac_data.get("nic_s", None):
        ac_data["nic"] = adsb.nic_v1(msg_hex, ac_data["nic_s"])

      if (type_code >= 1 and type_code <= 4):
        # Slightly normalise the callsign - it's supposed to only be [0-9A-Z]
        # with space padding. PyModeS uses _ padding, which I think is an older
        # version of the spec.
        ac_data["callsign"] = adsb.callsign(msg_hex).upper().replace("_", " ")[:8]
        ac_data["emitter_category"] = adsb.category(msg_hex)
      elif (type_code >= 9 and type_code <= 18) or (type_code >= 20 and type_code <= 22):
        nuc_p = None
        if ac_data.get("version", None) == 0:
          # In ADSB version 0, the type code encodes the nuc_p (navigational
          # uncertianty category - position) value via this magic lookup table
          nuc_p_lookup = {
            9: 9,
            10: 8,
            11: 7,
            12: 6,
            13: 5,
            14: 4,
            15: 3,
            16: 2,
            17: 1,
            18: 0,
            20: 9,
            21: 8,
            22: 0,
          }
          ac_data["nuc_p"] = nuc_p_lookup.get(type_code, None)

        elif ac_data.get("version", None) == 2:
          ac_data["nic_b"] = adsb.nic_b(msg_hex)

        if ac_data.get("version", None) == 2 and "nic_a" in ac_data.keys() and "nic_c" in ac_data.keys():
          nic_a = ac_data["nic_a"]
          nic_c = ac_data["nic_c"]
          ac_data["nic"] = adsb.nic_v2(msg_hex, nic_a, nic_c)

        # Aircraft position
        if not self.gps.is_fresh():
          #print("aircraft: not updating {0} df={1} tc={2} as my GPS position is unknown ({3})".format(icao, downlink_format, type_code, msg_hex))
          raise ValueError

        # Use the known location of the receiver to calculate the aircraft position
        # from one messsage
        try:
          my_latitude, my_longitude = self.gps.position()
        except NoFixError:
          # For testing
          my_latitude, my_longitude = (51.519559, -0.114227)
          # a rare race condition
          #raise ValueError

        ac_lat, ac_lon = adsb.position_with_ref(msg_hex, my_latitude, my_longitude)
        #print("aircraft: update {0} df={1} tc={2} {3}, {4} ({5})".format(icao, downlink_format, type_code, ac_lat, ac_lon, msg_hex))

        ac_data["lat"] = ac_lat
        ac_data["lon"] = ac_lon

      elif type_code == 19:
        # From the docs: returns 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).
        if ac_data.get("version", None) == 1 or ac_data.get("version", None) == 2:
          ac_data["nac_v"] = adsb.nac_v(msg_hex)

        try:
          (speed, track, climb, speed_source, track_source, climb_source) = adsb.velocity(msg_hex, rtn_sources=True)
          ac_data["speed_h"] = speed
          ac_data["track"] = track
          ac_data["speed_v"] = climb
          ac_data["speed_h_source"] = speed_source
          ac_data["track_source"] = track_source
          ac_data["speed_v_source"] = climb_source
        except TypeError:
          # adsb.velocity can return None
          raise ValueError

      elif type_code == 31:
        # Operational status
        version = adsb.version(msg_hex)
        nic_s = adsb.nic_s(msg_hex)

        # v0 nuc_p is determined by type_code above
        if version == 1:
          try:
            # Is this the right place for nucp? The docs say yes, but one error
            # I've received says 8d3c5ee6f81300000039283c21cf: Not a surface
            # position message (5<TC<8), airborne position message (8<TC<19),
            # or airborne position with GNSS height (20<TC<22)
            nuc_p = adsb.nuc_p(msg_hex)
            nuc_v = adsb.nuc_v(msg_hex)
          except RuntimeError as e:
            print("aircraft: error parsing v1 NUC: {}".format(e))
            raise ValueError

          ac_data["nic_s"] = nic_s
          ac_data["nuc_p"] = nuc_p
          ac_data["nuc_v"] = nuc_v
          ac_data["nac_p"] = adsb.nac_p(msg_hex)
          ac_data["sil"] = adsb.sil(msg_hex, version)
        elif version == 2:
          ac_data["nac_p"] = adsb.nac_p(msg_hex)
          (nic_a, nic_c) = adsb.nic_a_c(msg_hex)
          ac_data["nic_a"] = nic_a
          ac_data["nic_c"] = nic_c
          ac_data["sil"] = adsb.sil(msg_hex, version)

        ac_data["version"] = version
        ac_data["nic_s"] = nic_s
      else:
        raise ValueError

    elif downlink_format == 4 or downlink_format == 20:
      altitude = adsb_common.altcode(msg_hex)
      ac_data["altitude"] = altitude
    else:
      # unsupported message
      raise ValueError

    ac_data["updated"] = datetime.now()
    self.positions[icao] = ac_data