takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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