Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EasyCellularConnection.cpp Source File

EasyCellularConnection.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 "CellularTargets.h"
00019 #ifdef CELLULAR_DEVICE
00020 
00021 #if NSAPI_PPP_AVAILABLE
00022 #include "nsapi_ppp.h"
00023 #endif
00024 
00025 #include "CellularConnectionFSM.h"
00026 #include "CellularUtil.h"
00027 
00028 #include "EasyCellularConnection.h"
00029 #include "CellularLog.h"
00030 #include "mbed_wait_api.h"
00031 
00032 #if USE_APN_LOOKUP
00033 #include "APN_db.h"
00034 #endif //USE_APN_LOOKUP
00035 
00036 namespace mbed {
00037 
00038 bool EasyCellularConnection::cellular_status(int state, int next_state)
00039 {
00040     tr_info("cellular_status: %s ==> %s", _cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)state),
00041             _cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)next_state));
00042 
00043     if (_target_state == state) {
00044         tr_info("Target state reached: %s", _cellularConnectionFSM->get_state_string(_target_state));
00045         (void)_cellularSemaphore.release();
00046         return false; // return false -> state machine is halted
00047     }
00048     return true;
00049 }
00050 
00051 void EasyCellularConnection::network_callback(nsapi_event_t ev, intptr_t ptr)
00052 {
00053     if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE ) {
00054         if (ptr == NSAPI_STATUS_GLOBAL_UP ) {
00055             _is_connected = true;
00056         } else {
00057             _is_connected = false;
00058         }
00059     }
00060     if (_status_cb) {
00061         _status_cb(ev, ptr);
00062     }
00063 }
00064 
00065 EasyCellularConnection::EasyCellularConnection(bool debug) :
00066         _is_connected(false), _is_initialized(false), _target_state(CellularConnectionFSM::STATE_POWER_ON), _cellularSerial(
00067                 MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(0), _credentials_err(
00068                 NSAPI_ERROR_OK ), _status_cb(0)
00069 {
00070     tr_info("EasyCellularConnection()");
00071 #if USE_APN_LOOKUP
00072     _credentials_set = false;
00073 #endif // #if USE_APN_LOOKUP
00074     modem_debug_on(debug);
00075 }
00076 
00077 EasyCellularConnection::~EasyCellularConnection()
00078 {
00079     if (_cellularConnectionFSM) {
00080         _cellularConnectionFSM->set_callback(NULL);
00081         _cellularConnectionFSM->attach(NULL);
00082         delete _cellularConnectionFSM;
00083     }
00084 }
00085 
00086 nsapi_error_t EasyCellularConnection::init()
00087 {
00088     nsapi_error_t err = NSAPI_ERROR_OK ;
00089     if (!_is_initialized) {
00090 #if defined (MDMRTS) && defined (MDMCTS)
00091         _cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
00092 #endif
00093         _cellularConnectionFSM = new CellularConnectionFSM();
00094         _cellularConnectionFSM->set_serial(&_cellularSerial);
00095         _cellularConnectionFSM->set_callback(callback(this, &EasyCellularConnection::cellular_status));
00096 
00097         err = _cellularConnectionFSM->init();
00098 
00099         if (err == NSAPI_ERROR_OK ) {
00100             err = _cellularConnectionFSM->start_dispatch();
00101             _cellularConnectionFSM->attach(callback(this, &EasyCellularConnection::network_callback));
00102         }
00103         _is_initialized = true;
00104     }
00105 
00106     return err;
00107 }
00108 
00109 void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd)
00110 {
00111     if (apn && strlen(apn) > 0) {
00112         _credentials_err = init();
00113 
00114         if (_credentials_err) {
00115             return;
00116         }
00117         CellularNetwork *network = _cellularConnectionFSM->get_network();
00118         if (network) {
00119             _credentials_err = network->set_credentials(apn, uname, pwd);
00120 #if USE_APN_LOOKUP
00121             if (_credentials_err == NSAPI_ERROR_OK ) {
00122                 _credentials_set = true;
00123             }
00124 #endif // #if USE_APN_LOOKUP
00125         } else {
00126             //if get_network() returns NULL it means there was not enough memory for
00127             //an AT_CellularNetwork element during CellularConnectionFSM initialization
00128             tr_error("There was not enough memory during CellularConnectionFSM initialization");
00129         }
00130     }
00131 }
00132 
00133 void EasyCellularConnection::set_sim_pin(const char *sim_pin)
00134 {
00135     if (sim_pin && strlen(sim_pin) > 0) {
00136         if (!_cellularConnectionFSM) {
00137             _credentials_err = init();
00138 
00139             if (_credentials_err) {
00140                 return;
00141             }
00142         }
00143         _cellularConnectionFSM->set_sim_pin(sim_pin);
00144     }
00145 }
00146 
00147 nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
00148 {
00149     if (_is_connected) {
00150         return NSAPI_ERROR_IS_CONNECTED ;
00151     }
00152 
00153     set_credentials(apn, uname, pwd);
00154     if (_credentials_err) {
00155         return _credentials_err;
00156     }
00157 
00158     if (sim_pin) {
00159         _cellularConnectionFSM->set_sim_pin(sim_pin);
00160     }
00161 
00162     return connect();
00163 }
00164 
00165 nsapi_error_t EasyCellularConnection::check_connect()
00166 {
00167     if (_is_connected) {
00168         return NSAPI_ERROR_IS_CONNECTED ;
00169     }
00170 
00171     // there was an error while setting credentials but it's a void function so check error here...
00172     if (_credentials_err) {
00173         return _credentials_err;
00174     }
00175 
00176     nsapi_error_t err = init();
00177     if (err) {
00178         return err;
00179     }
00180 
00181     return NSAPI_ERROR_OK ;
00182 }
00183 
00184 nsapi_error_t EasyCellularConnection::connect()
00185 {
00186     nsapi_error_t err = check_connect();
00187     if (err) {
00188         return err;
00189     }
00190 #if USE_APN_LOOKUP
00191     if (!_credentials_set) {
00192         _target_state = CellularConnectionFSM::STATE_SIM_PIN;
00193         err = _cellularConnectionFSM->continue_to_state(_target_state);
00194         if (err == NSAPI_ERROR_OK ) {
00195             int sim_wait = _cellularSemaphore.wait(60 * 1000); // reserve 60 seconds to access to SIM
00196             if (sim_wait != 1) {
00197                 tr_error("NO SIM ACCESS");
00198                 err = NSAPI_ERROR_NO_CONNECTION ;
00199             } else {
00200                 char imsi[MAX_IMSI_LENGTH + 1];
00201                 wait(1); // need to wait to access SIM in some modems
00202                 err = _cellularConnectionFSM->get_sim()->get_imsi(imsi);
00203                 if (err == NSAPI_ERROR_OK ) {
00204                     const char *apn_config = apnconfig(imsi);
00205                     if (apn_config) {
00206                         const char* apn = _APN_GET(apn_config);
00207                         const char* uname = _APN_GET(apn_config);
00208                         const char* pwd = _APN_GET(apn_config);
00209                         tr_info("Looked up APN %s", apn);
00210                         err = _cellularConnectionFSM->get_network()->set_credentials(apn, uname, pwd);
00211                     }
00212                 }
00213             }
00214         }
00215         if (err) {
00216             tr_error("APN lookup failed");
00217             return err;
00218         }
00219     }
00220 #endif // USE_APN_LOOKUP
00221 
00222     _target_state = CellularConnectionFSM::STATE_CONNECTED;
00223     err = _cellularConnectionFSM->continue_to_state(_target_state);
00224     if (err == NSAPI_ERROR_OK ) {
00225         int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
00226         if (ret_wait != 1) {
00227             tr_info("No cellular connection");
00228             err = NSAPI_ERROR_NO_CONNECTION ;
00229         }
00230     }
00231 
00232     return err;
00233 }
00234 
00235 nsapi_error_t EasyCellularConnection::disconnect()
00236 {
00237     _credentials_err = NSAPI_ERROR_OK ;
00238     _is_connected = false;
00239     _is_initialized = false;
00240 #if USE_APN_LOOKUP
00241     _credentials_set = false;
00242 #endif // #if USE_APN_LOOKUP
00243 
00244     nsapi_error_t err = NSAPI_ERROR_OK ;
00245     if (_cellularConnectionFSM && _cellularConnectionFSM->get_network()) {
00246         err = _cellularConnectionFSM->get_network()->disconnect();
00247     }
00248 
00249     if (err == NSAPI_ERROR_OK ) {
00250         delete _cellularConnectionFSM;
00251         _cellularConnectionFSM = NULL;
00252     }
00253 
00254     return err;
00255 }
00256 
00257 bool EasyCellularConnection::is_connected()
00258 {
00259     return _is_connected;
00260 }
00261 
00262 const char *EasyCellularConnection::get_ip_address()
00263 {
00264     if (_cellularConnectionFSM) {
00265         CellularNetwork *network = _cellularConnectionFSM->get_network();
00266         if (!network) {
00267             return NULL;
00268         }
00269         return _cellularConnectionFSM->get_network()->get_ip_address();
00270     } else {
00271         return NULL;
00272     }
00273 }
00274 
00275 const char *EasyCellularConnection::get_netmask()
00276 {
00277     if (_cellularConnectionFSM) {
00278         CellularNetwork *network = _cellularConnectionFSM->get_network();
00279         if (!network) {
00280             return NULL;
00281         }
00282         return network->get_netmask();
00283     } else {
00284         return NULL;
00285     }
00286 }
00287 
00288 const char *EasyCellularConnection::get_gateway()
00289 {
00290     if (_cellularConnectionFSM) {
00291         CellularNetwork *network = _cellularConnectionFSM->get_network();
00292         if (!network) {
00293             return NULL;
00294         }
00295         return network->get_gateway();
00296     } else {
00297         return NULL;
00298     }
00299 }
00300 
00301 void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
00302 {
00303     _status_cb = status_cb;
00304 }
00305 
00306 void EasyCellularConnection::modem_debug_on(bool on)
00307 {
00308     if (_cellularConnectionFSM) {
00309         CellularDevice *dev = _cellularConnectionFSM->get_device();
00310         if (dev) {
00311             dev->modem_debug_on(on);
00312         }
00313     }
00314 }
00315 
00316 void EasyCellularConnection::set_plmn(const char *plmn)
00317 {
00318     if (plmn && strlen(plmn) > 0) {
00319         if (!_cellularConnectionFSM) {
00320             _credentials_err = init();
00321 
00322             if (_credentials_err) {
00323                 return;
00324             }
00325         }
00326         _cellularConnectionFSM->set_plmn(plmn);
00327     }
00328 }
00329 
00330 NetworkStack *EasyCellularConnection::get_stack()
00331 {
00332     if (_cellularConnectionFSM) {
00333         return _cellularConnectionFSM->get_stack();
00334     } else {
00335         return NULL;
00336     }
00337 }
00338 
00339 } // namespace
00340 
00341 #endif // CELLULAR_DEVICE