Cellular: removed manual registering state.

Simplified state machine by removing manual registering state.
This was done as some modems did not have all the needed at commands
for checking the registered network. Some modem run out of memory as when
checking correct network there might be so many networks available.
Manual registration still works but it does not do any checks to which network
it's registered. Moved manual registering at command earlier in state machine so it forces
registering to a correct network. Internal refactor/fix, does not affect applications.
pull/9937/head
Teppo Järvelin 2019-03-01 14:39:55 +02:00
parent 5c24ffefa4
commit a830dbf47d
4 changed files with 55 additions and 123 deletions

View File

@ -34,7 +34,6 @@ enum UT_CellularState {
UT_STATE_DEVICE_READY, UT_STATE_DEVICE_READY,
UT_STATE_SIM_PIN, UT_STATE_SIM_PIN,
UT_STATE_REGISTERING_NETWORK, UT_STATE_REGISTERING_NETWORK,
UT_STATE_MANUAL_REGISTERING_NETWORK,
UT_STATE_ATTACHING_NETWORK, UT_STATE_ATTACHING_NETWORK,
UT_STATE_MAX_FSM_STATE UT_STATE_MAX_FSM_STATE
}; };
@ -392,8 +391,8 @@ TEST_F(TestCellularStateMachine, test_run_to_state)
ut.set_plmn("12345"); ut.set_plmn("12345");
ASSERT_EQ(NSAPI_ERROR_OK, ut.run_to_device_registered()); ASSERT_EQ(NSAPI_ERROR_OK, ut.run_to_device_registered());
(void)ut.get_current_status(current_state, target_state); (void)ut.get_current_status(current_state, target_state);
ASSERT_EQ(UT_STATE_MANUAL_REGISTERING_NETWORK, current_state); ASSERT_EQ(UT_STATE_REGISTERING_NETWORK, current_state);
ASSERT_EQ(UT_STATE_MANUAL_REGISTERING_NETWORK, target_state); ASSERT_EQ(UT_STATE_REGISTERING_NETWORK, target_state);
ut.cellular_event_changed((nsapi_event_t)CellularRegistrationStatusChanged, (intptr_t)&data); ut.cellular_event_changed((nsapi_event_t)CellularRegistrationStatusChanged, (intptr_t)&data);
ut.reset(); ut.reset();

View File

@ -171,7 +171,9 @@ void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
reg_params._status == RegisteredRoaming)) { reg_params._status == RegisteredRoaming)) {
if (previous_registration_status == RegisteredHomeNetwork || if (previous_registration_status == RegisteredHomeNetwork ||
previous_registration_status == RegisteredRoaming) { previous_registration_status == RegisteredRoaming) {
call_network_cb(NSAPI_STATUS_DISCONNECTED); if (type != C_REG) {// we are interested only if we drop from packet network
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
}
} }
} }
} }
@ -267,6 +269,9 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
tr_debug("Manual network registration to %s", plmn); tr_debug("Manual network registration to %s", plmn);
_at.cmd_start("AT+COPS=1,2,"); _at.cmd_start("AT+COPS=1,2,");
_at.write_string(plmn); _at.write_string(plmn);
if (_op_act != RAT_UNKNOWN) {
_at.write_int(_op_act);
}
_at.cmd_stop_read_resp(); _at.cmd_stop_read_resp();
} }

View File

