Example #1
0
/****************************************************************************
 * Name: ubgps_setup_timeout
 *
 * Description:
 *   Setup target state transition timeout
 *
 * Input Parameters:
 *   gps         - GPS object
 *   timeout     - Timeout in seconds
 *
 * Returned Values:
 *   Status
 *
 ****************************************************************************/
int ubgps_setup_timeout(struct ubgps_s * const gps, uint32_t const timeout)
{
  DEBUGASSERT(gps);

  /* Check for running timeout timer */

  if (gps->state.target_timer_id >= 0)
    {
      __ubgps_remove_timer(gps, gps->state.target_timer_id);

      gps->state.target_timer_id = -1;
    }

  /* Check for timeout */

  if (timeout > 0)
    {
      gps->state.target_timer_id = __ubgps_set_timer(gps,
                                                     timeout * 1000,
                                                     ubgps_timeout,
                                                     gps);

      if (gps->state.target_timer_id < 0)
        return ERROR;
    }

  return OK;
}
Example #2
0
/****************************************************************************
 * Name: ubgps_filter_location
 *
 * Description:
 *   Filter location events in power save mode. Location events are published
 *   until horizontal accuracy is below defined threshold or location filter
 *   timeout occurs.
 *
 * Input Parameters:
 *   gps         - GPS object
 *   levent      - Location event
 *
 * Returned Values:
 *
 ****************************************************************************/
static void ubgps_filter_location(struct ubgps_s * const gps,
  struct gps_event_location_s const * const levent)
{
  DEBUGASSERT(gps && levent);

  if (gps->state.navigation_rate < CONFIG_UBGPS_PSM_MODE_THRESHOLD*1000)
    {
      /* Navigation rate less than PSM threshold. */

      ubgps_publish_event(gps, (struct gps_event_s *)levent);
      return;
    }

  if (CONFIG_UBGPS_PSM_ACCURACY_FILTER_DURATION == 0 ||
      (levent->location->horizontal_accuracy / 1000 <
      CONFIG_UBGPS_PSM_ACCURACY_FILTER_THRESHOLD))
    {
      struct sm_event_psm_event_s psm;

      /* Filter disabled or accuracy below threshold */

      ubgps_publish_event(gps, (struct gps_event_s *)levent);

      if (gps->state.location_timer_id >= 0)
        {
          __ubgps_remove_timer(gps, gps->state.location_timer_id);

          gps->state.location_timer_id = -1;
        }

      gps->filt_location.horizontal_accuracy = 0;

      /* Construct power save mode event */

      psm.super.id = SM_EVENT_PSM_STATE;
      psm.enable = true;
      ubgps_sm_process(gps, (struct sm_event_s *)&psm);

      return;
    }

  if (gps->filt_location.horizontal_accuracy == 0)
    {
      /* The first location event that is not below threshold,
         start timeout timer to collect location events. */

      gps->state.location_timer_id = __ubgps_set_timer(gps,
        CONFIG_UBGPS_PSM_ACCURACY_FILTER_DURATION*1000, ubgps_timeout, gps);
    }

  if (gps->filt_location.horizontal_accuracy == 0 ||
      (levent->location->horizontal_accuracy <
      gps->filt_location.horizontal_accuracy))
    {
      /* More accurate location than previous one, update location data. */

      memcpy(&gps->filt_location, levent->location, sizeof(*levent->location));
      return;
    }
}
Example #3
0
/****************************************************************************
 * Name: ubgps_report_target_state
 *
 * Description:
 *   Report target state reached status
 *
 * Input Parameters:
 *   gps         - GPS object
 *   timeout     - Timeout status
 *
 * Returned Values:
 *   Status
 *
 ****************************************************************************/
