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