static int network_register_timer_handler(struct ubmodem_s *modem,
                                          const int timer_id, void * const arg)
{
  const char *reason;

  if (timer_id != -1)
    {
      /* One-shot timer, not registered anymore. */

      modem->creg_timer_id = -1;
    }

  /* Could not register in time. Disable RF. */

  if (timer_id == -1)
    reason = "NETWORK: Denied.";
  else
    reason = "NETWORK: Timeout.";

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Failed to connect network. */

  __ubmodem_level_transition_failed(modem, "%s", reason);

  return OK;
}
static int network_register_timeout_handler(struct ubmodem_s *modem,
                                            const int timer_id,
                                            void * const arg)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  struct timespec curr_ts;
  const char *reason;
  int ret;

  MODEM_DEBUGASSERT(modem, modem->creg_timer_id == timer_id);

  if (timer_id != -1)
    {
      /* One-shot timer, not registered anymore. */

      modem->creg_timer_id = -1;

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, false);
    }

  (void)clock_gettime(CLOCK_MONOTONIC, &curr_ts);

  if (curr_ts.tv_sec - sub->net_reg_start_ts.tv_sec <=
      MODEM_CMD_NETWORK_REGISTRATION_TIMEOUT / 10)
    {
      /* Too soon, reregister timer. */

      ret = __ubmodem_set_timer(modem, NETWORK_REGISTRATION_CHECK_SECS * 1000,
                                &network_register_timeout_handler, sub);
      MODEM_DEBUGASSERT(modem, ret != ERROR);

      modem->creg_timer_id = ret;

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, true);

      return OK;
    }

  /* Could not register in time. Disable RF. */

  if (timer_id == -1)
    reason = "NETWORK: Denied.";
  else
    reason = "NETWORK: Timeout.";

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Failed to connect network. */

  __ubmodem_level_transition_failed(modem, "%s", reason);

  return OK;
}
static int retry_network_through_sim(struct ubmodem_s *modem, void *priv)
{
  ubdbg("\n");

  /* Go to SIM enabled level from current and then retry current. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Return error to tell task starter that task did not start new work on
   * state machine. */

  return ERROR;
}
static int reregister_network_failed(struct ubmodem_s *modem, void *priv)
{
  ubdbg("\n");

  /* Mark for retry, 'level transition failed' can modify the actual target
   * level. */

  __ubmodem_network_cleanup(modem);
  __ubmodem_retry_current_level(modem, UBMODEM_LEVEL_SIM_ENABLED);

  /* Could not reregister, shutdown modem. */

  __ubmodem_level_transition_failed(modem, "%s", "NETWORK: Lost connection.");

  /* Return error to tell task starter that task did not start new work on
   * state machine. */

  return ERROR;
}