void __ubmodem_substate_start_disconnect_network(struct ubmodem_s *modem)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  MODEM_DEBUGASSERT(modem, modem->level == UBMODEM_LEVEL_NETWORK ||
                           modem->level == UBMODEM_LEVEL_GPRS);

  /*
   * Disconnect network sequence is:
   *
   * 1. Send "AT+COPS=2".
   * 2. Send "AT+CFUN=0".
   *
   */

  __ubmodem_network_cleanup(modem);

  /* Reset sub-state data and initiate sub-state machine work. */

  memset(sub, 0, sizeof(*sub));
  sub->network_state = NETWORK_SETUP_DISCONNECTING;

  /* Disable network. */

  err = __ubmodem_send_cmd(modem, &cmd_ATpCOPS, set_ATpCOPS_off_handler, sub,
                           "%s", "=2");
  MODEM_DEBUGASSERT(modem, err == OK);
}
static int network_start_register_handler(struct ubmodem_s *modem,
                                          const int timer_id,
                                          void * const arg)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  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);
    }

  /* Keep retrying automatic network registration until timeout. */

  sub->network_state = NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION;
  sub->received_creg_while_retrying = -1;

  err = __ubmodem_send_cmd(modem, &cmd_ATpCOPS,
                           retry_ATpCOPS_handler, sub, "%s", "=0");
  MODEM_DEBUGASSERT(modem, err == OK);
  return OK;
}
static int voice_probe_fn(struct ubmodem_s *modem, const int timer_id,
                          void * const arg)
{
  int ret;

  modem->voice.probe_timerid = -1;

  if (!modem->voice.pm_activity_enabled)
    {
      return OK;
    }

  /* Start CMEE probe task. */

  if (!modem->voice.probe_task_queued)
    {
      ret = __ubmodem_add_task(modem, voice_probe_check_cmee, modem);
      MODEM_DEBUGASSERT(modem, ret != ERROR);
      modem->voice.probe_task_queued = true;
    }

  /* Reregister timer. */

  modem->voice.probe_timerid = __ubmodem_set_timer(modem,
                                 VOICE_MODEM_PROBE_SECS * 1000,
                                 voice_probe_fn, modem);
  MODEM_DEBUGASSERT(modem, modem->voice.probe_timerid >= 0);

  return OK;
}
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 urc_voice_cring_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)
{
  const char *type;
  uint16_t typelen;

  /*
   * URC handler for 'data available for sockets on modem'
   */

  MODEM_DEBUGASSERT(modem, cmd == &urc_ATpCRING);
  MODEM_DEBUGASSERT(modem, info->status == RESP_STATUS_URC);

  /* Get type. */

  if (!__ubmodem_stream_get_string(&resp_stream, &stream_len, &type, &typelen))
    {
      MODEM_DEBUGASSERT(modem, false); /* Should not get here. */
      return;
    }

  /* Just report for now. */

  dbg("+CRING: type='%s'\n", type);
}
void __ubmodem_substate_start_setup_network(struct ubmodem_s *modem)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  MODEM_DEBUGASSERT(modem, modem->level == UBMODEM_LEVEL_SIM_ENABLED);

  /*
   * Setup network sequence is:
   *
   * 1. Enable "+CREG" URC.
   * 2. Send "AT+CFUN=1".
   * 3. Send "AT+COPS=0".
   * 4. Wait until connected (Wait information from +CREG)
   *
   */

  MODEM_DEBUGASSERT(modem, modem->creg_urc_registered == false);
  MODEM_DEBUGASSERT(modem, modem->creg_timer_id == -1);

  /* Reset sub-state data and initiate sub-state machine work. */

  memset(sub, 0, sizeof(*sub));
  sub->network_state = NETWORK_SETUP_ENABLING_CREG;

  /* Setup sub-state clean-up function. */

  modem->substate_cleanup_fn = setup_network_cleanup;

  /* Enable +CREG. */

  err = __ubmodem_send_cmd(modem, &cmd_ATpCREG, ATpCREG_handler, sub,
                           "%s", "=1");
  MODEM_DEBUGASSERT(modem, err == OK);
}
void __ubmodem_recvfrom_socket(struct modem_socket_s *sock)
{
  struct ubmodem_s *modem = sock->modem;
  int err;
  size_t inlen;
  size_t max_stream_len;
  size_t recvlen;

  if (sock->is_closed)
    {
      /* Socket closed! */

      (void)__ubmodem_usrsock_send_response(modem, &sock->req, false, -EPIPE);
      __ubsocket_work_done(sock);
      return;
    }

  inlen = sock->recv.avail;

  if (inlen > sock->recv.max_buflen)
    inlen = sock->recv.max_buflen;

  if (sock->type == SOCK_DGRAM)
    {
      max_stream_len = __ubmodem_stream_max_readbuf_len(&cmd_ATpUSORF);
      max_stream_len -= INET_ADDRSTRLEN;
    }
  else
    {
      max_stream_len = __ubmodem_stream_max_readbuf_len(&cmd_ATpUSORD);
    }

  MODEM_DEBUGASSERT(modem, inlen > 0); /* sockets state machine should not allow
                                        * recv if input buffer has no space
                                        * left. */

  recvlen = max_stream_len;
  if (recvlen > MODEM_MAX_BINARY_SOCKET_READ_BYTES)
    recvlen = MODEM_MAX_BINARY_SOCKET_READ_BYTES;
  if (recvlen > inlen)
    recvlen = inlen;

  if (sock->type == SOCK_DGRAM)
    {
      /* Read data and peer address from modem. */

      err = __ubmodem_send_cmd(modem, &cmd_ATpUSORF, socket_recvfrom_handler,
                               sock, "=%d,%d", sock->modem_sd, recvlen);
      MODEM_DEBUGASSERT(modem, err == OK);
    }
  else
    {
      /* Read data from modem. */

      err = __ubmodem_send_cmd(modem, &cmd_ATpUSORD, socket_recvfrom_handler,
                               sock, "=%d,%d", sock->modem_sd, recvlen);
      MODEM_DEBUGASSERT(modem, err == 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 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);
}
Пример #11
0
static void ATA_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)
{
  uintptr_t mutepriv = (uintptr_t)priv;
  bool mute_mic = mutepriv >> 1;
  bool mute_speaker = mutepriv & 1;

  if (resp_status_is_error_or_timeout(info->status))
    {
      int err;

      /* In case of error, check CMEE setting to detect stuck hardware. */

      err =  __ubmodem_check_cmee_status(modem, modem_audio_check_cmee, modem);
      MODEM_DEBUGASSERT(modem, err == OK);
      return;
    }
  else if (info->status == RESP_STATUS_OK)
    {
      /* Configure audio. */

      ubmodem_audio_setup(modem, !mute_speaker, !mute_mic);
    }

  /* Reactions to call state changes are based on +UCALLSTAT. Just complete
   * task work. */

  /* Update main state machine. */

  __ubmodem_change_state(modem, MODEM_STATE_WAITING);
}
static int network_reregister_timer_handler(struct ubmodem_s *modem,
                                            const int timer_id,
                                            void * const arg)
{
  MODEM_DEBUGASSERT(modem, modem->creg_timer_id == timer_id);

  /* One-shot timer, not registered anymore. */

  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);
    }

  /* Issue new task. We cannot issue new state machine work from
   * URC 'context' as other work might be active in main state
   * machine. Task will be run with main state machine in proper
   * state. */

  __ubmodem_add_task(modem, reregister_network_failed, NULL);

  return OK;
}
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);
    }
}
Пример #14
0
static void config_audio_out_ctrl_gpio(struct ubmodem_s *modem, int pin,
                                       bool set)
{
  int err;

  err = __ubmodem_send_cmd(modem, &cmd_ATpUGPIOC,
                           __ubmodem_cmdprompt_generic_config_handler,
                           (void *)&cmd_ATpUGPIOC, "=%d,0,%d", pin, set);
  MODEM_DEBUGASSERT(modem, err == OK);
}
int __ubmodem_usrsock_handle_recvfrom_request(struct ubmodem_s *modem,
                                              void *reqbuf)
{
  struct usrsock_request_recvfrom_s *req = reqbuf;
  struct modem_socket_s *sock;
  int err;

  /* Get sockets for request. */

  sock = __ubmodem_socket_get_by_usockid(modem, req->usockid);
  if (!sock)
    {
      /* Give error result. */

      err = -EBADF;
      goto err_out;
    }

  MODEM_DEBUGASSERT(modem, sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM);

  /* Check if sockets is closed. */

  if (sock->is_closed || sock->modem_sd < 0)
    {
      err = -EPIPE;
      goto err_out;
    }

  if (sock->recv.avail == 0)
    {
      /* No data available at modem. */

      err = -EAGAIN;
      goto err_out;
    }

  /* TODO: Check for pending blocking operation (TCP connect) */

  /* Prepare to receive data from modem. */

  sock->req = req->head;
  sock->is_waiting_recv = true;
  sock->recv.max_addrlen = req->max_addrlen;
  sock->recv.max_buflen = req->max_buflen;

  __ubsocket_update_state(sock);
  __ubmodem_wake_waiting_state(modem, false);

  /* Report that request has been read and processing has started. */

  return __ubmodem_usrsock_send_response(modem, reqbuf, true, -EINPROGRESS);

err_out:
  return __ubmodem_usrsock_send_response(modem, reqbuf, false, err);
}
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;
    }
}
Пример #17
0
static void config_enable_urc_common(struct ubmodem_s *modem,
                                     const struct at_cmd_def_s *cmd)
{
  int err;

  __ubmodem_voice_control_setup(modem);

  err = __ubmodem_send_cmd(modem, cmd,
                           __ubmodem_cmdprompt_generic_config_handler,
                           (void *)cmd, "=1");
  MODEM_DEBUGASSERT(modem, err == OK);
}
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);
}
static int network_retry_registration_timer_handler(struct ubmodem_s *modem,
                                                    const int timer_id,
                                                    void * const arg)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  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);
    }

  DEBUGASSERT(
      sub->network_state == NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION);

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

      network_registration_successed(modem, sub);
    }
  else
    {
      err = __ubmodem_send_cmd(modem, &cmd_ATpCOPS,
                               retry_ATpCOPS_handler, sub, "%s", "=0");
      MODEM_DEBUGASSERT(modem, err == OK);
    }

  return OK;
}
static int network_unregister_timer_handler(struct ubmodem_s *modem,
                                            const int timer_id,
                                            void * const arg)
{
  struct modem_sub_setup_network_s *sub = arg;
  int err;

  /* Send +CFUN=0 */

  err = __ubmodem_send_cmd(modem, &cmd_ATpCFUN, set_ATpCFUN_off_handler, sub,
                           "%s", "=0");
  MODEM_DEBUGASSERT(modem, err == OK);

  return OK;
}
static int network_unregister_timer_handler(struct ubmodem_s *modem,
                                            const int timer_id,
                                            void * const arg)
{
  struct modem_sub_setup_network_s *sub = &modem->sub.setup_network;
  int err;

  /* Send +CFUN=0 */

  ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, false);
  err = __ubmodem_send_cmd(modem, &cmd_ATpCFUN, set_ATpCFUN_off_handler, sub,
                           "%s", "=0");
  MODEM_DEBUGASSERT(modem, err == OK);

  return OK;
}
Пример #24
0
static int start_task_voice_answer(struct ubmodem_s *modem, void *priv)
{
  int err;

  if (modem->level < UBMODEM_LEVEL_NETWORK)
    {
      return ERROR;
    }

  /* Send answer call command 'ATA' */

  err = __ubmodem_send_cmd(modem, &cmd_ATA, ATA_handler, priv, "");
  MODEM_DEBUGASSERT(modem, err == OK);

  return OK;
}
Пример #25
0
static int start_task_voice_hangup(struct ubmodem_s *modem, void *priv)
{
  int err;

  if (modem->level < UBMODEM_LEVEL_NETWORK)
    {
      return ERROR;
    }

  /* Send hangup call command 'AT+CHUP' */

  err = __ubmodem_send_cmd(modem, &cmd_ATpCHUP, ATpCHUP_handler, modem, "");
  MODEM_DEBUGASSERT(modem, err == OK);

  return OK;
}
Пример #26
0
static void voice_probe_check_cmee_result(struct ubmodem_s *modem,
                                          bool cmee_ok, int cmee_setting,
                                          void *priv)
{
  int err;

  /* Release main state machine for next task. */

  __ubmodem_change_state(modem, MODEM_STATE_WAITING);

  if (!cmee_ok && modem->voice.probe_fails++ >= VOICE_MODEM_PROBE_FAILS)
    {
      /* Modem HW is in unknown state, attempt to recover. */

      err = __ubmodem_recover_stuck_hardware(modem);
      MODEM_DEBUGASSERT(modem, err != ERROR);
    }
}
Пример #27
0
static void modem_voice_pm_activity(struct ubmodem_s *modem,
                                    bool ringing_or_active)
{
  if (ringing_or_active == modem->voice.pm_activity_enabled)
    {
      /* Already in this state. */

      return;
    }

  modem->voice.pm_activity_enabled = ringing_or_active;

  modem->voice.probe_fails = 0;
  if (modem->voice.probe_timerid >= 0)
    {
      __ubmodem_remove_timer(modem, modem->voice.probe_timerid);
      modem->voice.probe_timerid = -1;
    }

  if (ringing_or_active)
    {
      /* Voice call incoming, ringing. After ringing call is eventually
       * disconnected. Report low activity so that we get disconnect URC from
       * modem after hangup (no ring-indication anymore to wake-up MCU). */

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_LOW, true);

      /* Start probing to detect modem hang-ups (low voltage situation etc). */

      modem->voice.probe_timerid = __ubmodem_set_timer(modem,
                                     VOICE_MODEM_PROBE_SECS * 1000,
                                     voice_probe_fn, modem);
      MODEM_DEBUGASSERT(modem, modem->voice.probe_timerid >= 0);
    }
  else
    {
      /* Voice call disconnected, report change of activity to
       * power-management. */

      ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_LOW, false);
    }
}
Пример #28
0
static void modem_audio_check_cmee(struct ubmodem_s *modem, bool cmee_ok,
                                    int cmee_setting, void *priv)
{
  if (!cmee_ok)
    {
      int err;

      /* Modem hardware stuck or reseted, launch task to restore function. */

      err = __ubmodem_recover_stuck_hardware(modem);
      MODEM_DEBUGASSERT(modem, err != ERROR);
    }

  /* Reactions to call state changes are based on +UCALLSTAT. Just complete
   * task work. */

  /* Update main state machine. */

  __ubmodem_change_state(modem, MODEM_STATE_WAITING);
}
Пример #29
0
static int voice_probe_check_cmee(struct ubmodem_s *modem, void *priv)
{
  int err;

  modem->voice.probe_task_queued = false;

  if (!modem->voice.pm_activity_enabled)
    {
      return ERROR;
    }

  if (modem->level < UBMODEM_LEVEL_CMD_PROMPT)
    {
      return ERROR;
    }

  /* Check CMEE setting to see if modem has reseted or not. */

  err = __ubmodem_check_cmee_status(modem, voice_probe_check_cmee_result, modem);
  MODEM_DEBUGASSERT(modem, err == OK);

  return OK;
}
Пример #30
0
static void ATpCHUP_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)
{
  if (resp_status_is_error_or_timeout(info->status))
    {
      int err;

      /* In case of error, check CMEE setting to detect stuck hardware. */

      err =  __ubmodem_check_cmee_status(modem, modem_audio_check_cmee, modem);
      MODEM_DEBUGASSERT(modem, err == OK);
      return;
    }

  /* Reactions to call state changes are based on +UCALLSTAT. Just complete
   * task work. */

  /* Update main state machine. */

  __ubmodem_change_state(modem, MODEM_STATE_WAITING);
}