Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CellularConnectionFSM.cpp Source File

CellularConnectionFSM.cpp

00001 /*
00002  * Copyright (c) 2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "CellularConnectionFSM.h"
00019 
00020 #ifdef CELLULAR_DEVICE
00021 
00022 #ifndef MBED_TRACE_MAX_LEVEL
00023 #define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO
00024 #endif
00025 #include "CellularLog.h"
00026 #include "CellularCommon.h"
00027 
00028 // timeout to wait for AT responses
00029 #define TIMEOUT_POWER_ON     (1*1000)
00030 #define TIMEOUT_SIM_PIN      (1*1000)
00031 #define TIMEOUT_NETWORK      (10*1000)
00032 #define TIMEOUT_CONNECT      (60*1000)
00033 #define TIMEOUT_REGISTRATION (180*1000)
00034 
00035 // maximum time when retrying network register, attach and connect in seconds ( 20minutes )
00036 #define TIMEOUT_NETWORK_MAX (20*60)
00037 
00038 #define RETRY_COUNT_DEFAULT 3
00039 
00040 namespace mbed
00041 {
00042 
00043 CellularConnectionFSM::CellularConnectionFSM() :
00044         _serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _event_status_cb(0), _network(0), _power(0), _sim(0),
00045         _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(0), _retry_count(0), _event_timeout(-1),
00046         _at_queue(8 * EVENTS_EVENT_SIZE), _event_id(0), _plmn(0), _command_success(false), _plmn_network_found(false)
00047 {
00048     memset(_sim_pin, 0, sizeof(_sim_pin));
00049 #if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
00050     _start_time = 0;
00051 #else
00052     // so that not every device don't start at the exact same time (for example after power outage)
00053     _start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY);
00054 #endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY
00055 
00056     // set initial retry values in seconds
00057     _retry_timeout_array[0] = 1; // double time on each retry in order to keep network happy
00058     _retry_timeout_array[1] = 2;
00059     _retry_timeout_array[2] = 4;
00060     _retry_timeout_array[3] = 8;
00061     _retry_timeout_array[4] = 16;
00062     _retry_timeout_array[5] = 32;
00063     _retry_timeout_array[6] = 64;
00064     _retry_timeout_array[7] = 128; // if around two minutes was not enough then let's wait much longer
00065     _retry_timeout_array[8] = 600;
00066     _retry_timeout_array[9] = TIMEOUT_NETWORK_MAX;
00067     _retry_array_length = MAX_RETRY_ARRAY_SIZE;
00068 }
00069 
00070 CellularConnectionFSM::~CellularConnectionFSM()
00071 {
00072     stop();
00073 }
00074 
00075 void CellularConnectionFSM::stop()
00076 {
00077     _queue.cancel(_event_id);
00078     _queue.break_dispatch();
00079 
00080     if (_queue_thread) {
00081         _queue_thread->terminate();
00082         delete _queue_thread;
00083         _queue_thread = NULL;
00084     }
00085 
00086     delete _cellularDevice;
00087     _cellularDevice = NULL;
00088     // _cellularDevice closes all interfaces in destructor
00089     _power = NULL;
00090     _network = NULL;
00091     _sim = NULL;
00092 
00093     _state = STATE_INIT;
00094     _next_state = _state;
00095 }
00096 
00097 nsapi_error_t CellularConnectionFSM::init()
00098 {
00099     tr_info("CELLULAR_DEVICE: %s", CELLULAR_STRINGIFY(CELLULAR_DEVICE));
00100     _cellularDevice = new CELLULAR_DEVICE(_at_queue);
00101     if (!_cellularDevice) {
00102         stop();
00103         return NSAPI_ERROR_NO_MEMORY ;
00104     }
00105 
00106     _power = _cellularDevice->open_power(_serial);
00107     if (!_power) {
00108         stop();
00109         return NSAPI_ERROR_NO_MEMORY ;
00110     }
00111 
00112     _network = _cellularDevice->open_network(_serial);
00113     if (!_network) {
00114         stop();
00115         return NSAPI_ERROR_NO_MEMORY ;
00116     }
00117 
00118     _sim = _cellularDevice->open_sim(_serial);
00119     if (!_sim) {
00120         stop();
00121         return NSAPI_ERROR_NO_MEMORY ;
00122     }
00123 
00124     _at_queue.chain(&_queue);
00125 
00126     _retry_count = 0;
00127     _state = STATE_INIT;
00128     _next_state = STATE_INIT;
00129 
00130     return _network->init();
00131 }
00132 
00133 bool CellularConnectionFSM::power_on()
00134 {
00135     nsapi_error_t err = _power->on();
00136     if (err != NSAPI_ERROR_OK  && err != NSAPI_ERROR_UNSUPPORTED ) {
00137         tr_warn("Cellular start failed. Power off/on.");
00138         err = _power->off();
00139         if (err != NSAPI_ERROR_OK  && err != NSAPI_ERROR_UNSUPPORTED ) {
00140             tr_error("Cellular power down failing after failed power up attempt!");
00141         }
00142         return false;
00143     }
00144     return true;
00145 }
00146 
00147 void CellularConnectionFSM::set_sim_pin(const char * sim_pin)
00148 {
00149     strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
00150     _sim_pin[sizeof(_sim_pin)-1] = '\0';
00151 }
00152 
00153 void CellularConnectionFSM::set_plmn(const char* plmn)
00154 {
00155     _plmn = plmn;
00156 }
00157 
00158 bool CellularConnectionFSM::open_sim()
00159 {
00160     CellularSIM::SimState state = CellularSIM::SimStateUnknown;
00161     // wait until SIM is readable
00162     // here you could add wait(secs) if you know start delay of your SIM
00163     if (_sim->get_sim_state(state) != NSAPI_ERROR_OK ) {
00164         tr_info("Waiting for SIM (err while reading)...");
00165         return false;
00166     }
00167 
00168     if (state == CellularSIM::SimStatePinNeeded) {
00169         if (strlen(_sim_pin)) {
00170             tr_info("SIM pin required, entering pin: %s", _sim_pin);
00171             nsapi_error_t err = _sim->set_pin(_sim_pin);
00172             if (err) {
00173                 tr_error("SIM pin set failed with: %d, bailing out...", err);
00174             }
00175         } else {
00176             tr_warn("PIN required but No SIM pin provided.");
00177         }
00178     }
00179 
00180     if (_event_status_cb) {
00181         _event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state);
00182     }
00183 
00184     return state == CellularSIM::SimStateReady;
00185 }
00186 
00187 bool CellularConnectionFSM::set_network_registration()
00188 {
00189     if (_network->set_registration(_plmn) != NSAPI_ERROR_OK ) {
00190         tr_error("Failed to set network registration.");
00191         return false;
00192     }
00193     return true;
00194 }
00195 
00196 bool CellularConnectionFSM::is_registered()
00197 {
00198     CellularNetwork::RegistrationStatus status;
00199     bool is_registered = false;
00200 
00201     for (int type = 0; type < CellularNetwork::C_MAX; type++) {
00202         if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) {
00203             tr_debug("get_network_registration: type=%d, status=%d", type, status);
00204             if (is_registered) {
00205                 break;
00206             }
00207         }
00208     }
00209 
00210     return is_registered;
00211 }
00212 
00213 bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type,
00214         CellularNetwork::RegistrationStatus &status, bool &is_registered)
00215 {
00216     is_registered = false;
00217     bool is_roaming = false;
00218     nsapi_error_t err = _network->get_registration_status(type, status);
00219     if (err != NSAPI_ERROR_OK ) {
00220         if (err != NSAPI_ERROR_UNSUPPORTED ) {
00221             tr_warn("Get network registration failed (type %d)!", type);
00222         }
00223         return false;
00224     }
00225     switch (status) {
00226         case CellularNetwork::RegisteredRoaming:
00227             is_roaming = true;
00228         // fall-through
00229         case CellularNetwork::RegisteredHomeNetwork:
00230             is_registered = true;
00231             break;
00232         case CellularNetwork::RegisteredSMSOnlyRoaming:
00233             is_roaming = true;
00234         // fall-through
00235         case CellularNetwork::RegisteredSMSOnlyHome:
00236             tr_warn("SMS only network registration!");
00237             break;
00238         case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
00239             is_roaming = true;
00240         // fall-through
00241         case CellularNetwork::RegisteredCSFBNotPreferredHome:
00242             tr_warn("Not preferred network registration!");
00243             break;
00244         case CellularNetwork::AttachedEmergencyOnly:
00245             tr_warn("Emergency only network registration!");
00246             break;
00247         case CellularNetwork::RegistrationDenied:
00248         case CellularNetwork::NotRegistered:
00249         case CellularNetwork::Unknown:
00250         case CellularNetwork::SearchingNetwork:
00251         default:
00252             break;
00253     }
00254 
00255     if (is_roaming) {
00256         tr_warn("Roaming cellular network!");
00257     }
00258 
00259     return true;
00260 }
00261 
00262 bool CellularConnectionFSM::get_attach_network(CellularNetwork::AttachStatus &status)
00263 {
00264     nsapi_error_t err = _network->get_attach(status);
00265     if (err != NSAPI_ERROR_OK ) {
00266         return false;
00267     }
00268     return true;
00269 }
00270 
00271 bool CellularConnectionFSM::set_attach_network()
00272 {
00273     nsapi_error_t attach_err = _network->set_attach();
00274     if (attach_err != NSAPI_ERROR_OK ) {
00275         return false;
00276     }
00277     return true;
00278 }
00279 
00280 void CellularConnectionFSM::report_failure(const char* msg)
00281 {
00282     tr_error("Cellular network failed: %s", msg);
00283     if (_status_callback) {
00284         _status_callback(_state, _next_state);
00285     }
00286 }
00287 
00288 const char* CellularConnectionFSM::get_state_string(CellularState state)
00289 {
00290 #if MBED_CONF_MBED_TRACE_ENABLE
00291     static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"};
00292     return strings[state];
00293 #else
00294     return NULL;
00295 #endif // #if MBED_CONF_MBED_TRACE_ENABLE
00296 }
00297 
00298 nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg)
00299 {
00300     CellularNetwork::NWRegisteringMode mode;
00301     nsapi_error_t err = _network->get_network_registering_mode(mode);
00302     if (err == NSAPI_ERROR_OK ) {
00303         tr_debug("automatic registering mode: %d", mode);
00304         auto_reg = (mode == CellularNetwork::NWModeAutomatic);
00305     }
00306     return err;
00307 }
00308 
00309 bool CellularConnectionFSM::is_registered_to_plmn()
00310 {
00311     int format;
00312     CellularNetwork::operator_t op;
00313 
00314     nsapi_error_t err = _network->get_operator_params(format, op);
00315     if (err == NSAPI_ERROR_OK ) {
00316         if (format == 2) {
00317             // great, numeric format we can do comparison for that
00318             if (strcmp(op.op_num, _plmn) == 0) {
00319                 return true;
00320             }
00321             return false;
00322         }
00323 
00324         // format was alpha, get operator names to do the comparing
00325         CellularNetwork::operator_names_list names_list;
00326         nsapi_error_t err = _network->get_operator_names(names_list);
00327         if (err == NSAPI_ERROR_OK ) {
00328             CellularNetwork::operator_names_t* op_names = names_list.get_head();
00329             bool found_match = false;
00330             while (op_names) {
00331                 if (format == 0) {
00332                     if (strcmp(op.op_long, op_names->alpha) == 0) {
00333                         found_match = true;
00334                     }
00335                 } else if (format == 1) {
00336                     if (strcmp(op.op_short, op_names->alpha) == 0) {
00337                         found_match = true;
00338                     }
00339                 }
00340 
00341                 if (found_match) {
00342                     if (strcmp(_plmn, op_names->numeric)) {
00343                         names_list.delete_all();
00344                         return true;
00345                     }
00346                     names_list.delete_all();
00347                     return false;
00348                 }
00349             }
00350         }
00351         names_list.delete_all();
00352     }
00353 
00354     return false;
00355 }
00356 
00357 nsapi_error_t CellularConnectionFSM::continue_from_state(CellularState state)
00358 {
00359     tr_info("Continue state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state),
00360             get_state_string((CellularConnectionFSM::CellularState)state));
00361     _state = state;
00362     _next_state = state;
00363     _retry_count = 0;
00364     if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) {
00365         stop();
00366         return NSAPI_ERROR_NO_MEMORY ;
00367     }
00368 
00369     return NSAPI_ERROR_OK ;
00370 }
00371 
00372 nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state)
00373 {
00374     MBED_ASSERT(_cellularDevice);
00375     _retry_count = 0;
00376     if (state < _state) {
00377         _state = state;
00378     } else {
00379         // update next state so that we don't continue from previous state
00380         _state = _next_state;
00381     }
00382     if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) {
00383         stop();
00384         return NSAPI_ERROR_NO_MEMORY ;
00385     }
00386 
00387     return NSAPI_ERROR_OK ;
00388 }
00389 
00390 void CellularConnectionFSM::enter_to_state(CellularState state)
00391 {
00392     _next_state = state;
00393     _retry_count = 0;
00394     _command_success = false;
00395 }
00396 
00397 void CellularConnectionFSM::retry_state_or_fail()
00398 {
00399     if (++_retry_count < MAX_RETRY_ARRAY_SIZE) {
00400         tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, MAX_RETRY_ARRAY_SIZE);
00401         _event_timeout = _retry_timeout_array[_retry_count];
00402     } else {
00403         report_failure(get_state_string(_state));
00404         return;
00405     }
00406 }
00407 
00408 void CellularConnectionFSM::state_init()
00409 {
00410     _event_timeout = _start_time;
00411     tr_info("Init state, waiting %d ms before POWER state)", _start_time);
00412     enter_to_state(STATE_POWER_ON);
00413 }
00414 
00415 void CellularConnectionFSM::state_power_on()
00416 {
00417     _cellularDevice->set_timeout(TIMEOUT_POWER_ON);
00418     tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON);
00419     if (power_on()) {
00420         enter_to_state(STATE_DEVICE_READY);
00421     } else {
00422         // retry to power on device
00423         retry_state_or_fail();
00424     }
00425 }
00426 
00427 bool CellularConnectionFSM::device_ready()
00428 {
00429     tr_info("Cellular device ready");
00430     if (_event_status_cb) {
00431         _event_status_cb((nsapi_event_t)CellularDeviceReady, 0);
00432     }
00433 
00434     _power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
00435 
00436     bool success = false;
00437     for (int type = 0; type < CellularNetwork::C_MAX; type++) {
00438         if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) {
00439             success = true;
00440         }
00441     }
00442     if (!success) {
00443         tr_error("Failed to set any URC's for registration");
00444         report_failure(get_state_string(_state));
00445         return false;
00446     }
00447 
00448     return true;
00449 }
00450 
00451 void CellularConnectionFSM::state_device_ready()
00452 {
00453     _cellularDevice->set_timeout(TIMEOUT_POWER_ON);
00454     if (_power->set_at_mode() == NSAPI_ERROR_OK ) {
00455         if (device_ready()) {
00456             enter_to_state(STATE_SIM_PIN);
00457         }
00458     } else {
00459         if (_retry_count == 0) {
00460             (void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
00461         }
00462         retry_state_or_fail();
00463     }
00464 }
00465 
00466 void CellularConnectionFSM::state_sim_pin()
00467 {
00468     _cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
00469     tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
00470     if (open_sim()) {
00471         if (_plmn) {
00472             enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
00473         } else {
00474             enter_to_state(STATE_REGISTERING_NETWORK);
00475         }
00476     } else {
00477         retry_state_or_fail();
00478     }
00479 }
00480 
00481 void CellularConnectionFSM::state_registering()
00482 {
00483     _cellularDevice->set_timeout(TIMEOUT_NETWORK);
00484     if (is_registered()) {
00485         // we are already registered, go to attach
00486         enter_to_state(STATE_ATTACHING_NETWORK);
00487     } else {
00488         bool auto_reg = false;
00489         nsapi_error_t err = is_automatic_registering(auto_reg);
00490         if (err == NSAPI_ERROR_OK  && !auto_reg) {
00491             // automatic registering is not on, set registration and retry
00492             _cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
00493             set_network_registration();
00494         }
00495         retry_state_or_fail();
00496     }
00497 }
00498 
00499 // only used when _plmn is set
00500 void CellularConnectionFSM::state_manual_registering_network()
00501 {
00502     _cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
00503     tr_info("state_manual_registering_network");
00504     if (!_plmn_network_found) {
00505         if (is_registered() && is_registered_to_plmn()) {
00506             _plmn_network_found = true;
00507             enter_to_state(STATE_ATTACHING_NETWORK);
00508         } else {
00509             if (!_command_success) {
00510                 _command_success = set_network_registration();
00511             }
00512             retry_state_or_fail();
00513         }
00514     }
00515 }
00516 
00517 void CellularConnectionFSM::state_attaching()
00518 {
00519     _cellularDevice->set_timeout(TIMEOUT_CONNECT);
00520     CellularNetwork::AttachStatus attach_status;
00521     if (get_attach_network(attach_status)) {
00522         if (attach_status == CellularNetwork::Attached) {
00523             enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
00524         } else {
00525             if (!_command_success) {
00526                 _command_success = set_attach_network();
00527             }
00528             retry_state_or_fail();
00529         }
00530     } else {
00531         retry_state_or_fail();
00532     }
00533 }
00534 
00535 void CellularConnectionFSM::state_activating_pdp_context()
00536 {
00537     _cellularDevice->set_timeout(TIMEOUT_CONNECT);
00538     tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT);
00539     if (_network->activate_context() == NSAPI_ERROR_OK ) {
00540         // when using modems stack connect is synchronous
00541         _next_state = STATE_CONNECTING_NETWORK;
00542     } else {
00543         retry_state_or_fail();
00544     }
00545 }
00546 
00547 void CellularConnectionFSM::state_connect_to_network()
00548 {
00549     _cellularDevice->set_timeout(TIMEOUT_CONNECT);
00550     tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT);
00551     if (_network->connect() == NSAPI_ERROR_OK ) {
00552         _cellularDevice->set_timeout(TIMEOUT_NETWORK);
00553         tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK);
00554         // when using modems stack connect is synchronous
00555         _next_state = STATE_CONNECTED;
00556     } else {
00557         retry_state_or_fail();
00558     }
00559 }
00560 
00561 void CellularConnectionFSM::state_connected()
00562 {
00563     _cellularDevice->set_timeout(TIMEOUT_NETWORK);
00564     tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK);
00565     if (_status_callback) {
00566         _status_callback(_state, _next_state);
00567     }
00568 }
00569 
00570 void CellularConnectionFSM::event()
00571 {
00572     _event_timeout = -1;
00573     switch (_state) {
00574         case STATE_INIT:
00575             state_init();
00576             break;
00577         case STATE_POWER_ON:
00578             state_power_on();
00579             break;
00580         case STATE_DEVICE_READY:
00581             state_device_ready();
00582             break;
00583         case STATE_SIM_PIN:
00584             state_sim_pin();
00585             break;
00586         case STATE_REGISTERING_NETWORK:
00587             state_registering();
00588             break;
00589         case STATE_MANUAL_REGISTERING_NETWORK:
00590             state_manual_registering_network();
00591             break;
00592         case STATE_ATTACHING_NETWORK:
00593             state_attaching();
00594             break;
00595         case STATE_ACTIVATING_PDP_CONTEXT:
00596             state_activating_pdp_context();
00597             break;
00598         case STATE_CONNECTING_NETWORK:
00599             state_connect_to_network();
00600             break;
00601         case STATE_CONNECTED:
00602             state_connected();
00603             break;
00604         default:
00605             MBED_ASSERT(0);
00606             break;
00607     }
00608 
00609     if (_next_state != _state || _event_timeout >= 0) {
00610         if (_next_state != _state) { // state exit condition
00611             tr_info("Cellular state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state),
00612                     get_state_string((CellularConnectionFSM::CellularState)_next_state));
00613             if (_status_callback) {
00614                 if (!_status_callback(_state, _next_state)) {
00615                     return;
00616                 }
00617             }
00618         } else {
00619             tr_info("Cellular event in %d seconds", _event_timeout);
00620         }
00621         _state = _next_state;
00622         if (_event_timeout == -1) {
00623             _event_timeout = 0;
00624         }
00625         _event_id = _queue.call_in(_event_timeout*1000, callback(this, &CellularConnectionFSM::event));
00626         if (!_event_id) {
00627             report_failure("Cellular event failure!");
00628             return;
00629         }
00630     }
00631 }
00632 
00633 nsapi_error_t CellularConnectionFSM::start_dispatch()
00634 {
00635     MBED_ASSERT(!_queue_thread);
00636 
00637     _queue_thread = new rtos::Thread(osPriorityNormal, 2048);
00638     if (!_queue_thread) {
00639         stop();
00640         return NSAPI_ERROR_NO_MEMORY ;
00641     }
00642     if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) {
00643         stop();
00644         return NSAPI_ERROR_NO_MEMORY ;
00645     }
00646 
00647     return NSAPI_ERROR_OK ;
00648 }
00649 
00650 void CellularConnectionFSM::set_serial(UARTSerial *serial)
00651 {
00652     _serial = serial;
00653 }
00654 
00655 void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_callback)
00656 {
00657     _status_callback = status_callback;
00658 }
00659 
00660 void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
00661 {
00662     MBED_ASSERT(_network);
00663     _event_status_cb = status_cb;
00664     if (status_cb) {
00665         _network->attach(callback(this, &CellularConnectionFSM::network_callback));
00666     } else {
00667         _network->attach(NULL);
00668     }
00669 }
00670 
00671 void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr)
00672 {
00673     tr_info("FSM: network_callback called with event: %d, intptr: %d, _state: %s", ev, ptr, get_state_string(_state));
00674     if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged &&
00675             (_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) {
00676         // expect packet data so only these states are valid
00677         if (ptr == CellularNetwork::RegisteredHomeNetwork || ptr == CellularNetwork::RegisteredRoaming) {
00678             if (_plmn) {
00679                 if (is_registered_to_plmn()) {
00680                     if (!_plmn_network_found) {
00681                         _plmn_network_found = true;
00682                         _queue.cancel(_event_id);
00683                         continue_from_state(STATE_ATTACHING_NETWORK);
00684                     }
00685                 }
00686             } else {
00687                 _queue.cancel(_event_id);
00688                 continue_from_state(STATE_ATTACHING_NETWORK);
00689             }
00690         }
00691     }
00692 
00693     if (_event_status_cb) {
00694         _event_status_cb(ev, ptr);
00695     }
00696 }
00697 
00698 void CellularConnectionFSM::ready_urc_cb()
00699 {
00700     tr_debug("Device ready URC func called");
00701     if (_state == STATE_DEVICE_READY && _power->set_at_mode() == NSAPI_ERROR_OK ) {
00702         tr_debug("State was STATE_DEVICE_READY and at mode ready, cancel state and move to next");
00703         _queue.cancel(_event_id);
00704         if (device_ready()) {
00705             continue_from_state(STATE_SIM_PIN);
00706         }
00707     }
00708 }
00709 
00710 events::EventQueue *CellularConnectionFSM::get_queue()
00711 {
00712     return &_queue;
00713 }
00714 
00715 CellularNetwork* CellularConnectionFSM::get_network()
00716 {
00717     return _network;
00718 }
00719 
00720 CellularDevice* CellularConnectionFSM::get_device()
00721 {
00722     return _cellularDevice;
00723 }
00724 
00725 CellularSIM* CellularConnectionFSM::get_sim()
00726 {
00727     return _sim;
00728 }
00729 
00730 NetworkStack *CellularConnectionFSM::get_stack()
00731 {
00732     return _cellularDevice->get_stack();
00733 }
00734 
00735 void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len)
00736 {
00737     _retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len;
00738 
00739     for (int i = 0; i < _retry_array_length; i++) {
00740         _retry_timeout_array[i] = timeout[i];
00741     }
00742 }
00743 
00744 } // namespace
00745 
00746 #endif // CELLULAR_DEVICE