void ubgps_report_target_state(struct ubgps_s * const gps, bool const timeout)
{
  struct gps_event_target_state_s event;

  DEBUGASSERT(gps);

  /* Check if target state transition is in progress */

  if (!gps->state.target_state_pending)
    return;

  /* Setup event fields */

  event.current_state = gps->state.current_state;
  event.target_state = gps->state.target_state;

  if (timeout)
    {
      event.super.id = GPS_EVENT_TARGET_STATE_TIMEOUT;
    }
  else if (gps->state.current_state == gps->state.target_state)
    {
      event.super.id = GPS_EVENT_TARGET_STATE_REACHED;
    }
  else
    {
      event.super.id = GPS_EVENT_TARGET_STATE_NOT_REACHED;
    }

  if (gps->state.target_timer_id >= 0)
    {
      if (!timeout)
        {
          /* Stop target state timeout */
          __ubgps_remove_timer(gps, gps->state.target_timer_id);
        }

      /* Clear timeout timer ID */

      gps->state.target_timer_id = -1;
    }

  /* Clear target state transition pending flag */

  gps->state.target_state_pending = false;

  /* Publish event to listeners */

  ubgps_publish_event(gps, (struct gps_event_s *)&event);
}
Example #4
0
/****************************************************************************
 * Name: ubgps_sm_global
 *
 * Description:
 *   Global handler for gps_sm_searching_fix and gps_sm_fix_acquired states
 *
 ****************************************************************************/
