예제 #1
0
def TimeUtc(fields):
    seconds, fractional_seconds = FloatSplit(float(fields['seconds']))
    microseconds = int(math.floor(fractional_seconds * 1e6))

    fields['seconds'] = seconds
    fields['microseconds'] = microseconds
    fields['hours'] = util.MaybeToNumber(fields['hours'])
    fields['minutes'] = util.MaybeToNumber(fields['minutes'])

    when = datetime.time(fields['hours'], fields['minutes'], seconds,
                         microseconds)
    fields['when'] = when
예제 #2
0
def Zda(line):
  try:
    fields = ZDA_RE.match(line).groupdict()
  except TypeError:
    return

  for field in ('year', 'month', 'day', 'hours', 'minutes', 'zone_hours',
                'zone_minutes'):
    if fields[field] is not None and fields[field]:
      fields[field] = util.MaybeToNumber(fields[field])

  seconds, fractional_seconds = FloatSplit(float(fields['seconds']))
  microseconds = int(math.floor(fractional_seconds * 1e6))
  when = datetime.datetime(
      fields['year'],
      fields['month'],
      fields['day'],
      fields['hours'],
      fields['minutes'],
      seconds,
      microseconds)

  # TODO(schwehr): Convert this to Unix UTC seconds.
  result = {
      'msg': 'ZDA',
      'talker': fields['talker'],
      'datetime': when,
      'zone_hours': fields['zone_hours'],
      'zone_minutes': fields['zone_minutes'],
  }

  return result
예제 #3
0
def Txt(line):
  """Decode Text Transmission (TXT).

  TODO(schwehr): Handle encoded characters.  e.g. ^21 is a '!'.

  Args:
    line: A string containing a NMEA TXT message.

  Return:
    A dictionary with the decoded fields.
  """
  try:
    fields = TXT_RE.match(line).groupdict()
  except TypeError:
    return

  result = {
      'msg': 'TXT',
      'talker': fields['talker'],
      'text': fields['text'],
  }

  for field in ('sen_tot', 'sen_num', 'seq_num'):
    result[field] = util.MaybeToNumber(fields[field])

  return result
예제 #4
0
def Fsr(line):
  try:
    fields = FSR_RE.match(line).groupdict()
  except TypeError:
    return

  seconds, fractional_seconds = FloatSplit(float(fields['seconds']))
  microseconds = int(math.floor(fractional_seconds * 1e6))

  when = datetime.time(
      int(fields['hours']),
      int(fields['minutes']),
      seconds,
      microseconds
  )

  result = {
      'msg': 'FSR',
      'id': fields['id'],
      'chan': fields['chan'],
      'time': when,
  }
  for field in ('slots_recv', 'slots_self', 'crc_fails', 'slots_reserved',
                'slots_reserved_self', 'noise_db', 'slots_above_noise'):
    if fields[field] is not None and fields[field]:
      result[field] = util.MaybeToNumber(fields[field])

  return result
예제 #5
0
def HandleGga(line):
    try:
        fields = GGA_RE.match(line).groupdict()
    except TypeError:
        return

    seconds, fractional_seconds = FloatSplit(float(fields['seconds']))
    microseconds = int(math.floor(fractional_seconds * 1e6))

    when = datetime.time(int(fields['hours']), int(fields['minutes']), seconds,
                         microseconds)

    x = int(fields['lon_deg']) + float(fields['lon_min']) / 60.0
    if fields['longitude_hemisphere'] == 'W':
        x = -x

    y = int(fields['lat_deg']) + float(fields['lat_min']) / 60.0
    if fields['latitude_hemisphere'] == 'S':
        y = -y

    result = {
        'message': 'GGA',
        'time': when,
        'longitude': x,
        'latitude': y,
    }
    for field in ('gps_quality', 'satellites', 'hdop', 'antenna_height',
                  'antenna_height_units', 'geoidal_height',
                  'geoidal_height_units', 'differential_ref_station',
                  'differential_age_sec'):
        if fields[field] is not None and fields[field]:
            result[field] = util.MaybeToNumber(fields[field])

    return result
