Merge pull request #6629 from jarvte/add_select_plmn_to_cellularfsm

Cellular: add plmn for CellularConnectionFSM
pull/6682/head
Martin Kojtal 2018-04-19 12:07:20 +02:00 committed by GitHub
commit 9cc4302c51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 196 additions and 20 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)
_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
@ -146,6 +146,11 @@ void CellularConnectionFSM::set_sim_pin(const char * sim_pin)
_sim_pin[sizeof(_sim_pin)-1] = '\0';
}
void CellularConnectionFSM::set_plmn(const char* plmn)
{
_plmn = plmn;
}
bool CellularConnectionFSM::open_sim()
{
CellularSIM::SimState state = CellularSIM::SimStateUnknown;
@ -162,7 +167,7 @@ bool CellularConnectionFSM::open_sim()
nsapi_error_t err = _sim->set_pin(_sim_pin);
if (err) {
tr_error("SIM pin set failed with: %d, bailing out...", err);
}
}
} else {
tr_warn("PIN required but No SIM pin provided.");
}
@ -175,11 +180,10 @@ bool CellularConnectionFSM::open_sim()
return state == CellularSIM::SimStateReady;
}
bool CellularConnectionFSM::set_network_registration(char *plmn)
bool CellularConnectionFSM::set_network_registration()
{
nsapi_error_t error = _network->set_registration(plmn);
if (error != NSAPI_ERROR_OK) {
tr_error("Set network registration mode failing (%d)", error);
if (_network->set_registration(_plmn) != NSAPI_ERROR_OK) {
tr_error("Failed to set network registration.");
return false;
}
return true;
@ -279,8 +283,12 @@ void CellularConnectionFSM::report_failure(const char* msg)
const char* CellularConnectionFSM::get_state_string(CellularState state)
{
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"};
#if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"};
return strings[state];
#else
return NULL;
#endif // #if MBED_CONF_MBED_TRACE_ENABLE
}
nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg)
@ -294,6 +302,54 @@ 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;
}
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),
@ -330,6 +386,7 @@ void CellularConnectionFSM::enter_to_state(CellularState state)
{
_next_state = state;
_retry_count = 0;
_command_success = false;
}
void CellularConnectionFSM::retry_state_or_fail()
@ -406,7 +463,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();
}
@ -421,7 +482,7 @@ void CellularConnectionFSM::state_registering()
} else {
bool auto_reg = false;
nsapi_error_t err = is_automatic_registering(auto_reg);
if (err == NSAPI_ERROR_OK && !auto_reg) { // when we support plmn add this : || plmn
if (err == NSAPI_ERROR_OK && !auto_reg) {
// automatic registering is not on, set registration and retry
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
set_network_registration();
@ -430,6 +491,24 @@ void CellularConnectionFSM::state_registering()
}
}
// 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);
@ -438,7 +517,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 {
@ -500,6 +581,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;
@ -576,13 +660,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,
@ -139,12 +140,24 @@ public:
*/
void set_retry_timeout_array(uint16_t timeout[], int array_len);
/** Sets the operator plmn which is used when registering to a network specified by plmn. If plmn is not set then automatic
* registering is used when registering to a cellular network. Does not start any operations.
*
* @param plmn operator in numeric format. See more from 3GPP TS 27.007 chapter 7.3.
*/
void set_plmn(const char* plmn);
/** returns readable format of the given state. Used for printing states while debugging.
*
* @param state state which is returned in string format
* @return string format of the given state
*/
const char* get_state_string(CellularState state);
private:
bool power_on();
bool open_sim();
bool get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered);
bool set_network_registration(char *plmn = 0);
bool set_network_registration();
bool get_attach_network(CellularNetwork::AttachStatus &status);
bool set_attach_network();
bool is_registered();
@ -157,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();
@ -165,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;
@ -198,6 +213,9 @@ private:
events::EventQueue _at_queue;
char _st_string[20];
int _event_id;
const char* _plmn;
bool _command_success;
bool _plmn_network_found;
};
} // namespace

View File

@ -280,6 +280,11 @@ void EasyCellularConnection::modem_debug_on(bool on)
}
}
void EasyCellularConnection::set_plmn(const char* plmn)
{
_cellularConnectionFSM.set_plmn(plmn);
}
NetworkStack *EasyCellularConnection::get_stack()
{
return _cellularConnectionFSM.get_stack();

View File

@ -131,6 +131,12 @@ public:
*/
void modem_debug_on(bool on);
/** Sets the operator plmn which is used when registering to a network specified by plmn. If plmn is not set then automatic
* registering is used when registering to a cellular network.
*
* @param plmn operator in numeric format. See more from 3GPP TS 27.007 chapter 7.3.
*/
void set_plmn(const char* plmn);
protected:
/** Provide access to the NetworkStack object

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
@ -460,6 +472,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

@ -656,7 +656,7 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
tr_debug("Automatic network registration");
_at.cmd_start("AT+COPS?");
_at.cmd_stop();
_at.resp_start("AT+COPS:");
_at.resp_start("+COPS:");
int mode = _at.read_int();
_at.resp_stop();
if (mode != 0) {
@ -912,6 +912,14 @@ 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();
_at.unlock();
operators.delete_all();
opsCount = 0;
return NSAPI_ERROR_NO_MEMORY;
}
op->op_status = (operator_t::Status)_at.read_int();
_at.read_string(op->op_long, sizeof(op->op_long));
@ -933,7 +941,6 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
_at.resp_stop();
opsCount = idx;
return _at.unlock_return_error();
}
@ -1045,8 +1052,9 @@ nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t& params
params = params_list.add_new();
if (!params) {
tr_warn("Could not allocate new pdpcontext_params_t");
params_list.delete_all();
_at.resp_stop();
_at.unlock();
params_list.delete_all();
free(temp);
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
@ -1187,3 +1195,29 @@ 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();
_at.unlock();
op_names.delete_all();
return NSAPI_ERROR_NO_MEMORY;
}
_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

@ -141,6 +141,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();