static int ubgps_sm_global(struct ubgps_s * const gps, struct sm_event_s const * const event)
{
  DEBUGASSERT(gps && event);

  /* Check event */

  switch (event->id)
    {
      case SM_EVENT_ENTRY:
        {
          dbg_sm("SM_EVENT_ENTRY\n");
          if (gps->state.current_state == gps->state.target_state)
            {
              /* Report target reached */

              ubgps_report_target_state(gps, false);
            }

          if (gps->assist)
            {
              dbg_sm("start polling aiding status\n");

              (void)ubgps_send_aid_alp_poll(gps);
            }

          return OK;
        }

      case SM_EVENT_TARGET_STATE:
        {
          struct sm_event_target_state_s const * const target =
              (struct sm_event_target_state_s *)event;

          dbg_sm("SM_EVENT_TARGET_STATE\n");

          if (target->target_state != gps->state.current_state)
            {
              /* Setup target state transition timeout */

              ubgps_setup_timeout(gps, target->timeout);

              /* Set GPS target state */

              gps->state.target_state = target->target_state;

              /* Check current and target state */

              if (gps->state.target_state == GPS_STATE_FIX_ACQUIRED &&
                  gps->state.current_state == GPS_STATE_COLD_START)
                {
                  /* Move to GPS initialization for GPS aiding parameters */

                  ubgps_set_new_state(gps, GPS_STATE_INITIALIZATION);
                }
              else if (gps->state.target_state == GPS_STATE_FIX_ACQUIRED &&
                  gps->state.current_state < GPS_STATE_FIX_ACQUIRED)
                {
                  /* Move to search for GPS fix */

                  ubgps_set_new_state(gps, GPS_STATE_SEARCHING_FIX);
                }
              else
                {
                  /* Move to requested target state */

                  ubgps_set_new_state(gps, gps->state.target_state);
                }
            }
          else
            {
              /* Make current state the target state */

              gps->state.target_state = gps->state.current_state;

              /* Report target reached */

              ubgps_report_target_state(gps, false);
            }

          return OK;
        }

      case SM_EVENT_TIMEOUT:
        {
          struct sm_event_timeout_s const * const timeout =
              (struct sm_event_timeout_s *)event;
          dbg_sm("SM_EVENT_TIMEOUT\n");

          if (timeout->timer_id == gps->state.target_timer_id)
            {
              /* Report target state timeout */

              ubgps_report_target_state(gps, true);
            }
          else if (timeout->timer_id == gps->state.aid_timer_id)
            {
              /* poll whether ALP data has been expired */

              return ubgps_send_aid_alp_poll(gps);
            }
#ifdef CONFIG_UBGPS_PSM_MODE
          else if (timeout->timer_id == gps->state.location_timer_id)
            {
              struct gps_event_location_s levent;

              /* Publish the most accurate location event received so far. */

              dbg_sm("location filter timeout, accuracy: %um\n",
                  gps->filt_location.horizontal_accuracy / 1000);

              levent.super.id = GPS_EVENT_LOCATION;
              levent.time = &gps->time;
              levent.location = &gps->filt_location;
              ubgps_publish_event(gps, (struct gps_event_s *)&levent);

              /* Reset filtered location event. */

              gps->filt_location.horizontal_accuracy = 0;

              /* Construct power save mode event */

              if (gps->state.navigation_rate >= CONFIG_UBGPS_PSM_MODE_THRESHOLD)
                {
                  struct sm_event_psm_event_s psm;

                  psm.super.id = SM_EVENT_PSM_STATE;
                  psm.enable = true;
                  ubgps_sm_process(gps, (struct sm_event_s *)&psm);
                }
            }
#endif /* CONFIG_UBGPS_PSM_MODE */

          return OK;
        }

      case SM_EVENT_UBX_MESSAGE:
        {
          struct sm_event_ubx_msg_s const * const ubx_msg =
              (struct sm_event_ubx_msg_s *)event;
          struct ubx_msg_s const * const msg = ubx_msg->msg;

          if (msg->class_id == UBX_CLASS_NAV && msg->msg_id == UBX_NAV_PVT)
            {
              return ubgps_handle_nav_pvt(gps, msg);
            }
          else if (msg->class_id == UBX_CLASS_AID && msg->msg_id == UBX_AID_ALPSRV)
            {
              return ubgps_handle_aid_alpsrv(gps, msg);
            }
          else if (msg->class_id == UBX_CLASS_AID && msg->msg_id == UBX_AID_ALP)
            {
              return ubgps_handle_aid_alp(gps, msg);
            }

          dbg_sm("Unhandled UBX message, class:0x%02x, msg:0x%02x, len:%d.\n",
              ubx_msg->msg->class_id, ubx_msg->msg->msg_id, ubx_msg->msg->length);

          return OK;
        }

      case SM_EVENT_AID_STATUS:
        {
#ifdef CONFIG_UBGPS_ASSIST_UPDATER
          struct sm_event_aid_s const * const aid = (struct sm_event_aid_s *)event;
          struct timespec ts = {};
          uint32_t timeout = 0;
          dbg_sm("SM_EVENT_AID_STATUS\n");

          /* Check whether aiding has been enabled */

          if (!gps->assist)
            {
              return OK;
            }

          if (!gps->assist->alp_file)
            {
              /* Aiding file does not exist, start updater */

              ubgps_aid_updater_start(gps->assist);
              timeout = AID_STATUS_POLL_DELAY;
            }
          else if (aid->age < 0)
            {
              /* Status of aiding data not yet resolved */

              timeout = AID_STATUS_POLL_DELAY;
            }
          else if (aid->age < AID_VALIDITY_TIME_1D )
            {
              /* Aiding still valid, setup recheck timeout */

              timeout = AID_RECHECK_DELAY*1000;
            }
          else
            {
              /* Aiding data needs to be updated */

              clock_gettime(CLOCK_MONOTONIC, &ts);

              /* But first add nanoseconds to entropy pool. */

              add_time_randomness(ts.tv_nsec);

              if (gps->assist->update_time == 0 ||
                 (ts.tv_sec - gps->assist->update_time) > AID_RECHECK_DELAY)
                {
                  /* The first update attempt or retry after timeout */

                  dbg_sm("start aiding update, previous update: %ds\n",
                    ts.tv_sec - gps->assist->update_time);

                  gps->assist->update_time = ts.tv_sec;
                  ubgps_aid_updater_start(gps->assist);
                  timeout = AID_STATUS_POLL_DELAY;
                }
              else
                {
                  /* Set timeout for the next update attempt */

                  timeout = AID_RECHECK_DELAY*1000;
                }
            }

            if (gps->state.aid_timer_id >= 0)
              {
                __ubgps_remove_timer(gps, gps->state.aid_timer_id);
              }

            gps->state.aid_timer_id = __ubgps_set_timer(gps,
                                                       timeout,
                                                       ubgps_timeout,
                                                       gps);
#endif /* CONFIG_UBGPS_ASSIST_UPDATER */
          return OK;
        }

#ifdef CONFIG_UBGPS_PSM_MODE
      case SM_EVENT_PSM_STATE:
        {
          struct sm_event_psm_event_s const * const psm_event =
              (struct sm_event_psm_event_s *)event;
          dbg_sm("SM_EVENT_PSM_STATE -> %u\n", psm_event->enable);

          if (psm_event->enable)
            {
              /* Start SW controlled power save mode (PSM). */

              if (gps->state.navigation_rate >= CONFIG_UBGPS_PSM_MODE_THRESHOLD)
                {
                  struct timespec ts = {};

                  clock_gettime(CLOCK_MONOTONIC, &ts);
                  ts.tv_sec += gps->state.navigation_rate/1000;
                  gps->state.psm_timer_id = ts_core_timer_setup_date(&ts,
                      ubgps_psm_timer_cb, gps);

                  /* Update assist params */

                  gps->assist->use_time = true;
                  gps->assist->use_loc = true;
                  gps->assist->latitude = gps->location.latitude;
                  gps->assist->longitude = gps->location.longitude;
                  gps->assist->altitude = gps->location.height;
                  gps->assist->accuracy = gps->location.horizontal_accuracy;

                  dbg_sm("gps->state.psm_timer_id:%d, set POWER_OFF\n",
                      gps->state.psm_timer_id);
                  ubgps_set_new_state(gps, GPS_STATE_POWER_OFF);
                }
            }

          return OK;
        }
#endif /* CONFIG_UBGPS_PSM_MODE */

      default:
        return OK;
    }
}
Example #5
0
/****************************************************************************
 * Name: ubgps_sm_poweroff
 *
 * Description:
 *   State machine for GPS power off
 *
 ****************************************************************************/