예제 #6
0
파일: tag_block.py 프로젝트: hsiboy/seabus
def Parse(data):
  """Unpack a TAG Block line or return None.

  Makes sure that the line matches the regex and the checksum matches.

  Args:
    data: Line of text or a dict from at TAG_BLOCK_RE.

  Returns:
    A NMEA TAG Block dict or None if the line would not parse or has
    an invalid checksum.
  """
  if isinstance(data, str):
    try:
      result = TAG_BLOCK_RE.search(data).groupdict()
    except AttributeError:
      return
  elif isinstance(data, dict):
    result = data
  else:
    return

  result.update({k: util.MaybeToNumber(v)
                 for k, v in six.iteritems(result) if k in NUMERIC_FIELDS})

  actual = nmea.Checksum(result['metadata'])
  expected = result['tag_checksum'].upper()
  if actual != expected:
    return

  return result
예제 #7
0
def Abk(line):
  """Decode AIS Addressed and Binary Broadcast Acknowledgement (ABK)."""
  try:
    fields = ABK_RE.match(line).groupdict()
  except TypeError:
    return

  result = {
      'msg': 'ABK',
      'talker': fields['talker'],
      'chan': fields['chan'],
  }

  for field in ('mmsi', 'msg_id', 'seq_num', 'ack_type'):
    result[field] = util.MaybeToNumber(fields[field])

  return result
예제 #8
0
def Bbm(line):
  """Decode Binary Broadcast Message (BBM) sentence."""
  try:
    fields = BBM_RE.match(line).groupdict()
  except TypeError:
    return

  result = {
      'msg': 'BBM',
      'talker': fields['talker'],
      'body': fields['body'],
  }

  for field in ('sen_tot', 'sen_num', 'seq_num', 'chan', 'msg_id', 'fill_bits'):
    result[field] = util.MaybeToNumber(fields[field])

  return result
예제 #9
0
def HandleAds(line):
    """Decode Automatic Device Status (ADS)."""
    try:
        fields = ADS_RE.match(line).groupdict()
    except TypeError:
        return

    TimeUtc(fields)

    return {
        'message': 'ADS',
        'talker': fields['talker'],
        'id': fields['id'],
        'alarm': fields['alarm'],
        'time_sync_method': util.MaybeToNumber(fields['time_sync_method']),
        'pos_src': fields['pos_src'],
        'time_src': fields['time_src'],
        'when': fields['when'],
    }
예제 #10
0
def Parse(data):
  """Unpack a USCG old metadata format line or return None.

  Makes sure that the line matches the regex and the checksum matches.

  Args:
    data: Line of text.

  Returns:
    A vdm dict or None and a metadata dict or None.
  """
  try:
    result = USCG_RE.search(data).groupdict()
  except AttributeError:
    return None

  result.update({k: util.MaybeToNumber(v)
                 for k, v in six.iteritems(result) if k in NUMERIC_FIELDS})

  return result
예제 #11
0
def Parse(data):
    """Unpack a NMEA VDM AIS message line(s)."""

    if not isinstance(data, six.string_types):
        raise NotImplementedError

    try:
        result = VDM_RE.search(data).groupdict()
    except AttributeError:
        return

    result.update({
        k: util.MaybeToNumber(v)
        for k, v in six.iteritems(result) if k in NUMERIC_FIELDS
    })

    actual = nmea.Checksum(result['vdm'])
    expected = result['checksum']
    if actual != expected:
        return

    return result