@ -48,8 +48,7 @@ CellularStateMachine::CellularStateMachine(CellularDevice &device, events::Event
_cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state), _cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state),
_event_status_cb(0), _network(0), _queue(queue), _queue_thread(0), _sim_pin(0), _event_status_cb(0), _network(0), _queue(queue), _queue_thread(0), _sim_pin(0),
_retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false), _retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false),
_plmn_network_found(false), _is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE), _is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE), _status(0)
_status(0)
{ {
#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0 #if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
_start_time = 0; _start_time = 0;
@ -83,7 +82,6 @@ void CellularStateMachine::reset()
_state = STATE_INIT; _state = STATE_INIT;
_event_timeout = -1; _event_timeout = -1;
_event_id = -1; _event_id = -1;
_plmn_network_found = false;
_is_retry = false; _is_retry = false;
_status = 0; _status = 0;
_target_state = STATE_INIT; _target_state = STATE_INIT;
@ -161,7 +159,20 @@ bool CellularStateMachine::open_sim()
} }
} }
return state == CellularDevice::SimStateReady; bool sim_ready = state == CellularDevice::SimStateReady;
if (sim_ready) {
// If plmn is set, we should it right after sim is opened so that registration is forced to correct network.
if (_plmn && strlen(_plmn)) {
_cb_data.error = _network->set_registration(_plmn);
tr_debug("STM: manual set_registration: %d, plmn: %s", _cb_data.error, _plmn);
if (_cb_data.error) {
return false;
}
}
}
return sim_ready;
} }
bool CellularStateMachine::is_registered() bool CellularStateMachine::is_registered()
@ -169,7 +180,9 @@ bool CellularStateMachine::is_registered()
CellularNetwork::RegistrationStatus status; CellularNetwork::RegistrationStatus status;
bool is_registered = false; bool is_registered = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) { // accept only CGREG/CEREG. CREG is for circuit switch network changed. If we accept CREG attach will fail if also
// CGREG/CEREG is not registered.
for (int type = 0; type < CellularNetwork::C_REG; type++) {
if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) { if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) {
if (is_registered) { if (is_registered) {
break; break;
@ -178,6 +191,11 @@ bool CellularStateMachine::is_registered()
} }
_cb_data.status_data = status; _cb_data.status_data = status;
// in manual registering we are forcing registration to certain network so we don't accept active context or attached
// as indication that device is registered to correct network.
if (_plmn && strlen(_plmn)) {
return is_registered;
}
return is_registered || _status; return is_registered || _status;
} }
@ -249,61 +267,13 @@ void CellularStateMachine::report_failure(const char *msg)
const char *CellularStateMachine::get_state_string(CellularState state) const const char *CellularStateMachine::get_state_string(CellularState state) const
{ {
#if MBED_CONF_MBED_TRACE_ENABLE #if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[STATE_MAX_FSM_STATE] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network"}; static const char *strings[STATE_MAX_FSM_STATE] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Attaching network"};
return strings[state]; return strings[state];
#else #else
return NULL; return NULL;
#endif // #if MBED_CONF_MBED_TRACE_ENABLE #endif // #if MBED_CONF_MBED_TRACE_ENABLE
} }
bool CellularStateMachine::is_registered_to_plmn()
{
int format;
CellularNetwork::operator_t op;
_cb_data.error = _network->get_operator_params(format, op);
if (_cb_data.error == NSAPI_ERROR_OK) {
if (format == 2) {
// great, numeric format we can do comparison for that
if (strcmp(op.op_num, _plmn) == 0) {
return true;
}
return false;
}
// format was alpha, get operator names to do the comparing
CellularNetwork::operator_names_list names_list;
_cb_data.error = _network->get_operator_names(names_list);
if (_cb_data.error == NSAPI_ERROR_OK) {
CellularNetwork::operator_names_t *op_names = names_list.get_head();
bool found_match = false;
while (op_names) {
if (format == 0) {
if (strcmp(op.op_long, op_names->alpha) == 0) {
found_match = true;
}
} else if (format == 1) {
if (strcmp(op.op_short, op_names->alpha) == 0) {
found_match = true;
}
}
if (found_match) {
if (strcmp(_plmn, op_names->numeric)) {
names_list.delete_all();
return true;
}
names_list.delete_all();
return false;
}
}
}
names_list.delete_all();
}
return false;
}
void CellularStateMachine::enter_to_state(CellularState state) void CellularStateMachine::enter_to_state(CellularState state)
{ {
_next_state = state; _next_state = state;
@ -378,6 +348,7 @@ bool CellularStateMachine::device_ready()
_event_status_cb((nsapi_event_t)CellularDeviceReady, (intptr_t)&_cb_data); _event_status_cb((nsapi_event_t)CellularDeviceReady, (intptr_t)&_cb_data);
} }
_cellularDevice.set_ready_cb(0); _cellularDevice.set_ready_cb(0);
return true; return true;
} }
@ -410,16 +381,15 @@ void CellularStateMachine::state_sim_pin()
_cellularDevice.set_timeout(TIMEOUT_SIM_PIN); _cellularDevice.set_timeout(TIMEOUT_SIM_PIN);
tr_info("Setup SIM (timeout %d s)", TIMEOUT_SIM_PIN / 1000); tr_info("Setup SIM (timeout %d s)", TIMEOUT_SIM_PIN / 1000);
if (open_sim()) { if (open_sim()) {
bool success = false; bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) { for (int type = 0; type < CellularNetwork::C_MAX; type++) {
_cb_data.error = _network->set_registration_urc((CellularNetwork::RegistrationType)type, true); _cb_data.error = _network->set_registration_urc((CellularNetwork::RegistrationType)type, true);
if (!_cb_data.error) { if (!_cb_data.error && (type == CellularNetwork::C_EREG || type == CellularNetwork::C_GREG)) {
success = true; success = true;
} }
} }
if (!success) { if (!success) {
tr_warn("Failed to set any URC's for registration"); tr_error("Failed to set CEREG/CGREG URC's for registration");
retry_state_or_fail(); retry_state_or_fail();
return; return;
} }
@ -428,16 +398,13 @@ void CellularStateMachine::state_sim_pin()
tr_debug("Active context found."); tr_debug("Active context found.");
_status |= ACTIVE_PDP_CONTEXT; _status |= ACTIVE_PDP_CONTEXT;
} }
CellularNetwork::AttachStatus status; // check if modem is already attached to a network CellularNetwork::AttachStatus status = CellularNetwork::Detached; // check if modem is already attached to a network
if (_network->get_attach(status) == NSAPI_ERROR_OK && status == CellularNetwork::Attached) { if (_network->get_attach(status) == NSAPI_ERROR_OK && status == CellularNetwork::Attached) {
_status |= ATTACHED_TO_NETWORK; _status |= ATTACHED_TO_NETWORK;
tr_debug("Cellular already attached."); tr_debug("Cellular already attached.");
} }
if (_plmn) {
enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
enter_to_state(STATE_REGISTERING_NETWORK); enter_to_state(STATE_REGISTERING_NETWORK);
}
} else { } else {
retry_state_or_fail(); retry_state_or_fail();
} }
@ -448,42 +415,23 @@ void CellularStateMachine::state_registering()
_cellularDevice.set_timeout(TIMEOUT_NETWORK); _cellularDevice.set_timeout(TIMEOUT_NETWORK);
tr_info("Network registration (timeout %d s)", TIMEOUT_REGISTRATION / 1000); tr_info("Network registration (timeout %d s)", TIMEOUT_REGISTRATION / 1000);
if (is_registered()) { if (is_registered()) {
if (_cb_data.status_data != CellularNetwork::RegisteredHomeNetwork &&
_cb_data.status_data != CellularNetwork::RegisteredRoaming && _status) {
// there was already activated context or attached to network, and registration status is not registered, set to already registered.
_cb_data.status_data = CellularNetwork::AlreadyRegistered; _cb_data.status_data = CellularNetwork::AlreadyRegistered;
}
_cb_data.error = NSAPI_ERROR_OK; _cb_data.error = NSAPI_ERROR_OK;
_event_status_cb(_current_event, (intptr_t)&_cb_data); _event_status_cb(_current_event, (intptr_t)&_cb_data);
// we are already registered, go to attach // we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK); enter_to_state(STATE_ATTACHING_NETWORK);
} else { } else {
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION); _cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
if (!_command_success) { if (!_command_success && !_plmn) { // don't call set_registration twice for manual registration
_cb_data.error = _network->set_registration();
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
}
retry_state_or_fail();
}
}
// only used when _plmn is set
void CellularStateMachine::state_manual_registering_network()
{
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
tr_info("Manual registration %s (timeout %d s)", _plmn, TIMEOUT_REGISTRATION / 1000);
if (!_plmn_network_found) {
if (is_registered() && is_registered_to_plmn()) {
// we have to send registration changed event as network thinks that we are not registered even we have active PDP context
_cb_data.status_data = CellularNetwork::AlreadyRegistered;
_cb_data.error = NSAPI_ERROR_OK;
_event_status_cb(_current_event, (intptr_t)&_cb_data);
_plmn_network_found = true;
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
if (!_command_success) {
_cb_data.error = _network->set_registration(_plmn); _cb_data.error = _network->set_registration(_plmn);
_command_success = (_cb_data.error == NSAPI_ERROR_OK); _command_success = (_cb_data.error == NSAPI_ERROR_OK);
} }
retry_state_or_fail(); retry_state_or_fail();
} }
}
} }
void CellularStateMachine::state_attaching() void CellularStateMachine::state_attaching()
@ -523,13 +471,8 @@ void CellularStateMachine::continue_from_state(CellularState state)
nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state) nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state)
{ {
_mutex.lock(); _mutex.lock();
CellularState tmp_state = state;
if (_plmn && tmp_state == STATE_REGISTERING_NETWORK) {
tmp_state = STATE_MANUAL_REGISTERING_NETWORK;
}
// call pre_event via queue so that it's in same thread and it's safe to decisions // call pre_event via queue so that it's in same thread and it's safe to decisions
int id = _queue.call_in(0, this, &CellularStateMachine::pre_event, tmp_state); int id = _queue.call_in(0, this, &CellularStateMachine::pre_event, state);
if (!id) { if (!id) {
report_failure("Failed to call queue."); report_failure("Failed to call queue.");
stop(); stop();
@ -620,10 +563,6 @@ void CellularStateMachine::event()
_current_event = (nsapi_event_t)CellularRegistrationStatusChanged; _current_event = (nsapi_event_t)CellularRegistrationStatusChanged;
state_registering(); state_registering();
break; break;
case STATE_MANUAL_REGISTERING_NETWORK:
_current_event = (nsapi_event_t)CellularRegistrationStatusChanged;
state_manual_registering_network();
break;
case STATE_ATTACHING_NETWORK: case STATE_ATTACHING_NETWORK:
_current_event = (nsapi_event_t)CellularAttachNetwork; _current_event = (nsapi_event_t)CellularAttachNetwork;
state_attaching(); state_attaching();
@ -694,14 +633,14 @@ bool CellularStateMachine::check_is_target_reached()
void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr) void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr)
{ {
cell_callback_data_t *data = (cell_callback_data_t *)ptr; cell_callback_data_t *data = (cell_callback_data_t *)ptr;
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) {
(_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) {
// expect packet data so only these states are valid // expect packet data so only these states are valid
if ((data->status_data == CellularNetwork::RegisteredHomeNetwork || data->status_data == CellularNetwork::RegisteredRoaming) && data->error == NSAPI_ERROR_OK) { CellularNetwork::registration_params_t reg_params;
if (_plmn) { nsapi_error_t err = _network->get_registration_params(reg_params);
if (is_registered_to_plmn()) {
if (!_plmn_network_found) { if (err == NSAPI_ERROR_OK && (reg_params._type == CellularNetwork::C_EREG || reg_params._type == CellularNetwork::C_GREG)) {
_plmn_network_found = true; if ((data->status_data == CellularNetwork::RegisteredHomeNetwork ||
data->status_data == CellularNetwork::RegisteredRoaming) && data->error == NSAPI_ERROR_OK) {
_queue.cancel(_event_id); _queue.cancel(_event_id);
_is_retry = false; _is_retry = false;
_event_id = -1; _event_id = -1;
@ -709,15 +648,8 @@ void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr
continue_from_state(STATE_ATTACHING_NETWORK); continue_from_state(STATE_ATTACHING_NETWORK);
} }
} }
}
} else { } else {
_queue.cancel(_event_id); tr_debug("creg event, discard...");
_is_retry = false;
_event_id = -1;
if (!check_is_target_reached()) {
continue_from_state(STATE_ATTACHING_NETWORK);
}
}
} }
} }
} }

