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 %d=>%d", state, next_state);
00041     if (_target_state == state) {
00042         if (state == CellularConnectionFSM::STATE_CONNECTED) {
00043             _is_connected = true;
00044         } else {
00045             _is_connected = false;
00046         }
00047         tr_info("Target state reached: %d", _target_state);
00048         MBED_ASSERT(_cellularSemaphore.release() == osOK);
00049         return false;
00050     } else {
00051         _is_connected = false;
00052     }
00053     return true;
00054 }
00055 
00056 EasyCellularConnection::EasyCellularConnection(bool debug) :
00057         _is_connected(false), _is_initialized(false), _target_state(CellularConnectionFSM::STATE_POWER_ON), _cellularSerial(
00058                 MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(), _credentials_err(
00059                 NSAPI_ERROR_OK )
00060 {
00061     tr_info("EasyCellularConnection()");
00062 #if USE_APN_LOOKUP
00063     _credentials_set = false;
00064 #endif // #if USE_APN_LOOKUP
00065     modem_debug_on(debug);
00066 }
00067 
00068 EasyCellularConnection::~EasyCellularConnection()
00069 {
00070     _cellularConnectionFSM.stop();
00071 }
00072 
00073 nsapi_error_t EasyCellularConnection::init()
00074 {
00075     nsapi_error_t err = NSAPI_ERROR_OK ;
00076     if (!_is_initialized) {
00077 #if defined (MDMRTS) && defined (MDMCTS)
00078         _cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
00079 #endif
00080         _cellularConnectionFSM.set_serial(&_cellularSerial);
00081         _cellularConnectionFSM.set_callback(callback(this, &EasyCellularConnection::cellular_status));
00082 
00083         err = _cellularConnectionFSM.init();
00084 
00085         if (err == NSAPI_ERROR_OK ) {
00086             err = _cellularConnectionFSM.start_dispatch();
00087         }
00088         _is_initialized = true;
00089     }
00090 
00091     return err;
00092 }
00093 
00094 void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd)
00095 {
00096     if (apn && strlen(apn) > 0) {
00097         _credentials_err = init();
00098 
00099         if (_credentials_err) {
00100             return;
00101         }
00102         CellularNetwork * network = _cellularConnectionFSM.get_network();
00103         if (network) {
00104             _credentials_err = network->set_credentials(apn, uname, pwd);
00105 #if USE_APN_LOOKUP
00106             if (_credentials_err == NSAPI_ERROR_OK ) {
00107                 _credentials_set = true;
00108             }
00109 #endif // #if USE_APN_LOOKUP
00110         } else {
00111             tr_error("NO Network...");
00112         }
00113     }
00114 }
00115 
00116 void EasyCellularConnection::set_sim_pin(const char *sim_pin)
00117 {
00118     if (sim_pin) {
00119         _cellularConnectionFSM.set_sim_pin(sim_pin);
00120     }
00121 }
00122 
00123 nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
00124 {
00125     if (_is_connected) {
00126         return NSAPI_ERROR_IS_CONNECTED ;
00127     }
00128 
00129     set_credentials(apn, uname, pwd);
00130     if (_credentials_err) {
00131         return _credentials_err;
00132     }
00133 
00134     if (sim_pin) {
00135         _cellularConnectionFSM.set_sim_pin(sim_pin);
00136     }
00137 
00138     return connect();
00139 }
00140 
00141 nsapi_error_t EasyCellularConnection::check_connect()
00142 {
00143     if (_is_connected) {
00144         return NSAPI_ERROR_IS_CONNECTED ;
00145     }
00146 
00147     // there was an error while setting credentials but it's a void function so check error here...
00148     if (_credentials_err) {
00149         return _credentials_err;
00150     }
00151 
00152     nsapi_error_t err = init();
00153     if (err) {
00154         return err;
00155     }
00156 
00157     return NSAPI_ERROR_OK ;
00158 }
00159 
00160 nsapi_error_t EasyCellularConnection::connect()
00161 {
00162     nsapi_error_t err = check_connect();
00163     if (err) {
00164         return err;
00165     }
00166 #if USE_APN_LOOKUP
00167     if (!_credentials_set) {
00168         _target_state = CellularConnectionFSM::STATE_SIM_PIN;
00169         err = _cellularConnectionFSM.continue_to_state(_target_state);
00170         if (err == NSAPI_ERROR_OK ) {
00171             int sim_wait = _cellularSemaphore.wait(60*1000); // reserve 60 seconds to access to SIM
00172             if (sim_wait != 1) {
00173                 tr_error("NO SIM ACCESS");
00174                 err = NSAPI_ERROR_NO_CONNECTION ;
00175             } else {
00176                 char imsi[MAX_IMSI_LENGTH+1];
00177                 wait(1); // need to wait to access SIM in some modems
00178                 err = _cellularConnectionFSM.get_sim()->get_imsi(imsi);
00179                 if (err == NSAPI_ERROR_OK ) {
00180                     const char *apn_config = apnconfig(imsi);
00181                     if (apn_config) {
00182                         const char* apn = _APN_GET(apn_config);
00183                         const char* uname = _APN_GET(apn_config);
00184                         const char* pwd = _APN_GET(apn_config);
00185                         tr_info("Looked up APN %s", apn);
00186                         err = _cellularConnectionFSM.get_network()->set_credentials(apn, uname, pwd);
00187                     }
00188                 }
00189             }
00190         }
00191         if (err) {
00192             tr_info("APN lookup failed");
00193             return err;
00194         }
00195     }
00196 #endif // USE_APN_LOOKUP
00197 
00198     _target_state = CellularConnectionFSM::STATE_CONNECTED;
00199     err = _cellularConnectionFSM.continue_to_state(_target_state);
00200     if (err == NSAPI_ERROR_OK ) {
00201         int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
00202         if (ret_wait != 1) {
00203             tr_info("No cellular connection");
00204             err = NSAPI_ERROR_NO_CONNECTION ;
00205         }
00206     }
00207 
00208     return err;
00209 }
00210 
00211 nsapi_error_t EasyCellularConnection::disconnect()
00212 {
00213     _credentials_err = NSAPI_ERROR_OK ;
00214     _is_connected = false;
00215 #if USE_APN_LOOKUP
00216     _credentials_set = false;
00217 #endif // #if USE_APN_LOOKUP
00218     if (!_cellularConnectionFSM.get_network()) {
00219         return NSAPI_ERROR_NO_CONNECTION ;
00220     }
00221     return _cellularConnectionFSM.get_network()->disconnect();
00222 }
00223 
00224 bool EasyCellularConnection::is_connected()
00225 {
00226     return _is_connected;
00227 }
00228 
00229 const char *EasyCellularConnection::get_ip_address()
00230 {
00231     CellularNetwork *network = _cellularConnectionFSM.get_network();
00232     if (!network) {
00233         return NULL;
00234     }
00235     return _cellularConnectionFSM.get_network()->get_ip_address();
00236 }
00237 
00238 const char *EasyCellularConnection::get_netmask()
00239 {
00240     CellularNetwork *network = _cellularConnectionFSM.get_network();
00241     if (!network) {
00242         return NULL;
00243     }
00244 
00245     return network->get_netmask();
00246 }
00247 
00248 const char *EasyCellularConnection::get_gateway()
00249 {
00250     CellularNetwork *network = _cellularConnectionFSM.get_network();
00251     if (!network) {
00252         return NULL;
00253     }
00254 
00255     return network->get_gateway();
00256 }
00257 
00258 void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
00259 {
00260     CellularNetwork *network = _cellularConnectionFSM.get_network();
00261     if (network) {
00262         network->attach(status_cb);
00263     }
00264 }
00265 
00266 void EasyCellularConnection::modem_debug_on(bool on)
00267 {
00268     CellularDevice *dev = _cellularConnectionFSM.get_device();
00269     if (dev) {
00270         dev->modem_debug_on(on);
00271     }
00272 }
00273 
00274 NetworkStack *EasyCellularConnection::get_stack()
00275 {
00276     return _cellularConnectionFSM.get_stack();
00277 }
00278 
00279 } // namespace
00280 
00281 #endif // CELLULAR_DEVICE