Nicolas Borla / Mbed OS BBR_1Ebene
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         MBED_ASSERT(_cellularSemaphore.release() == osOK);
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(), _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     _cellularConnectionFSM.set_callback(NULL);
00080     _cellularConnectionFSM.attach(NULL);
00081 }
00082 
00083 nsapi_error_t EasyCellularConnection::init()
00084 {
00085     nsapi_error_t err = NSAPI_ERROR_OK ;
00086     if (!_is_initialized) {
00087 #if defined (MDMRTS) && defined (MDMCTS)
00088         _cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
00089 #endif
00090         _cellularConnectionFSM.set_serial(&_cellularSerial);
00091         _cellularConnectionFSM.set_callback(callback(this, &EasyCellularConnection::cellular_status));
00092 
00093         err = _cellularConnectionFSM.init();
00094 
00095         if (err == NSAPI_ERROR_OK ) {
00096             err = _cellularConnectionFSM.start_dispatch();
00097             _cellularConnectionFSM.attach(callback(this, &EasyCellularConnection::network_callback));
00098         }
00099         _is_initialized = true;
00100     }
00101 
00102     return err;
00103 }
00104 
00105 void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd)
00106 {
00107     if (apn && strlen(apn) > 0) {
00108         _credentials_err = init();
00109 
00110         if (_credentials_err) {
00111             return;
00112         }
00113         CellularNetwork * network = _cellularConnectionFSM.get_network();
00114         if (network) {
00115             _credentials_err = network->set_credentials(apn, uname, pwd);
00116 #if USE_APN_LOOKUP
00117             if (_credentials_err == NSAPI_ERROR_OK ) {
00118                 _credentials_set = true;
00119             }
00120 #endif // #if USE_APN_LOOKUP
00121         } else {
00122             //if get_network() returns NULL it means there was not enough memory for
00123             //an AT_CellularNetwork element during CellularConnectionFSM initialization
00124             tr_error("There was not enough memory during CellularConnectionFSM initialization");
00125         }
00126     }
00127 }
00128 
00129 void EasyCellularConnection::set_sim_pin(const char *sim_pin)
00130 {
00131     if (sim_pin) {
00132         _cellularConnectionFSM.set_sim_pin(sim_pin);
00133     }
00134 }
00135 
00136 nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
00137 {
00138     if (_is_connected) {
00139         return NSAPI_ERROR_IS_CONNECTED ;
00140     }
00141 
00142     set_credentials(apn, uname, pwd);
00143     if (_credentials_err) {
00144         return _credentials_err;
00145     }
00146 
00147     if (sim_pin) {
00148         _cellularConnectionFSM.set_sim_pin(sim_pin);
00149     }
00150 
00151     return connect();
00152 }
00153 
00154 nsapi_error_t EasyCellularConnection::check_connect()
00155 {
00156     if (_is_connected) {
00157         return NSAPI_ERROR_IS_CONNECTED ;
00158     }
00159 
00160     // there was an error while setting credentials but it's a void function so check error here...
00161     if (_credentials_err) {
00162         return _credentials_err;
00163     }
00164 
00165     nsapi_error_t err = init();
00166     if (err) {
00167         return err;
00168     }
00169 
00170     return NSAPI_ERROR_OK ;
00171 }
00172 
00173 nsapi_error_t EasyCellularConnection::connect()
00174 {
00175     nsapi_error_t err = check_connect();
00176     if (err) {
00177         return err;
00178     }
00179 #if USE_APN_LOOKUP
00180     if (!_credentials_set) {
00181         _target_state = CellularConnectionFSM::STATE_SIM_PIN;
00182         err = _cellularConnectionFSM.continue_to_state(_target_state);
00183         if (err == NSAPI_ERROR_OK ) {
00184             int sim_wait = _cellularSemaphore.wait(60*1000); // reserve 60 seconds to access to SIM
00185             if (sim_wait != 1) {
00186                 tr_error("NO SIM ACCESS");
00187                 err = NSAPI_ERROR_NO_CONNECTION ;
00188             } else {
00189                 char imsi[MAX_IMSI_LENGTH+1];
00190                 wait(1); // need to wait to access SIM in some modems
00191                 err = _cellularConnectionFSM.get_sim()->get_imsi(imsi);
00192                 if (err == NSAPI_ERROR_OK ) {
00193                     const char *apn_config = apnconfig(imsi);
00194                     if (apn_config) {
00195                         const char* apn = _APN_GET(apn_config);
00196                         const char* uname = _APN_GET(apn_config);
00197                         const char* pwd = _APN_GET(apn_config);
00198                         tr_info("Looked up APN %s", apn);
00199                         err = _cellularConnectionFSM.get_network()->set_credentials(apn, uname, pwd);
00200                     }
00201                 }
00202             }
00203         }
00204         if (err) {
00205             tr_error("APN lookup failed");
00206             return err;
00207         }
00208     }
00209 #endif // USE_APN_LOOKUP
00210 
00211     _target_state = CellularConnectionFSM::STATE_CONNECTED;
00212     err = _cellularConnectionFSM.continue_to_state(_target_state);
00213     if (err == NSAPI_ERROR_OK ) {
00214         int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
00215         if (ret_wait != 1) {
00216             tr_info("No cellular connection");
00217             err = NSAPI_ERROR_NO_CONNECTION ;
00218         }
00219     }
00220 
00221     return err;
00222 }
00223 
00224 nsapi_error_t EasyCellularConnection::disconnect()
00225 {
00226     _credentials_err = NSAPI_ERROR_OK ;
00227     _is_connected = false;
00228     _is_initialized = false;
00229 #if USE_APN_LOOKUP
00230     _credentials_set = false;
00231 #endif // #if USE_APN_LOOKUP
00232 
00233     nsapi_error_t err = NSAPI_ERROR_OK ;
00234     if (_cellularConnectionFSM.get_network()) {
00235         err = _cellularConnectionFSM.get_network()->disconnect();
00236     }
00237 
00238     _cellularConnectionFSM.stop();
00239 
00240     return err;
00241 }
00242 
00243 bool EasyCellularConnection::is_connected()
00244 {
00245     return _is_connected;
00246 }
00247 
00248 const char *EasyCellularConnection::get_ip_address()
00249 {
00250     CellularNetwork *network = _cellularConnectionFSM.get_network();
00251     if (!network) {
00252         return NULL;
00253     }
00254     return _cellularConnectionFSM.get_network()->get_ip_address();
00255 }
00256 
00257 const char *EasyCellularConnection::get_netmask()
00258 {
00259     CellularNetwork *network = _cellularConnectionFSM.get_network();
00260     if (!network) {
00261         return NULL;
00262     }
00263 
00264     return network->get_netmask();
00265 }
00266 
00267 const char *EasyCellularConnection::get_gateway()
00268 {
00269     CellularNetwork *network = _cellularConnectionFSM.get_network();
00270     if (!network) {
00271         return NULL;
00272     }
00273 
00274     return network->get_gateway();
00275 }
00276 
00277 void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
00278 {
00279     _status_cb = status_cb;
00280 }
00281 
00282 void EasyCellularConnection::modem_debug_on(bool on)
00283 {
00284     CellularDevice *dev = _cellularConnectionFSM.get_device();
00285     if (dev) {
00286         dev->modem_debug_on(on);
00287     }
00288 }
00289 
00290 void EasyCellularConnection::set_plmn(const char* plmn)
00291 {
00292     _cellularConnectionFSM.set_plmn(plmn);
00293 }
00294 
00295 NetworkStack *EasyCellularConnection::get_stack()
00296 {
00297     return _cellularConnectionFSM.get_stack();
00298 }
00299 
00300 } // namespace
00301 
00302 #endif // CELLULAR_DEVICE