static int ubgps_sm_poweroff(struct ubgps_s * const gps, struct sm_event_s const * const event)
{
  DEBUGASSERT(gps && event);

  /* Check event */

  switch (event->id)
    {
      case SM_EVENT_ENTRY:
        {
          dbg_sm("SM_EVENT_ENTRY\n");
          if (gps->state.powered)
            {
              /* Power down GPS chip */

              board_gps_power(false);

              /* Mark GPS power down */

              gps->state.powered = false;

              /* Reset UBX receiver */

              ubx_reset(gps);
            }

          /* Report target reached status */

          ubgps_report_target_state(gps, false);

          /* Reset PSM accuracy filter */

          gps->filt_location.horizontal_accuracy = 0;

          /* Make sure that timers are not running */

          if (gps->state.location_timer_id >= 0)
            {
              __ubgps_remove_timer(gps, gps->state.location_timer_id);
              gps->state.location_timer_id = -1;
            }

#ifdef CONFIG_UBGPS_ASSIST_UPDATER
          /* Stop aiding updater and timers */

          if (gps->state.aid_timer_id >= 0)
            {
              __ubgps_remove_timer(gps, gps->state.aid_timer_id);
              gps->state.aid_timer_id = -1;
            }

          if (gps->assist)
            {
              if (ubgps_aid_updater_stop(gps->assist))
                {
                  dbg("Aiding updater stop failed\n");
                }
            }
#endif
          /* Free GPS assistance data if PSM is not active */

          if (gps->assist && gps->state.psm_timer_id < 0)
            {
              if (gps->assist->alp_file)
                free(gps->assist->alp_file);

              free(gps->assist);
              gps->assist = NULL;
            }

          return OK;
        }

      case SM_EVENT_TARGET_STATE:
        {
          struct sm_event_target_state_s * const target =
              (struct sm_event_target_state_s *)event;

          dbg_sm("SM_EVENT_TARGET_STATE -> %u\n", target->target_state);

          /* Stop PSM timer */

          if (gps->state.psm_timer_id > 0)
            {
              ts_core_timer_stop(gps->state.psm_timer_id);
              gps->state.psm_timer_id = -1;
            }

          if (target->target_state != GPS_STATE_POWER_OFF)
            {
              /* Setup target state transition timeout */

              ubgps_setup_timeout(gps, target->timeout);

              /* Set GPS target state */

              gps->state.target_state = target->target_state;

              /* Set next GPS state */

              ubgps_set_new_state(gps, GPS_STATE_INITIALIZATION);
            }
          else
            {
              /* Make current state the target state */

              /* Free GPS assistance data */

              if (gps->assist)
                {
                  if (gps->assist->alp_file)
                    free(gps->assist->alp_file);

                  free(gps->assist);
                  gps->assist = NULL;
                }

              gps->state.target_state = gps->state.current_state;

              /* Report target reached */

              ubgps_report_target_state(gps, false);
            }

          return OK;
        }

      case SM_EVENT_PSM_STATE:
        {
          struct sm_event_psm_event_s const * const psm_event =
              (struct sm_event_psm_event_s *)event;
          dbg_sm("SM_EVENT_PSM_STATE -> %u\n", psm_event->enable);

          if (!psm_event->enable)
            {
              gps->state.target_state = GPS_STATE_FIX_ACQUIRED;
              ubgps_set_new_state(gps, GPS_STATE_INITIALIZATION);
            }

          return OK;
        }

      case SM_EVENT_EXIT:
        {
          dbg_sm("SM_EVENT_EXIT\n");

          if (!gps->state.powered)
            {
              struct termios uart;
              int ret;

              /* Configure initial baud rate to GPS UART */

              ret = ioctl(gps->fd, TCGETS, (unsigned long)&uart);
              DEBUGASSERT(ret == OK);

              uart.c_cflag = CS8;
              uart.c_speed = GPS_INITIAL_BAUD_RATE;

              ret = ioctl(gps->fd, TCSETS, (unsigned long)&uart);
              DEBUGASSERT(ret == OK);

              /* Power up GPS chip */

              board_gps_power(true);

              /* Mark GPS power up */

              gps->state.powered = true;
            }

          return OK;
        }

      default:
        break;
    }

  return OK;
}
Example #6
0
/****************************************************************************
 * Name: ubgps_sm_initialization
 *
 * Description:
 *   State machine for GPS initialization
 *
 ****************************************************************************/
