Beispiel #1
0
/** Service an external event interrupt
 *
 * When an event occurs (i.e. pin edge) that matches the NAP's trigger
 * condition, the NAP will latch the time, pin number and trigger direction.
 * It will also set an IRQ bit which will lead to an EXTI.  The firmware
 * EXTI handling routine handle_nap_exti() will call this function, which
 * reads out the details and spits them out as an SBP message to our host.
 *
 */
void ext_event_service(void)
{
  u8 event_pin;
  ext_event_trigger_t event_trig;

  /* Read the details, and also clear IRQ + set up for next time */
  u32 event_nap_time = nap_rw_ext_event(&event_pin, &event_trig, trigger);
  
  /* We have to infer the most sig word (i.e. # of 262-second rollovers) */
  union {
    u32 half[2];
    u64 full;
  } tc;
  tc.full = nap_timing_count();
  if (tc.half[0] < event_nap_time)  /* Rollover occurred since event */
    tc.half[1]--;
  tc.half[0] = event_nap_time;

  /* Prepare the MSG_EXT_EVENT */
  msg_ext_event_t msg;
  msg.flags = (event_trig == TRIG_RISING) ? (1<<0) : (0<<0);
  if (time_quality == TIME_FINE)
    msg.flags |= (1 << 1);
  msg.pin = event_pin;

  /* Convert to the SBP convention of rounded ms + signed ns residual */
  gps_time_t gpst = rx2gpstime(tc.full);
  msg_gps_time_t mgt;
  sbp_make_gps_time(&mgt, &gpst, 0);
  msg.wn = mgt.wn;
  msg.tow = mgt.tow;
  msg.ns = mgt.ns;

  sbp_send_msg(SBP_MSG_EXT_EVENT, sizeof(msg), (u8 *)&msg);
}
Beispiel #2
0
/** Get current GPS time.
 *
 * \note The GPS time may only be a guess or completely unknown. time_quality
 *       should be checked first to determine the quality of the GPS time
 *       estimate.
 *
 * This function should be used only for approximate timing purposes as simply
 * calling this function does not give a well defined instant at which the GPS
 * time is queried.
 *
 * \return Current GPS time.
 */
gps_time_t get_current_time(void)
{
  /* TODO: Return invalid when TIME_UNKNOWN. */
  /* TODO: Think about what happens when nap_timing_count overflows. */
  u64 tc = nap_timing_count();
  gps_time_t t = rx2gpstime(tc);

  return t;
}
Beispiel #3
0
/** Retrieve a channel measurement for a tracker channel.
 *
 * \param id      ID of the tracker channel to use.
 * \param ref_tc  Reference timing count.
 * \param meas    Pointer to output channel_measurement_t.
 */
void tracking_channel_measurement_get(tracker_channel_id_t id, u64 ref_tc,
                                      channel_measurement_t *meas)
{
  tracker_channel_t *tracker_channel = tracker_channel_get(id);
  tracker_internal_data_t *internal_data =
      &tracker_channel->internal_data;
  const tracker_common_data_t *common_data = &tracker_channel->common_data;

  /* Update our channel measurement. */
  meas->sid = tracker_channel->info.sid;
  meas->code_phase_chips = common_data->code_phase_early;
  meas->code_phase_rate = common_data->code_phase_rate;
  meas->carrier_phase = common_data->carrier_phase;
  meas->carrier_freq = common_data->carrier_freq;
  meas->time_of_week_ms = common_data->TOW_ms;
  meas->rec_time_delta = (double)((s32)(common_data->sample_count - (u32)ref_tc))
                             / SAMPLE_FREQ;
  meas->snr = common_data->cn0;
  if (internal_data->bit_polarity == BIT_POLARITY_INVERTED) {
    meas->carrier_phase += 0.5;
  }
  meas->lock_counter = internal_data->lock_counter;

  /* Adjust carrier phase initial integer offset to be approximately equal to
     pseudorange. */
  if ((time_quality == TIME_FINE)
      && (internal_data->carrier_phase_offset == 0.0)) {
      gps_time_t tor = rx2gpstime(ref_tc + meas->rec_time_delta);
      gps_time_t tot;
      tot.tow = 1e-3 * meas->time_of_week_ms;
      tot.tow += meas->code_phase_chips / GPS_CA_CHIPPING_RATE;
      gps_time_match_weeks(&tot, &tor);
      internal_data->carrier_phase_offset = round(GPS_L1_HZ
                                                  * gpsdifftime(&tor, &tot));
  }
  meas->carrier_phase -= internal_data->carrier_phase_offset;
}
Beispiel #4
0
/** Manages acquisition searches and starts tracking channels after successful acquisitions. */
void manage_acq()
{
  /* Decide which PRN to try and then start it acquiring. */
  u8 prn = best_prn();
  if (prn == (u8)-1)
    return;

  u32 timer_count;
  float snr, cp, cf;

  acq_set_prn(prn);

  /* We have our PRN chosen, now load some fresh data
   * into the acquisition ram on the Swift NAP for
   * an initial coarse acquisition.
   */
  acq_prn_param[prn].state = ACQ_PRN_ACQUIRING;
  do {
    timer_count = nap_timing_count() + 20000;
    /* acq_load could timeout if we're preempted and miss the timing strobe */
  } while (!acq_load(timer_count));

  /* Done loading, now lets set that coarse acquisition going. */
  if (almanac[prn].valid && time_quality == TIME_COARSE) {
    gps_time_t t = rx2gpstime(timer_count);

    double dopp = -calc_sat_doppler_almanac(&almanac[prn], t.tow, t.wn, position_solution.pos_ecef);
    /* TODO: look into accuracy of prediction and possibilities for
     * improvement, e.g. use clock bias estimated by PVT solution. */
    /*log_info("Expecting PRN %02d @ %.1f\n", prn+1, dopp);*/
    acq_search(dopp - 4000, dopp + 4000, ACQ_FULL_CF_STEP);
  } else {
    acq_search(ACQ_FULL_CF_MIN, ACQ_FULL_CF_MAX, ACQ_FULL_CF_STEP);
  }

  /* Done with the coarse acquisition, check if we have found a
   * satellite, if so save the results and start the loading
   * for the fine acquisition. If not, start again choosing a
   * different PRN.
   */
  acq_get_results(&cp, &cf, &snr);
  /* Send result of an acquisition to the host. */
  acq_send_result(prn, snr, cp, cf);
  if (snr < ACQ_THRESHOLD) {
    /* Didn't find the satellite :( */
    acq_prn_param[prn].state = ACQ_PRN_TRIED;
    return;
  }

  log_info("acq: PRN %d found @ %d Hz, %d SNR\n", prn + 1, (int)cf, (int)snr);

  u8 chan = manage_track_new_acq(snr);
  if (chan == MANAGE_NO_CHANNELS_FREE) {
    /* No channels are free to accept our new satellite :( */
    /* TODO: Perhaps we can try to warm start this one
     * later using another fine acq.
     */
    log_info("No channels free :(\n");
    acq_prn_param[prn].state = ACQ_PRN_TRIED;
    return;
  }
  /* Transition to tracking. */
  u32 track_count = nap_timing_count() + 20000;
  cp = propagate_code_phase(cp, cf, track_count - timer_count);

  // Contrive for the timing strobe to occur at or close to a PRN edge (code phase = 0)
  track_count += 16*(1023.0-cp)*(1.0 + cf / GPS_L1_HZ);

  tracking_channel_init(chan, prn, cf, track_count, snr);
  acq_prn_param[prn].state = ACQ_PRN_TRACKING;
  nap_timing_strobe_wait(100);
}