View File

@ -58,7 +58,6 @@ private:
STATE_DEVICE_READY, STATE_DEVICE_READY,
STATE_SIM_PIN, STATE_SIM_PIN,
STATE_REGISTERING_NETWORK, STATE_REGISTERING_NETWORK,
STATE_MANUAL_REGISTERING_NETWORK,
STATE_ATTACHING_NETWORK, STATE_ATTACHING_NETWORK,
STATE_MAX_FSM_STATE STATE_MAX_FSM_STATE
}; };
@ -146,12 +145,10 @@ private:
void state_device_ready(); void state_device_ready();
void state_sim_pin(); void state_sim_pin();
void state_registering(); void state_registering();
void state_manual_registering_network();
void state_attaching(); void state_attaching();
void enter_to_state(CellularState state); void enter_to_state(CellularState state);
void retry_state_or_fail(); void retry_state_or_fail();
void continue_from_state(CellularState state); void continue_from_state(CellularState state);
bool is_registered_to_plmn();
void report_failure(const char *msg); void report_failure(const char *msg);
void event(); void event();
void device_ready_cb(); void device_ready_cb();
@ -179,7 +176,6 @@ private:
int _event_id; int _event_id;
const char *_plmn; const char *_plmn;
bool _command_success; bool _command_success;
bool _plmn_network_found;
bool _is_retry; bool _is_retry;
cell_callback_data_t _cb_data; cell_callback_data_t _cb_data;
nsapi_event_t _current_event; nsapi_event_t _current_event;