void __ubmodem_network_cleanup(struct ubmodem_s *modem) { if (modem->level == UBMODEM_LEVEL_GPRS) { /* Uninitialize GRPS */ __ubmodem_gprs_cleanup(modem); } if (modem->level >= UBMODEM_LEVEL_NETWORK) { if (modem->creg_timer_id != -1) { /* Unregister timeout. */ __ubmodem_remove_timer(modem, modem->creg_timer_id); modem->creg_timer_id = -1; ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, false); } if (modem->creg_urc_registered) { /* Unregister +CREG URC */ __ubparser_unregister_response_handler(&modem->parser, urc_ATpCREG.name); modem->creg_urc_registered = false; } } }
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); } }
static void setup_network_cleanup(struct ubmodem_s *modem) { struct modem_sub_setup_network_s *sub = &modem->sub.setup_network; if (modem->creg_timer_id != -1) { /* Unregister timeout. */ __ubmodem_remove_timer(modem, modem->creg_timer_id); modem->creg_timer_id = -1; } if (modem->creg_urc_registered && !sub->keep_creg_urc) { /* Unregister +CREG URC */ __ubparser_unregister_response_handler(&modem->parser, urc_ATpCREG.name); modem->creg_urc_registered = false; } }
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 monitor_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 ret; (void)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->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); } switch (val) { default: /* Unknown? */ case 1: /* Switched to home network? */ case 5: /* Switched to roaming? */ return; case 2: /* Looking for connection. */ #ifdef CONFIG_UBMODEM_CREG_WAIT_NETWORK_TO_RESTORE /* Start connection search timeout timer. */ ret = __ubmodem_set_timer(modem, MODEM_CMD_NETWORK_TIMEOUT * 100, &network_reregister_timer_handler, modem); MODEM_DEBUGASSERT(modem, ret != ERROR); modem->creg_timer_id = ret; ubmodem_pm_set_activity(modem, UBMODEM_PM_ACTIVITY_HIGH, true); return; #else /* Reset network through SIM reinitialization. Appears to work * better in roaming conditions. TODO: Study why, do we understand * function of modem in low-signal environments properly? */ #endif 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; } }
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; } } }