Cellular: check plmn against network to verify correct network and don't try to register again if we are are already in correct nw.

pull/6629/head
Teppo Järvelin 2018-04-17 09:46:28 +03:00
parent e4c37f2275
commit e78e1d28db
5 changed files with 158 additions and 29 deletions

View File

@ -43,7 +43,7 @@ namespace mbed
CellularConnectionFSM::CellularConnectionFSM() :
_serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _event_status_cb(0), _network(0), _power(0), _sim(0),
_queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(0), _retry_count(0), _event_timeout(-1),
_at_queue(8 * EVENTS_EVENT_SIZE), _event_id(0), _plmn(0)
_at_queue(8 * EVENTS_EVENT_SIZE), _event_id(0), _plmn(0), _command_success(false), _plmn_network_found(false)
{
memset(_sim_pin, 0, sizeof(_sim_pin));
#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
@ -284,7 +284,7 @@ void CellularConnectionFSM::report_failure(const char* msg)
const char* CellularConnectionFSM::get_state_string(CellularState state)
{
#if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Attaching network", "Connecting network", "Connected"};
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Connecting network", "Connected"};
return strings[state];
#else
return NULL;
@ -302,6 +302,55 @@ nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg)
return err;
}
bool CellularConnectionFSM::is_registered_to_plmn()
{
int format;
CellularNetwork::operator_t op;
nsapi_error_t err = _network->get_operator_params(format, op);
if (err == 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;
nsapi_error_t err = _network->get_operator_names(names_list);
if (err == 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;
} else {
names_list.delete_all();
return false;
}
}
}
}
names_list.delete_all();
}
return false;
}
nsapi_error_t CellularConnectionFSM::continue_from_state(CellularState state)
{
tr_info("Continue state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state),
@ -338,6 +387,7 @@ void CellularConnectionFSM::enter_to_state(CellularState state)
{
_next_state = state;
_retry_count = 0;
_command_success = false;
}
void CellularConnectionFSM::retry_state_or_fail()
@ -414,7 +464,11 @@ void CellularConnectionFSM::state_sim_pin()
_cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
enter_to_state(STATE_REGISTERING_NETWORK);
if (_plmn) {
enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
enter_to_state(STATE_REGISTERING_NETWORK);
}
} else {
retry_state_or_fail();
}
@ -424,31 +478,38 @@ void CellularConnectionFSM::state_registering()
{
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
if (is_registered()) {
if (_plmn && _retry_count == 0) {
// we don't know which network we are registered, try to register to specific network
// we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
bool auto_reg = false;
nsapi_error_t err = is_automatic_registering(auto_reg);
if (err == NSAPI_ERROR_OK && !auto_reg) {
// automatic registering is not on, set registration and retry
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
set_network_registration();
retry_state_or_fail();
} else {
// we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK);
}
} else {
if (_plmn) {
set_network_registration();
} else {
bool auto_reg = false;
nsapi_error_t err = is_automatic_registering(auto_reg);
if (err == NSAPI_ERROR_OK && !auto_reg) {
// automatic registering is not on, set registration and retry
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
set_network_registration();
}
}
retry_state_or_fail();
}
}
// only used when _plmn is set
void CellularConnectionFSM::state_manual_registering_network()
{
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
tr_info("state_manual_registering_network");
if (!_plmn_network_found) {
if (is_registered() && is_registered_to_plmn()) {
_plmn_network_found = true;
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
if (!_command_success) {
_command_success = set_network_registration();
}
retry_state_or_fail();
}
}
}
void CellularConnectionFSM::state_attaching()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
@ -457,7 +518,9 @@ void CellularConnectionFSM::state_attaching()
if (attach_status == CellularNetwork::Attached) {
enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
} else {
set_attach_network();
if (!_command_success) {
_command_success = set_attach_network();
}
retry_state_or_fail();
}
} else {
@ -519,6 +582,9 @@ void CellularConnectionFSM::event()
case STATE_REGISTERING_NETWORK:
state_registering();
break;
case STATE_MANUAL_REGISTERING_NETWORK:
state_manual_registering_network();
break;
case STATE_ATTACHING_NETWORK:
state_attaching();
break;
@ -595,13 +661,23 @@ void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)>
void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr)
{
tr_info("FSM: network_callback called with event: %d, intptr: %d", ev, ptr);
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) {
tr_info("FSM: network_callback called with event: %d, intptr: %d, _state: %s", ev, ptr, get_state_string(_state));
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged &&
(_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) {
// expect packet data so only these states are valid
if (ptr == CellularNetwork::RegisteredHomeNetwork && CellularNetwork::RegisteredRoaming) {
_queue.cancel(_event_id);
continue_from_state(STATE_ATTACHING_NETWORK);
if (ptr == CellularNetwork::RegisteredHomeNetwork || ptr == CellularNetwork::RegisteredRoaming) {
if (_plmn) {
if (is_registered_to_plmn()) {
if (!_plmn_network_found) {
_plmn_network_found = true;
_queue.cancel(_event_id);
continue_from_state(STATE_ATTACHING_NETWORK);
}
}
} else {
_queue.cancel(_event_id);
continue_from_state(STATE_ATTACHING_NETWORK);
}
}
}

View File

@ -58,6 +58,7 @@ public:
STATE_DEVICE_READY,
STATE_SIM_PIN,
STATE_REGISTERING_NETWORK,
STATE_MANUAL_REGISTERING_NETWORK,
STATE_ATTACHING_NETWORK,
STATE_ACTIVATING_PDP_CONTEXT,
STATE_CONNECTING_NETWORK,
@ -169,6 +170,7 @@ private:
void state_device_ready();
void state_sim_pin();
void state_registering();
void state_manual_registering_network();
void state_attaching();
void state_activating_pdp_context();
void state_connect_to_network();
@ -177,6 +179,7 @@ private:
void retry_state_or_fail();
void network_callback(nsapi_event_t ev, intptr_t ptr);
nsapi_error_t continue_from_state(CellularState state);
bool is_registered_to_plmn();
private:
friend class EasyCellularConnection;
@ -211,6 +214,8 @@ private:
char _st_string[20];
int _event_id;
const char* _plmn;
bool _command_success;
bool _plmn_network_found;
};
} // namespace

