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 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 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; }
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 void registration_urc_pCREG_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; int8_t val; int ret; DEBUGASSERT(modem->state == MODEM_STATE_IN_SUBSTATE); /* * Response handler for +CREG URC. */ MODEM_DEBUGASSERT(modem, cmd == &urc_ATpCREG); if (info->status != RESP_STATUS_URC) { /* Should not happen. */ MODEM_DEBUGASSERT(modem, false); return; } if (!__ubmodem_stream_get_int8(&resp_stream, &stream_len, &val)) { /* Should not happen. */ MODEM_DEBUGASSERT(modem, false); return; } dbg("Network registration URC, +CREG=%d.\n", val); if (val >= 0 && val < ARRAY_SIZE(creg_strings)) { dbg("%s\n", creg_strings[val]); } else { dbg("Unknown +CREG status: %d\n", val); } if (sub->network_state < NETWORK_SETUP_WAITING_NETWORK_REGISTRATION) { /* Not ready yet, spurious +CREG URC? */ ubdbg("Ignored spurious +CREG URC.\n"); return; } switch (val) { case 1: case 5: /* * If 'val' is 1, registered: home network. * If 'val' is 5, registered: roamed. */ if (sub->network_state == NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION) { /* Cannot do state transition to UBMODEM_LEVEL_NETWORK right now * as still retrying AT+COPS=0. Defer handling to * retry_ATpCOPS_handler. */ sub->received_creg_while_retrying = val; } else { network_registration_successed(modem, sub); } return; case 0: /* * MT not searching for connection. */ if (sub->network_state == NETWORK_SETUP_WAITING_NETWORK_REGISTRATION) { /* Stop timer before issuing command. */ if (modem->creg_timer_id >= 0) { __ubmodem_remove_timer(modem, modem->creg_timer_id); 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; ret = __ubmodem_set_timer(modem, 1000, &network_retry_registration_timer_handler, sub); MODEM_DEBUGASSERT(modem, ret != ERROR); modem->creg_timer_id = ret; ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, true); } return; case 4: /* * If 'val' is 4, unknown registration error. * * Network registration flow-chart in "AT Commands Examples" * (UBX-13001820, R09, p.24) tells that proper action for this * event is to 'Wait'. */ return; case 3: /* * If 'val' is 3, registration was denied. * * Network registration flow-chart in "AT Commands Examples" * (UBX-13001820, R09, p.24) tells that proper action for this * event is 'DTE intervention may be required'. Further information * on event type '3': * * "3: the registration fails after a Location Update Reject; * possible causes are: * - Illegal MS * - Illegal ME * - IMSI unknown at HLR * - PLMN not allowed * - Location area not allowed * - Roaming not allowed in this location area * - Network failure * - Network congestion * * If the registration type is manual, then no further attempt is * made to search for a new PLMN or register with it. If the * registration type is automatic, the MS may look for an allowed * PLMN if the rejection cause was roaming restriction. In case of * illegal MS / ME, there could be possible problems with either * the SIM card or with the MT's identity (IMEI): user intervention * may be required." * * Modem can still be continuing connection effort after this event * especially in roaming conditions. Thus, we do not react on this * message but keep waiting for timeout or other indication of * network error. */ return; case 2: /* * If 'val' is 2, modem is trying to register. */ return; default: /* * Unknown. */ return; } }
static void urc_pCREG_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) { int8_t val; int err; int ret; /* * Response handler for +CREG URC. */ MODEM_DEBUGASSERT(modem, cmd == &urc_ATpCREG); if (info->status != RESP_STATUS_URC) { /* Should not happen. */ MODEM_DEBUGASSERT(modem, false); return; } if (!__ubmodem_stream_get_int8(&resp_stream, &stream_len, &val)) { /* Should not happen. */ MODEM_DEBUGASSERT(modem, false); return; } dbg("Network registration URC, +CREG=%d.\n", val); if (val >= 0 && val < ARRAY_SIZE(creg_strings)) { dbg("%s\n", creg_strings[val]); } else { dbg("Unknown +CREG status: %d\n", val); } if (modem->level < UBMODEM_LEVEL_NETWORK) { struct modem_sub_setup_network_s *sub = &modem->sub.setup_network; DEBUGASSERT(modem->state == MODEM_STATE_IN_SUBSTATE); if (sub->network_state < NETWORK_SETUP_WAITING_NETWORK_REGISTRATION) { /* Not ready yet, spurious +CREG URC? */ ubdbg("Ignored spurious +CREG URC.\n"); return; } switch (val) { case 1: case 5: /* * If 'val' is 1, registered: home network. * If 'val' is 5, registered: roamed. */ if (sub->network_state == NETWORK_SETUP_RETRYING_NETWORK_REGISTRATION) { /* Cannot do state transition to UBMODEM_LEVEL_NETWORK right now * as still retrying AT+COPS=0. Defer handling to * retry_ATpCOPS_handler. */ sub->received_creg_while_retrying = val; } else { /* Report successful cellular network connection. */ sub->keep_creg_urc = true; __ubmodem_reached_level(modem, UBMODEM_LEVEL_NETWORK); } return; case 0: /* * MT not searching for connection. */ if (sub->network_state == NETWORK_SETUP_WAITING_NETWORK_REGISTRATION) { /* 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; case 4: /* * If 'val' is 4, unknown registration error. */ /* no break */ case 3: /* * If 'val' is 3, registration was denied. */ /* Perform fail-over code from timeout handler. */ network_register_timer_handler(modem, -1, sub); return; case 2: /* * If 'val' is 2, modem is trying to register. */ return; default: /* * Unknown. */ return; } } else { /* Current level is UBMODEM_LEVEL_NETWORK or higher. */ switch (val) { default: /* Unknown? */ case 1: /* Switched to home network? */ case 5: /* Switched to roaming? */ if (modem->creg_timer_id >= 0) { __ubmodem_remove_timer(modem, modem->creg_timer_id); modem->creg_timer_id = -1; } return; case 2: /* Looking for connection. */ /* Start connection search timeout timer. */ ret = __ubmodem_set_timer(modem, MODEM_CMD_NETWORK_TIMEOUT * 100, &network_reregister_timer_handler, modem); if (ret == ERROR) { /* Error here? Add assert? Or just try bailout? */ MODEM_DEBUGASSERT(modem, false); (void)network_reregister_timer_handler(modem, -1, modem); return; } modem->creg_timer_id = ret; return; case 3: /* Registration failed? */ case 4: /* Unknown registration error? */ case 0: /* MT not searching for connection. */ /* Unregister +CREG URC */ __ubparser_unregister_response_handler(&modem->parser, urc_ATpCREG.name); modem->creg_urc_registered = 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, retry_network_through_sim, NULL); return; } } }