static int ubgps_sm_initialization(struct ubgps_s * const gps,
                                   struct sm_event_s const * const event)
{
  DEBUGASSERT(gps && event);

  /* Check event */

  switch (event->id)
    {
      case SM_EVENT_ENTRY:
        {
          dbg_sm("SM_EVENT_ENTRY\n");

          /* Start initialization timer */

          gps->state.init_timer_id = __ubgps_set_timer(gps,
                                                       GPS_POWERUP_DELAY,
                                                       ubgps_timeout,
                                                       gps);

          if (gps->state.init_timer_id < 0)
            {
              dbg("Error while setting up initialization timer.\n");

              /* Fail back to power down state */

              ubgps_set_new_state(gps, GPS_STATE_POWER_OFF);

              return ERROR;
            }

          /* Initialize GPS location data */

          memset(&gps->location, 0, sizeof(gps->location));

          /* Reset initialization phase & retry counter */

          gps->state.init_phase = 0;
          gps->state.init_count = 0;

          return OK;
        }

      case SM_EVENT_TIMEOUT:
        {
          struct sm_event_timeout_s const * const timeout =
              (struct sm_event_timeout_s *)event;

          dbg_sm("SM_EVENT_TIMEOUT\n");

          if (timeout->timer_id == gps->state.target_timer_id)
            {
              /* Report target state timeout */

              ubgps_report_target_state(gps, true);
            }
          else if (timeout->timer_id == gps->state.init_timer_id)
            {
              /* Clear initialization timer ID */

              gps->state.init_timer_id = -1;

              /* Continue initialization process */

              return ubgps_init_process_phase(gps, false);
            }

          return OK;
        }

      case SM_EVENT_UBX_STATUS:
        {
          struct sm_event_ubx_status_s const * const ubx =
              (struct sm_event_ubx_status_s *)event;

          dbg_sm("SM_EVENT_UBX_STATUS - class:%02X, msg:%02X\n",
              ubx->class_id, ubx->msg_id);

          if (ubx->class_id == UBX_CLASS_CFG &&
             (ubx->msg_id == UBX_CFG_PRT || ubx->msg_id == UBX_CFG_MSG ||
              ubx->msg_id == UBX_CFG_RATE || ubx->msg_id == UBX_CFG_SBAS ||
              ubx->msg_id == UBX_CFG_PM2 || ubx->msg_id == UBX_CFG_RXM ||
              ubx->msg_id == UBX_CFG_ANT))
            {
              if (ubx->status != UBX_STATUS_ACK)
                {
                  /* Retry initialization phase */

                  dbg_sm("SM_EVENT_UBX_STATUS - NACK\n");

                  return ubgps_init_process_phase(gps, false);
                }

              /* Move to next phase */

              return ubgps_init_process_phase(gps, true);
            }

          dbg_sm("Unhandled SM_EVENT_UBX_STATUS. Class 0x%02x, message 0x%02x\n",
              ubx->class_id, ubx->msg_id);

          return OK;
        }

      case SM_EVENT_UBX_MESSAGE:
        {
          struct sm_event_ubx_msg_s const * const ubx_msg =
              (struct sm_event_ubx_msg_s *)event;
          struct ubx_msg_s const * const msg = ubx_msg->msg;
          dbg_sm("SM_EVENT_UBX_MESSAGE\n");

          if (msg->class_id == UBX_CLASS_NAV && msg->msg_id == UBX_NAV_PVT)
            {
              dbg_sm("Unexpected NAV message in initialization phase???\n");

              return ubgps_handle_nav_pvt(gps, msg);
            }
          else if (msg->class_id == UBX_CLASS_AID && msg->msg_id == UBX_AID_ALPSRV)
            {
              return ubgps_handle_aid_alpsrv(gps, msg);
            }

          return OK;
        }

      case SM_EVENT_TARGET_STATE:
        {
          struct sm_event_target_state_s const * const target =
              (struct sm_event_target_state_s *)event;

          dbg_sm("SM_EVENT_TARGET_STATE\n");

          if (target->target_state != GPS_STATE_INITIALIZATION)
            {
              /* Setup target state transition timeout */

              ubgps_setup_timeout(gps, target->timeout);

              /* Set GPS target state */

              gps->state.target_state = target->target_state;

              if (target->target_state == GPS_STATE_POWER_OFF)
                {
                  /* Set next GPS state */

                  ubgps_set_new_state(gps, GPS_STATE_POWER_OFF);
                }
            }
          else if (gps->state.init_phase == INIT_PHASE_DONE)
            {
              /* Make current state the target state */

              gps->state.target_state = gps->state.current_state;

              /* Report target reached */

              ubgps_report_target_state(gps, false);
            }

          return OK;
        }

      case SM_EVENT_EXIT:
        {
          dbg_sm("SM_EVENT_EXIT\n");

          /* Stop pending initialization timer */

          if (gps->state.init_timer_id >= 0)
            {
              __ubgps_remove_timer(gps, gps->state.init_timer_id);

              gps->state.init_timer_id = -1;
            }

          return OK;
        }

      default:
        return OK;
    }
}