View File

@ -199,6 +199,18 @@ public:
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
struct operator_names_t {
char numeric[MAX_OPERATOR_NAME_SHORT+1];
char alpha[MAX_OPERATOR_NAME_LONG+1];
operator_names_t* next;
operator_names_t() {
numeric[0] = '\0';
alpha[0] = '\0';
next = NULL;
}
};
typedef CellularList<operator_names_t> operator_names_list;
/* Network registering mode */
enum NWRegisteringMode {
NWModeAutomatic = 0, // automatic registering
@ -452,6 +464,12 @@ public:
*/
virtual nsapi_error_t set_blocking(bool blocking) = 0;
/** Read operator names
*
* @param op_names on successful return will contain linked list of operator names.
* @return zero on success
*/
virtual nsapi_error_t get_operator_names(operator_names_list &op_names) = 0;
};
} // namespace mbed

View File

@ -899,6 +899,12 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
while (_at.info_elem('(')) {
op = operators.add_new();
if (!op) {
tr_warn("Could not allocate new operator");
_at.resp_stop();
opsCount = idx;
return _at.unlock_return_error();
}
op->op_status = (operator_t::Status)_at.read_int();
_at.read_string(op->op_long, sizeof(op->op_long));
@ -920,7 +926,6 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
_at.resp_stop();
opsCount = idx;
return _at.unlock_return_error();
}
@ -1174,3 +1179,27 @@ nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &o
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_names)
{
_at.lock();
_at.cmd_start("AT+COPN?");
_at.cmd_stop();
_at.resp_start("+COPN:");
operator_names_t *names = NULL;
while (_at.info_resp()) {
names = op_names.add_new();
if (!names) {
tr_warn("Could not allocate new operator_names_t");
_at.resp_stop();
return _at.unlock_return_error();
}
_at.read_string(names->numeric, sizeof(names->numeric));
_at.read_string(names->alpha, sizeof(names->alpha));
}
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -139,6 +139,7 @@ protected:
*/
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology op_rat);
virtual nsapi_error_t get_operator_names(operator_names_list &op_names);
private:
// "NO CARRIER" urc
void urc_no_carrier();