static void set_ATpCFUN_off_handler(struct ubmodem_s *modem,
                                    const struct at_cmd_def_s *cmd,
                                    const struct at_resp_info_s *info,
                                    const uint8_t *resp_stream,
                                    size_t stream_len, void *priv)
{
  /*
   * Response handler for AT+CFUN=0
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCFUN);

  if (resp_status_is_error_or_timeout(info->status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=0");
      return;
    }
  else if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /* Done unregistering from network. */

  __ubmodem_reached_level(modem, UBMODEM_LEVEL_SIM_ENABLED);
}
static void set_ATpCOPS_handler(struct ubmodem_s *modem,
                                const struct at_cmd_def_s *cmd,
                                const struct at_resp_info_s *info,
                                const uint8_t *resp_stream,
                                size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = priv;
  int ret;
  int status = info->status;

  /*
   * Response handler for AT+COPS=0
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCOPS);

  if (status == RESP_STATUS_CME_ERROR)
    {
      if (handle_cops_cme_error(modem, info))
        return;
    }
  else if (resp_status_is_error_or_timeout(status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=0");
      return;
    }
  else if (status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /*
   * Now waiting for +CREG URC.
   *
   * Register timer for timeout.
   */

  sub->network_state = NETWORK_SETUP_WAITING_NETWORK_REGISTRATION;

  ret = __ubmodem_set_timer(modem, MODEM_CMD_NETWORK_TIMEOUT * 100,
                            &network_register_timer_handler, sub);
  if (ret == ERROR)
    {
      /* Error here? Add assert? Or just try bailout? */

      MODEM_DEBUGASSERT(modem, false);

      (void)network_register_timer_handler(modem, -1, sub);
      return;
    }

  modem->creg_timer_id = ret;
}
static void retry_ATpCOPS_handler(struct ubmodem_s *modem,
                                  const struct at_cmd_def_s *cmd,
                                  const struct at_resp_info_s *info,
                                  const uint8_t *resp_stream,
                                  size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int status = info->status;
  int ret;

  /*
   * Response handler for retried AT+COPS=0
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCOPS);

  if (status == RESP_STATUS_CME_ERROR)
    {
      if (handle_cops_cme_error(modem, info))
        return;
    }
  else if (resp_status_is_error_or_timeout(status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=0");
      return;
    }
  else if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  DEBUGASSERT(
      sub->network_state == NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION);
  sub->network_state = NETWORK_SETUP_WAITING_NETWORK_REGISTRATION;

  /*
   * Now waiting for +CREG URC.
   *
   * Register timer for timeout.
   */

  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);
}
static void retry_ATpCOPS_handler(struct ubmodem_s *modem,
                                  const struct at_cmd_def_s *cmd,
                                  const struct at_resp_info_s *info,
                                  const uint8_t *resp_stream,
                                  size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = priv;
  int status = info->status;

  /*
   * Response handler for retried AT+COPS=0
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCOPS);

  if (status == RESP_STATUS_CME_ERROR)
    {
      if (handle_cops_cme_error(modem, info))
        return;
    }
  else if (resp_status_is_error_or_timeout(status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=0");
      return;
    }
  else if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  DEBUGASSERT(
      sub->network_state == NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION);
  sub->network_state = NETWORK_SETUP_WAITING_NETWORK_REGISTRATION;

  if (sub->received_creg_while_retrying > 0)
    {
      ubdbg("Handling deferred +CREG: %d\n", sub->received_creg_while_retrying);

      /* Report successful cellular network connection. */

      sub->keep_creg_urc = true;
      __ubmodem_reached_level(modem, UBMODEM_LEVEL_NETWORK);
    }
}
static void set_ATpCOPS_off_handler(struct ubmodem_s *modem,
                                    const struct at_cmd_def_s *cmd,
                                    const struct at_resp_info_s *info,
                                    const uint8_t *resp_stream,
                                    size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int ret;

  /*
   * Response handler for AT+COPS=2
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCOPS);

  if (resp_status_is_error_or_timeout(info->status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=2");
      return;
    }
  else if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /* Wait for sometime so modem can complete unregistering from network. */

  ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, true);
  ret = __ubmodem_set_timer(modem, 1500, &network_unregister_timer_handler,
                            sub);
  if (ret == ERROR)
    {
      /* Error here? Add assert? Or just try bailout? */

      MODEM_DEBUGASSERT(modem, false);

      (void)network_unregister_timer_handler(modem, -1, sub);
      return;
    }
}
static void ATpCREG_handler(struct ubmodem_s *modem,
                            const struct at_cmd_def_s *cmd,
                            const struct at_resp_info_s *info,
                            const uint8_t *resp_stream,
                            size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  /*
   * Response handler for AT+CREG=1
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCREG);

  if (resp_status_is_error_or_timeout(info->status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=1");
      return;
    }

  if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /* Register "+CREG" URC handler. */

  __ubparser_register_response_handler(&modem->parser, &urc_ATpCREG,
                                       registration_urc_pCREG_handler,
                                       sub, true);
  modem->creg_urc_registered = true;
  sub->network_state = NETWORK_SETUP_ENABLING_RF;

  /* Enable modem RF. */

  err = __ubmodem_send_cmd(modem, &cmd_ATpCFUN, ATpCFUN_handler, sub, "%s", "=1");
  MODEM_DEBUGASSERT(modem, err == OK);
}
static void ATpCFUN_handler(struct ubmodem_s *modem,
                            const struct at_cmd_def_s *cmd,
                            const struct at_resp_info_s *info,
                            const uint8_t *resp_stream,
                            size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  /*
   * Response handler for AT+CFUN=1
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCFUN);

  if (resp_status_is_error_or_timeout(info->status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=1");
      return;
    }

  if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /*
   * Modem RF enabled, now disable previous automatic network registration.
   * +CREG:0 will be received and +COPS=0 will be issued to start new automatic
   * network registration.
   */

  sub->network_state = NETWORK_SETUP_STARTING_NETWORK_REGISTRATION;
  (void)clock_gettime(CLOCK_MONOTONIC, &sub->net_reg_start_ts);

  err = __ubmodem_send_cmd(modem, &cmd_ATpCOPS, disable_ATpCOPS_handler, sub,
                           "%s", "=2");
  MODEM_DEBUGASSERT(modem, err == OK);
}
static void ATpCFUN_handler(struct ubmodem_s *modem,
                            const struct at_cmd_def_s *cmd,
                            const struct at_resp_info_s *info,
                            const uint8_t *resp_stream,
                            size_t stream_len, void *priv)
{
  struct modem_sub_setup_network_s *sub = priv;
  int err;

  /*
   * Response handler for AT+CFUN=1
   */

  MODEM_DEBUGASSERT(modem, cmd == &cmd_ATpCFUN);

  if (resp_status_is_error_or_timeout(info->status))
    {
      __ubmodem_common_failed_command(modem, cmd, info, "=1");
      return;
    }

  if (info->status != RESP_STATUS_OK)
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /*
   *  Modem RF enabled, now start automatic network registration.
   */

  sub->network_state = NETWORK_SETUP_STARTING_NETWORK_REGISTRATION;

  err = __ubmodem_send_cmd(modem, &cmd_ATpCOPS, set_ATpCOPS_handler, sub,
                       "%s", "=0");
  MODEM_DEBUGASSERT(modem, err == OK);
}