예제 #12
0
  def put(self, line, line_num=None):
    if line_num is not None:
      self.line_num = line_num
    else:
      self.line_num += 1

    line = line.rstrip()
    metadata_match = Parse(line)
    match = vdm.Parse(line)

    if not match:
      logging.info('not match')
      msg = {
          'line_nums': [self.line_num],
          'lines': [line],
      }
      if metadata_match:
        msg['match'] = metadata_match
      Queue.Queue.put(self, msg)
      return

    if not metadata_match:
      logging.info('not metadata match')
      self.unknown_queue.put(line)
      if not self.unknown_queue.empty():
        msg = Queue.Queue.get()
        self.put(msg)
      return

    match.update(metadata_match)

    if 'station' not in match:
      match['station'] = 'rUnknown'

    sentence_tot = int(match['sen_tot'])

    if sentence_tot == 1:
      body = match['body']
      fill_bits = int(match['fill_bits'])
      try:
        decoded = ais.decode(body, fill_bits)
      except ais.DecodeError as error:
        logging.error(
            'Unable to decode message: %s\n  %d %s', error, self.line_num, line)
        return
      decoded['md5'] = hashlib.md5(body.encode('utf-8')).hexdigest()
      Queue.Queue.put(self, {
          'line_nums': [line_num],
          'lines': [line],
          'decoded': decoded,
          'matches': [match]
      })
      return

    station = match['station'] or 'rUnknown'
    sentence_num = int(match['sen_num'])
    sequence_id = match['seq_id'] or ''
    group_id = station + str(sequence_id)
    time = util.MaybeToNumber(match['time'])

    if group_id not in self.groups:
      self.groups[group_id] = []

    if not self.groups[group_id]:
      if sentence_num != 1:
        # Drop a partial AIS message.
        return

    if sentence_num == 1:
      self.groups[group_id] = {
          'line_nums': [self.line_num],
          'lines': [line],
          'matches': [match],
          'times': [time],
      }
      return

    entry = self.groups[group_id]
    entry['line_nums'].append(self.line_num)
    entry['lines'].append(line)
    entry['matches'].append(match)
    entry['times'].append(time)

    if sentence_num != sentence_tot:
      # Found the middle part of a message.
      return

    decoded = DecodeMultiple(entry)

    if decoded:
      entry['decoded'] = decoded
    else:
      logging.info('Unable to process: %s', entry)
    Queue.Queue.put(self, entry)
    self.groups.pop(group_id)
예제 #13
0
파일: tag_block.py 프로젝트: hsiboy/seabus
  def put(self, line, line_num=None):
    if line_num is not None:
      self.line_num = line_num
    else:
      self.line_num += 1

    line = line.rstrip()
    match = Parse(line)

    if not match:
      Queue.Queue.put(self, {
          'line_nums': [self.line_num],
          'lines': [line],
      })
      return

    time = util.MaybeToNumber(match['time'])

    if not match['group']:
      msg = {
          'line_nums': [self.line_num],
          'lines': [line],
          'matches': [match],
          'times': [time],
      }
      decoded = DecodeTagSingle(msg)
      if decoded:
        msg['decoded'] = decoded
      else:
        logging.info('Unable to decode. Passing without decoded block.')
        decoded = nmea_messages.Decode(match['payload'])
        if decoded:
          msg['decoded'] = decoded
        else:
          logging.info('No NMEA match for line: %d, %s', line_num, line)
      Queue.Queue.put(self, msg)
      return

    sentence_num = int(match['sentence_num'])
    sentence_total = int(match['sentence_tot'])
    group_id = int(match['group_id'])

    if sentence_num == 1:
      self.groups[group_id] = {
          'line_nums': [self.line_num],
          'lines': [line],
          'matches': [match],
          'times': [time],
      }
      return

    if group_id not in self.groups:
      logging.error('group_id not in groups: %d', group_id)
      return

    entry = self.groups[group_id]
    entry['line_nums'].append(self.line_num)
    entry['lines'].append(line)
    entry['matches'].append(match)
    entry['times'].append(time)

    if sentence_num != sentence_total:
      # Found the middle part of a message.
      return

    # Found the final message in a group.
    decoded = DecodeTagMultiple(entry)
    if decoded:
      entry['decoded'] = decoded
    else:
      logging.info('Unable to process: %s', entry)
    Queue.Queue.put(self, entry)
    self.groups.pop(group_id)
예제 #14
0
  def testMaybeToNumber(self):
    self.assertEqual(util.MaybeToNumber(None), None)
    self.assertEqual(util.MaybeToNumber([]), [])
    self.assertEqual(util.MaybeToNumber({}), {})
    self.assertEqual(util.MaybeToNumber('a'), 'a')
    self.assertEqual(util.MaybeToNumber(1), 1)
    self.assertEqual(util.MaybeToNumber(-3.12), -3.12)

    self.assertEqual(util.MaybeToNumber('-1'), -1)
    self.assertIsInstance(util.MaybeToNumber('-1'), int)

    self.assertEqual(util.MaybeToNumber('42.0'), 42.0)
    self.assertIsInstance(util.MaybeToNumber('42.0'), float)

    value = 9999999999999999999999999
    value_str = '9999999999999999999999999'
    self.assertEqual(util.MaybeToNumber(value_str), value)
    self.assertIsInstance(util.MaybeToNumber(value_str), six.integer_types)

    self.assertEqual(
        util.MaybeToNumber('1e99999999999999999999999'), float('inf'))
    self.assertEqual(
        util.MaybeToNumber('-1e99999999999999999999999'), float('-inf'))