Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
AT_CellularNetwork.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 <stdlib.h> 00019 #include "AT_CellularNetwork.h" 00020 #include "nsapi_ppp.h" 00021 #include "CellularUtil.h" 00022 #include "CellularLog.h" 00023 #include "CellularCommon.h" 00024 00025 using namespace std; 00026 using namespace mbed_cellular_util; 00027 using namespace mbed; 00028 00029 struct at_reg_t { 00030 const CellularNetwork::RegistrationType type; 00031 const char *const cmd; 00032 const char *const urc_prefix; 00033 }; 00034 00035 static const at_reg_t at_reg[] = { 00036 { CellularNetwork::C_EREG, "AT+CEREG", "+CEREG:"}, 00037 { CellularNetwork::C_GREG, "AT+CGREG", "+CGREG:"}, 00038 { CellularNetwork::C_REG, "AT+CREG", "+CREG:"} 00039 }; 00040 00041 AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler), 00042 _stack(NULL), _apn(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK), 00043 _ip_stack_type(DEFAULT_STACK), _cid(-1), _connection_status_cb(NULL), _op_act(RAT_UNKNOWN), 00044 _authentication_type(CHAP), _cell_id(-1), _connect_status(NSAPI_STATUS_DISCONNECTED ), _new_context_set(false), 00045 _is_context_active(false), _reg_status(NotRegistered), _current_act(RAT_UNKNOWN) 00046 { 00047 } 00048 00049 AT_CellularNetwork::~AT_CellularNetwork() 00050 { 00051 #if NSAPI_PPP_AVAILABLE 00052 (void)disconnect(); 00053 #else 00054 delete _stack; 00055 #endif // NSAPI_PPP_AVAILABLE 00056 00057 for (int type = 0; type < CellularNetwork::C_MAX; type++) { 00058 if (has_registration((RegistrationType)type) != RegistrationModeDisable) { 00059 _at.remove_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]); 00060 } 00061 } 00062 00063 _at.remove_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier)); 00064 _at.remove_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev)); 00065 free_credentials(); 00066 } 00067 00068 nsapi_error_t AT_CellularNetwork::init() 00069 { 00070 _urc_funcs[C_EREG] = callback(this, &AT_CellularNetwork::urc_cereg); 00071 _urc_funcs[C_GREG] = callback(this, &AT_CellularNetwork::urc_cgreg); 00072 _urc_funcs[C_REG] = callback(this, &AT_CellularNetwork::urc_creg); 00073 00074 for (int type = 0; type < CellularNetwork::C_MAX; type++) { 00075 if (has_registration((RegistrationType)type) != RegistrationModeDisable) { 00076 if (_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]) != NSAPI_ERROR_OK ) { 00077 return NSAPI_ERROR_NO_MEMORY ; 00078 } 00079 } 00080 } 00081 00082 return _at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier)); 00083 } 00084 00085 void AT_CellularNetwork::free_credentials() 00086 { 00087 if (_uname) { 00088 free(_uname); 00089 _uname = NULL; 00090 } 00091 00092 if (_pwd) { 00093 free(_pwd); 00094 _pwd = NULL; 00095 } 00096 00097 if (_apn) { 00098 free(_apn); 00099 _apn = NULL; 00100 } 00101 } 00102 00103 void AT_CellularNetwork::urc_no_carrier() 00104 { 00105 tr_error("Data call failed: no carrier"); 00106 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00107 } 00108 00109 void AT_CellularNetwork::urc_cgev() 00110 { 00111 char buf[13]; 00112 if (_at.read_string(buf, 13) < 8) { // smallest string length we wan't to compare is 8 00113 return; 00114 } 00115 tr_debug("urc_cgev: %s", buf); 00116 00117 bool call_cb = false; 00118 // NOTE! If in future there will be 2 or more active contexts we might wan't to read context id also but not for now. 00119 00120 if (memcmp(buf, "NW DETACH", 9) == 0) { // The network has forced a PS detach 00121 call_cb = true; 00122 } else if (memcmp(buf, "ME DETACH", 9) == 0) {// The mobile termination has forced a PS detach. 00123 call_cb = true; 00124 } else if (memcmp(buf, "NW DEACT", 8) == 0) {// The network has forced a context deactivation 00125 call_cb = true; 00126 } else if (memcmp(buf, "ME DEACT", 8) == 0) {// The mobile termination has forced a context deactivation 00127 call_cb = true; 00128 } else if (memcmp(buf, "NW PDN DEACT", 12) == 0) {// The network has deactivated a context 00129 call_cb = true; 00130 } else if (memcmp(buf, "ME PDN DEACT", 12) == 0) {// The mobile termination has deactivated a context. 00131 call_cb = true; 00132 } 00133 00134 if (call_cb) { 00135 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00136 } 00137 } 00138 00139 void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type) 00140 { 00141 RegistrationStatus reg_status = NotRegistered; 00142 int lac = -1, cell_id = -1, act = -1; 00143 00144 read_reg_params(type, reg_status, lac, cell_id, act); 00145 00146 #if MBED_CONF_MBED_TRACE_ENABLE 00147 switch (reg_status) { 00148 case NotRegistered: 00149 tr_warn("not registered"); 00150 break; 00151 case RegistrationDenied: 00152 tr_warn("registration denied"); 00153 break; 00154 case Unknown: 00155 tr_warn("registration status unknown"); 00156 break; 00157 default: 00158 break; 00159 } 00160 #endif 00161 00162 if (_at.get_last_error() == NSAPI_ERROR_OK && _connection_status_cb) { 00163 tr_debug("stat: %d, lac: %d, cellID: %d, act: %d", reg_status, lac, cell_id, act); 00164 if (act != -1 && (RadioAccessTechnology)act != _current_act) { 00165 _current_act = (RadioAccessTechnology)act; 00166 _connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, _current_act); 00167 } 00168 if (reg_status != _reg_status) { 00169 _reg_status = reg_status; 00170 _connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, _reg_status); 00171 } 00172 if (cell_id != -1 && cell_id != _cell_id) { 00173 _cell_id = cell_id; 00174 _connection_status_cb((nsapi_event_t)CellularCellIDChanged, _cell_id); 00175 } 00176 } 00177 } 00178 00179 void AT_CellularNetwork::urc_creg() 00180 { 00181 tr_debug("urc_creg"); 00182 read_reg_params_and_compare(C_REG); 00183 } 00184 00185 void AT_CellularNetwork::urc_cereg() 00186 { 00187 tr_debug("urc_cereg"); 00188 read_reg_params_and_compare(C_EREG); 00189 } 00190 00191 void AT_CellularNetwork::urc_cgreg() 00192 { 00193 tr_debug("urc_cgreg"); 00194 read_reg_params_and_compare(C_GREG); 00195 } 00196 00197 nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, 00198 const char *username, const char *password) 00199 { 00200 free_credentials(); 00201 00202 size_t len; 00203 if (apn && (len = strlen(apn)) > 0) { 00204 _apn = (char *)malloc(len * sizeof(char) + 1); 00205 if (_apn) { 00206 memcpy(_apn, apn, len + 1); 00207 } else { 00208 return NSAPI_ERROR_NO_MEMORY ; 00209 } 00210 } 00211 00212 if (username && (len = strlen(username)) > 0) { 00213 if (!is_supported(AT_CGAUTH)) { // APN authentication is needed with username/password 00214 return NSAPI_ERROR_UNSUPPORTED ; 00215 } 00216 _uname = (char *)malloc(len * sizeof(char) + 1); 00217 if (_uname) { 00218 memcpy(_uname, username, len + 1); 00219 } else { 00220 return NSAPI_ERROR_NO_MEMORY ; 00221 } 00222 } 00223 00224 if (password && (len = strlen(password)) > 0) { 00225 _pwd = (char *)malloc(len * sizeof(char) + 1); 00226 if (_pwd) { 00227 memcpy(_pwd, password, len + 1); 00228 } else { 00229 return NSAPI_ERROR_NO_MEMORY ; 00230 } 00231 } 00232 00233 return NSAPI_ERROR_OK ; 00234 } 00235 00236 nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, 00237 AuthenticationType type, const char *username, const char *password) 00238 { 00239 nsapi_error_t err = set_credentials(apn, username, password); 00240 if (err) { 00241 return err; 00242 } 00243 00244 _authentication_type = type; 00245 00246 return NSAPI_ERROR_OK ; 00247 } 00248 00249 nsapi_error_t AT_CellularNetwork::connect(const char *apn, 00250 const char *username, const char *password) 00251 { 00252 nsapi_error_t err = set_credentials(apn, username, password); 00253 if (err) { 00254 return err; 00255 } 00256 00257 return connect(); 00258 } 00259 00260 nsapi_error_t AT_CellularNetwork::delete_current_context() 00261 { 00262 tr_info("Delete context %d", _cid); 00263 _at.clear_error(); 00264 _at.cmd_start("AT+CGDCONT="); 00265 _at.write_int(_cid); 00266 _at.cmd_stop(); 00267 _at.resp_start(); 00268 _at.resp_stop(); 00269 00270 if (_at.get_last_error() == NSAPI_ERROR_OK ) { 00271 _cid = -1; 00272 _new_context_set = false; 00273 } 00274 00275 return _at.get_last_error(); 00276 } 00277 00278 nsapi_error_t AT_CellularNetwork::activate_context() 00279 { 00280 _at.lock(); 00281 00282 nsapi_error_t err = NSAPI_ERROR_OK ; 00283 00284 // try to find or create context with suitable stack 00285 if (!get_context()) { 00286 err = NSAPI_ERROR_NO_CONNECTION ; 00287 } 00288 00289 if (err != NSAPI_ERROR_OK ) { 00290 _at.unlock(); 00291 tr_error("Failed to activate network context! (%d)", err); 00292 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00293 00294 return err; 00295 } 00296 00297 // do check for stack to validate that we have support for stack 00298 _stack = get_stack(); 00299 if (!_stack) { 00300 tr_error("No cellular stack!"); 00301 return NSAPI_ERROR_UNSUPPORTED ; 00302 } 00303 00304 _is_context_active = false; 00305 _at.cmd_start("AT+CGACT?"); 00306 _at.cmd_stop(); 00307 _at.resp_start("+CGACT:"); 00308 while (_at.info_resp()) { 00309 int context_id = _at.read_int(); 00310 int context_activation_state = _at.read_int(); 00311 if (context_id == _cid && context_activation_state == 1) { 00312 _is_context_active = true; 00313 } 00314 } 00315 _at.resp_stop(); 00316 00317 if (!_is_context_active) { 00318 // authenticate before activating or modifying context 00319 nsapi_error_t err = do_user_authentication(); 00320 if (err != NSAPI_ERROR_OK ) { 00321 tr_error("Cellular authentication failed!"); 00322 return err; 00323 } 00324 00325 tr_info("Activate PDP context %d", _cid); 00326 _at.cmd_start("AT+CGACT=1,"); 00327 _at.write_int(_cid); 00328 _at.cmd_stop(); 00329 _at.resp_start(); 00330 _at.resp_stop(); 00331 } 00332 00333 err = (_at.get_last_error() == NSAPI_ERROR_OK ) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION ; 00334 00335 // If new PDP context was created and failed to activate, delete it 00336 if (err != NSAPI_ERROR_OK && _new_context_set) { 00337 delete_current_context(); 00338 } else if (err == NSAPI_ERROR_OK ) { 00339 _is_context_active = true; 00340 } 00341 00342 _at.unlock(); 00343 00344 return err; 00345 } 00346 00347 nsapi_error_t AT_CellularNetwork::connect() 00348 { 00349 call_network_cb(NSAPI_STATUS_CONNECTING ); 00350 00351 nsapi_error_t err = NSAPI_ERROR_OK ; 00352 if (!_is_context_active) { 00353 err = activate_context(); 00354 } 00355 if (err) { 00356 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00357 return err; 00358 } 00359 00360 #if NSAPI_PPP_AVAILABLE 00361 _at.lock(); 00362 err = open_data_channel(); 00363 _at.unlock(); 00364 if (err != NSAPI_ERROR_OK ) { 00365 tr_error("Failed to open data channel!"); 00366 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00367 return err; 00368 } 00369 #else 00370 // additional urc to get better disconnect info for application. Not critical so not returning an error in case of failure 00371 err = _at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev)); 00372 if (err == NSAPI_ERROR_OK ) { 00373 _at.lock(); 00374 _at.cmd_start("AT+CGEREP=1"); 00375 _at.cmd_stop(); 00376 _at.resp_start(); 00377 _at.resp_stop(); 00378 _at.unlock(); 00379 } 00380 00381 call_network_cb(NSAPI_STATUS_GLOBAL_UP ); 00382 #endif 00383 00384 return NSAPI_ERROR_OK ; 00385 } 00386 00387 nsapi_error_t AT_CellularNetwork::open_data_channel() 00388 { 00389 #if NSAPI_PPP_AVAILABLE 00390 tr_info("Open data channel in PPP mode"); 00391 if (is_supported(AT_CGDATA)) { 00392 _at.cmd_start("AT+CGDATA=\"PPP\","); 00393 _at.write_int(_cid); 00394 } else { 00395 MBED_ASSERT(_cid >= 0 && _cid <= 99); 00396 char cmd_buf[sizeof("ATD*99***xx#")]; 00397 std::sprintf(cmd_buf, "ATD*99***%d#", _cid); 00398 _at.cmd_start(cmd_buf); 00399 } 00400 _at.cmd_stop(); 00401 00402 _at.resp_start("CONNECT", true); 00403 if (_at.get_last_error()) { 00404 tr_error("Failed to CONNECT"); 00405 return _at.get_last_error(); 00406 } 00407 00408 _at.set_is_filehandle_usable(false); 00409 00410 /* Initialize PPP 00411 * If blocking: mbed_ppp_init() is a blocking call, it will block until 00412 connected, or timeout after 30 seconds*/ 00413 return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), NULL, NULL, _ip_stack_type); 00414 #else 00415 return NSAPI_ERROR_OK ; 00416 #endif // #if NSAPI_PPP_AVAILABLE 00417 } 00418 00419 /** 00420 * User initiated disconnect 00421 * 00422 * Disconnects from PPP connection only and brings down the underlying network 00423 * interface 00424 */ 00425 nsapi_error_t AT_CellularNetwork::disconnect() 00426 { 00427 #if NSAPI_PPP_AVAILABLE 00428 nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle()); 00429 // after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it 00430 // will set the correct sigio and nonblocking 00431 _at.lock(); 00432 _at.set_file_handle(_at.get_file_handle()); 00433 _at.set_is_filehandle_usable(true); 00434 _at.unlock(); 00435 return err; 00436 #else 00437 _at.lock(); 00438 00439 _is_context_active = false; 00440 size_t active_contexts_count = 0; 00441 _at.cmd_start("AT+CGACT?"); 00442 _at.cmd_stop(); 00443 _at.resp_start("+CGACT:"); 00444 while (_at.info_resp()) { 00445 int context_id = _at.read_int(); 00446 int context_activation_state = _at.read_int(); 00447 if (context_activation_state == 1) { 00448 active_contexts_count++; 00449 if (context_id == _cid) { 00450 _is_context_active = true; 00451 } 00452 } 00453 } 00454 _at.resp_stop(); 00455 00456 // 3GPP TS 27.007: 00457 // For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR 00458 if (_is_context_active && (_current_act < RAT_E_UTRAN || active_contexts_count > 1)) { 00459 _at.cmd_start("AT+CGACT=0,"); 00460 _at.write_int(_cid); 00461 _at.cmd_stop(); 00462 _at.resp_start(); 00463 _at.resp_stop(); 00464 } 00465 00466 _at.restore_at_timeout(); 00467 00468 _at.remove_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev)); 00469 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00470 00471 return _at.unlock_return_error(); 00472 #endif 00473 } 00474 00475 void AT_CellularNetwork::call_network_cb(nsapi_connection_status_t status) 00476 { 00477 if (_connect_status != status) { 00478 _connect_status = status; 00479 if (_connection_status_cb) { 00480 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , _connect_status); 00481 } 00482 } 00483 } 00484 00485 void AT_CellularNetwork::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb) 00486 { 00487 _connection_status_cb = status_cb; 00488 } 00489 00490 nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const 00491 { 00492 return _connect_status; 00493 } 00494 00495 nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking) 00496 { 00497 #if NSAPI_PPP_AVAILABLE 00498 return nsapi_ppp_set_blocking(blocking); 00499 #else 00500 return NSAPI_ERROR_OK ; 00501 #endif 00502 } 00503 00504 #if NSAPI_PPP_AVAILABLE 00505 void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter) 00506 { 00507 _connect_status = (nsapi_connection_status_t)parameter; 00508 00509 if (_connection_status_cb) { 00510 _connection_status_cb(event, parameter); 00511 } 00512 } 00513 #endif 00514 00515 nsapi_error_t AT_CellularNetwork::do_user_authentication() 00516 { 00517 // if user has defined user name and password we need to call CGAUTH before activating or modifying context 00518 if (_pwd && _uname) { 00519 if (!is_supported(AT_CGAUTH)) { 00520 return NSAPI_ERROR_UNSUPPORTED ; 00521 } 00522 _at.cmd_start("AT+CGAUTH="); 00523 _at.write_int(_cid); 00524 _at.write_int(_authentication_type); 00525 _at.write_string(_uname); 00526 _at.write_string(_pwd); 00527 _at.cmd_stop(); 00528 _at.resp_start(); 00529 _at.resp_stop(); 00530 if (_at.get_last_error() != NSAPI_ERROR_OK ) { 00531 return NSAPI_ERROR_AUTH_FAILURE ; 00532 } 00533 } 00534 00535 return NSAPI_ERROR_OK ; 00536 } 00537 00538 bool AT_CellularNetwork::set_new_context(int cid) 00539 { 00540 nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested; 00541 00542 if (tmp_stack == DEFAULT_STACK) { 00543 bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK); 00544 bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK); 00545 00546 if (modem_supports_ipv6 && modem_supports_ipv4) { 00547 tmp_stack = IPV4V6_STACK; 00548 } else if (modem_supports_ipv6) { 00549 tmp_stack = IPV6_STACK; 00550 } else if (modem_supports_ipv4) { 00551 tmp_stack = IPV4_STACK; 00552 } 00553 } 00554 00555 char pdp_type[8 + 1] = {0}; 00556 00557 switch (tmp_stack) { 00558 case IPV4_STACK: 00559 strncpy(pdp_type, "IP", sizeof(pdp_type)); 00560 break; 00561 case IPV6_STACK: 00562 strncpy(pdp_type, "IPV6", sizeof(pdp_type)); 00563 break; 00564 case IPV4V6_STACK: 00565 strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4 00566 break; 00567 default: 00568 break; 00569 } 00570 00571 //apn: "If the value is null or omitted, then the subscription value will be requested." 00572 bool success = false; 00573 _at.cmd_start("AT+CGDCONT="); 00574 _at.write_int(cid); 00575 _at.write_string(pdp_type); 00576 _at.write_string(_apn); 00577 _at.cmd_stop(); 00578 _at.resp_start(); 00579 _at.resp_stop(); 00580 success = (_at.get_last_error() == NSAPI_ERROR_OK ); 00581 00582 // Fall back to ipv4 00583 if (!success && tmp_stack == IPV4V6_STACK) { 00584 tmp_stack = IPV4_STACK; 00585 _at.cmd_start("AT+FCLASS=0;+CGDCONT="); 00586 _at.write_int(cid); 00587 _at.write_string("IP"); 00588 _at.write_string(_apn); 00589 _at.cmd_stop(); 00590 _at.resp_start(); 00591 _at.resp_stop(); 00592 success = (_at.get_last_error() == NSAPI_ERROR_OK ); 00593 } 00594 00595 if (success) { 00596 _ip_stack_type = tmp_stack; 00597 _cid = cid; 00598 _new_context_set = true; 00599 tr_info("New PDP context id %d was created", _cid); 00600 } 00601 00602 return success; 00603 } 00604 00605 bool AT_CellularNetwork::get_context() 00606 { 00607 if (_apn) { 00608 tr_debug("APN in use: %s", _apn); 00609 } else { 00610 tr_debug("NO APN"); 00611 } 00612 00613 _at.cmd_start("AT+CGDCONT?"); 00614 _at.cmd_stop(); 00615 _at.resp_start("+CGDCONT:"); 00616 _cid = -1; 00617 int cid_max = 0; // needed when creating new context 00618 char apn[MAX_ACCESSPOINT_NAME_LENGTH]; 00619 int apn_len = 0; 00620 00621 bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK); 00622 bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK); 00623 00624 while (_at.info_resp()) { 00625 int cid = _at.read_int(); 00626 if (cid > cid_max) { 00627 cid_max = cid; 00628 } 00629 char pdp_type_from_context[10]; 00630 int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1); 00631 if (pdp_type_len > 0) { 00632 apn_len = _at.read_string(apn, sizeof(apn) - 1); 00633 if (apn_len >= 0) { 00634 if (_apn && (strcmp(apn, _apn) != 0)) { 00635 continue; 00636 } 00637 nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context); 00638 // Accept dual PDP context for IPv4/IPv6 only modems 00639 if (pdp_stack != DEFAULT_STACK && (get_modem_stack_type(pdp_stack) || pdp_stack == IPV4V6_STACK)) { 00640 if (_ip_stack_type_requested == IPV4_STACK) { 00641 if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) { 00642 _ip_stack_type = _ip_stack_type_requested; 00643 _cid = cid; 00644 break; 00645 } 00646 } else if (_ip_stack_type_requested == IPV6_STACK) { 00647 if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) { 00648 _ip_stack_type = _ip_stack_type_requested; 00649 _cid = cid; 00650 break; 00651 } 00652 } else { 00653 // requested dual stack or stack is not specified 00654 // If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6. 00655 if (pdp_stack == IPV4V6_STACK) { 00656 if (modem_supports_ipv6) { 00657 _ip_stack_type = IPV6_STACK; 00658 _cid = cid; 00659 break; 00660 } else if (modem_supports_ipv4) { 00661 _ip_stack_type = IPV4_STACK; 00662 _cid = cid; 00663 break; 00664 } 00665 // If PDP is IPV4 or IPV6 they are already checked if supported 00666 } else { 00667 _ip_stack_type = pdp_stack; 00668 _cid = cid; 00669 00670 if (pdp_stack == IPV6_STACK) { 00671 break; 00672 } 00673 if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) { 00674 break; 00675 } 00676 } 00677 } 00678 } 00679 } 00680 } 00681 } 00682 _at.resp_stop(); 00683 if (_cid == -1) { // no suitable context was found so create a new one 00684 if (!set_new_context(cid_max + 1)) { 00685 return false; 00686 } 00687 } 00688 00689 // save the apn 00690 if (apn_len > 0 && !_apn) { 00691 _apn = (char *)malloc(apn_len * sizeof(char) + 1); 00692 if (_apn) { 00693 memcpy(_apn, apn, apn_len + 1); 00694 } else { 00695 return false; 00696 } 00697 } 00698 00699 tr_debug("Context id %d", _cid); 00700 return true; 00701 } 00702 00703 nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type) 00704 { 00705 nsapi_ip_stack_t stack = DEFAULT_STACK; 00706 int len = strlen(pdp_type); 00707 00708 if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) { 00709 stack = IPV4V6_STACK; 00710 } else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) { 00711 stack = IPV6_STACK; 00712 } else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) { 00713 stack = IPV4_STACK; 00714 } 00715 return stack; 00716 } 00717 00718 nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on) 00719 { 00720 int index = (int)type; 00721 MBED_ASSERT(index >= 0 && index < C_MAX); 00722 00723 RegistrationMode mode = has_registration(type); 00724 if (mode == RegistrationModeDisable) { 00725 return NSAPI_ERROR_UNSUPPORTED ; 00726 } else { 00727 _at.lock(); 00728 if (urc_on) { 00729 _at.cmd_start(at_reg[index].cmd); 00730 const uint8_t ch_eq = '='; 00731 _at.write_bytes(&ch_eq, 1); 00732 _at.write_int((int)mode); 00733 _at.cmd_stop(); 00734 } else { 00735 _at.cmd_start(at_reg[index].cmd); 00736 _at.write_string("=0", false); 00737 _at.cmd_stop(); 00738 } 00739 00740 _at.resp_start(); 00741 _at.resp_stop(); 00742 return _at.unlock_return_error(); 00743 } 00744 } 00745 00746 nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode &mode) 00747 { 00748 _at.lock(); 00749 _at.cmd_start("AT+COPS?"); 00750 _at.cmd_stop(); 00751 _at.resp_start("+COPS:"); 00752 mode = (NWRegisteringMode)_at.read_int(); 00753 _at.resp_stop(); 00754 00755 return _at.unlock_return_error(); 00756 } 00757 00758 nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn) 00759 { 00760 _at.lock(); 00761 00762 if (!plmn) { 00763 tr_debug("Automatic network registration"); 00764 _at.cmd_start("AT+COPS?"); 00765 _at.cmd_stop(); 00766 _at.resp_start("+COPS:"); 00767 int mode = _at.read_int(); 00768 _at.resp_stop(); 00769 if (mode != 0) { 00770 _at.clear_error(); 00771 _at.cmd_start("AT+COPS=0"); 00772 _at.cmd_stop(); 00773 _at.resp_start(); 00774 _at.resp_stop(); 00775 } 00776 } else { 00777 tr_debug("Manual network registration to %s", plmn); 00778 _at.cmd_start("AT+COPS=4,2,"); 00779 _at.write_string(plmn); 00780 _at.cmd_stop(); 00781 _at.resp_start(); 00782 _at.resp_stop(); 00783 } 00784 00785 return _at.unlock_return_error(); 00786 } 00787 00788 void AT_CellularNetwork::read_reg_params(RegistrationType type, RegistrationStatus ®_status, int &lac, int &cell_id, int &act) 00789 { 00790 const int LAC_LENGTH = 5, CELL_ID_LENGTH = 9; 00791 char lac_string[LAC_LENGTH] = {0}, cell_id_string[CELL_ID_LENGTH] = {0}; 00792 bool lac_read = false, cell_id_read = false; 00793 00794 reg_status = (RegistrationStatus)_at.read_int(); 00795 00796 int len = _at.read_string(lac_string, LAC_LENGTH); 00797 if (memcmp(lac_string, "ffff", LAC_LENGTH - 1) && len >= 0) { 00798 lac_read = true; 00799 } 00800 00801 len = _at.read_string(cell_id_string, CELL_ID_LENGTH); 00802 if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH - 1) && len >= 0) { 00803 cell_id_read = true; 00804 } 00805 00806 act = _at.read_int(); 00807 00808 if (lac_read) { 00809 lac = hex_str_to_int(lac_string, LAC_LENGTH); 00810 tr_debug("lac %s %d", lac_string, lac); 00811 } 00812 00813 if (cell_id_read) { 00814 cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH); 00815 tr_debug("cell_id %s %d", cell_id_string, cell_id); 00816 } 00817 } 00818 00819 nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status) 00820 { 00821 int i = (int)type; 00822 MBED_ASSERT(i >= 0 && i < C_MAX); 00823 00824 if (has_registration(at_reg[i].type) == RegistrationModeDisable) { 00825 return NSAPI_ERROR_UNSUPPORTED ; 00826 } 00827 00828 _at.lock(); 00829 00830 const char *rsp[] = { "+CEREG:", "+CGREG:", "+CREG:"}; 00831 _at.cmd_start(at_reg[i].cmd); 00832 _at.write_string("?", false); 00833 _at.cmd_stop(); 00834 _at.resp_start(rsp[i]); 00835 00836 (void)_at.read_int(); // ignore urc mode subparam 00837 int lac = -1, cell_id = -1, act = -1; 00838 read_reg_params(type, status, lac, cell_id, act); 00839 _at.resp_stop(); 00840 _reg_status = status; 00841 00842 if (cell_id != -1) { 00843 _cell_id = cell_id; 00844 } 00845 if (act != -1) { 00846 _current_act = (RadioAccessTechnology)act; 00847 } 00848 00849 return _at.unlock_return_error(); 00850 } 00851 00852 nsapi_error_t AT_CellularNetwork::get_cell_id(int &cell_id) 00853 { 00854 cell_id = _cell_id; 00855 return NSAPI_ERROR_OK ; 00856 } 00857 00858 AT_CellularNetwork::RegistrationMode AT_CellularNetwork::has_registration(RegistrationType reg_type) 00859 { 00860 (void)reg_type; 00861 return RegistrationModeLAC; 00862 } 00863 00864 nsapi_error_t AT_CellularNetwork::set_attach(int /*timeout*/) 00865 { 00866 _at.lock(); 00867 00868 _at.cmd_start("AT+CGATT?"); 00869 _at.cmd_stop(); 00870 _at.resp_start("+CGATT:"); 00871 int attached_state = _at.read_int(); 00872 _at.resp_stop(); 00873 if (attached_state != 1) { 00874 tr_debug("Network attach"); 00875 _at.cmd_start("AT+CGATT=1"); 00876 _at.cmd_stop(); 00877 _at.resp_start(); 00878 _at.resp_stop(); 00879 } 00880 00881 return _at.unlock_return_error(); 00882 } 00883 00884 nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status) 00885 { 00886 _at.lock(); 00887 00888 _at.cmd_start("AT+CGATT?"); 00889 _at.cmd_stop(); 00890 00891 _at.resp_start("+CGATT:"); 00892 if (_at.info_resp()) { 00893 int attach_status = _at.read_int(); 00894 status = (attach_status == 1) ? Attached : Detached; 00895 } 00896 _at.resp_stop(); 00897 00898 return _at.unlock_return_error(); 00899 } 00900 00901 nsapi_error_t AT_CellularNetwork::detach() 00902 { 00903 _at.lock(); 00904 00905 tr_debug("Network detach"); 00906 _at.cmd_start("AT+CGATT=0"); 00907 _at.cmd_stop(); 00908 _at.resp_start(); 00909 _at.resp_stop(); 00910 00911 call_network_cb(NSAPI_STATUS_DISCONNECTED ); 00912 00913 return _at.unlock_return_error(); 00914 } 00915 00916 nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer) 00917 { 00918 // If apn is set 00919 if (_apn) { 00920 _at.lock(); 00921 _at.cmd_start("AT+CABTRDP="); 00922 _at.write_string(_apn); 00923 _at.cmd_stop(); 00924 _at.resp_start("+CABTRDP:"); 00925 if (_at.info_resp()) { 00926 _at.skip_param(); 00927 backoff_timer = _at.read_int(); 00928 } 00929 _at.resp_stop(); 00930 return _at.unlock_return_error(); 00931 } 00932 00933 return NSAPI_ERROR_PARAMETER ; 00934 } 00935 00936 NetworkStack *AT_CellularNetwork::get_stack() 00937 { 00938 #if NSAPI_PPP_AVAILABLE 00939 // use lwIP/PPP if modem does not have IP stack 00940 if (!_stack) { 00941 _stack = nsapi_ppp_get_stack(); 00942 } 00943 #endif 00944 return _stack; 00945 } 00946 00947 const char *AT_CellularNetwork::get_ip_address() 00948 { 00949 #if NSAPI_PPP_AVAILABLE 00950 return nsapi_ppp_get_ip_addr(_at.get_file_handle()); 00951 #else 00952 if (!_stack) { 00953 _stack = get_stack(); 00954 } 00955 if (_stack) { 00956 return _stack->get_ip_address(); 00957 } 00958 return NULL; 00959 #endif 00960 } 00961 00962 nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type) 00963 { 00964 if (get_modem_stack_type(stack_type)) { 00965 _ip_stack_type_requested = stack_type; 00966 return NSAPI_ERROR_OK ; 00967 } else { 00968 return NSAPI_ERROR_PARAMETER ; 00969 } 00970 } 00971 00972 nsapi_ip_stack_t AT_CellularNetwork::get_stack_type() 00973 { 00974 return _ip_stack_type; 00975 } 00976 00977 bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) 00978 { 00979 if (requested_stack == _ip_stack_type) { 00980 return true; 00981 } else { 00982 return false; 00983 } 00984 } 00985 00986 nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct) 00987 { 00988 return NSAPI_ERROR_UNSUPPORTED ; 00989 } 00990 00991 nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology &rat) 00992 { 00993 rat = _current_act; 00994 return NSAPI_ERROR_OK ; 00995 } 00996 00997 nsapi_error_t AT_CellularNetwork::set_access_technology(RadioAccessTechnology opAct) 00998 { 00999 if (opAct == RAT_UNKNOWN) { 01000 return NSAPI_ERROR_UNSUPPORTED ; 01001 } 01002 01003 _op_act = opAct; 01004 01005 return set_access_technology_impl(opAct); 01006 } 01007 01008 nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount) 01009 { 01010 int idx = 0; 01011 01012 _at.lock(); 01013 01014 _at.cmd_start("AT+COPS=?"); 01015 _at.cmd_stop(); 01016 01017 _at.resp_start("+COPS:"); 01018 01019 int ret, error_code = -1; 01020 operator_t *op = NULL; 01021 01022 while (_at.info_elem('(')) { 01023 01024 op = operators.add_new(); 01025 if (!op) { 01026 tr_warn("Could not allocate new operator"); 01027 _at.resp_stop(); 01028 _at.unlock(); 01029 operators.delete_all(); 01030 opsCount = 0; 01031 return NSAPI_ERROR_NO_MEMORY ; 01032 } 01033 01034 op->op_status = (operator_t::Status)_at.read_int(); 01035 _at.read_string(op->op_long, sizeof(op->op_long)); 01036 _at.read_string(op->op_short, sizeof(op->op_short)); 01037 _at.read_string(op->op_num, sizeof(op->op_num)); 01038 01039 // Optional - try read an int 01040 ret = _at.read_int(); 01041 op->op_rat = (ret == error_code) ? RAT_UNKNOWN : (RadioAccessTechnology)ret; 01042 01043 if ((_op_act == RAT_UNKNOWN) || 01044 ((op->op_rat != RAT_UNKNOWN) && (op->op_rat == _op_act))) { 01045 idx++; 01046 } else { 01047 operators.delete_last(); 01048 } 01049 } 01050 01051 _at.resp_stop(); 01052 01053 opsCount = idx; 01054 return _at.unlock_return_error(); 01055 } 01056 01057 nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt, 01058 Preferred_UE_Opt preferred_opt) 01059 { 01060 _at.lock(); 01061 01062 _at.cmd_start("AT+CCIOTOPT="); 01063 _at.write_int(_cid); 01064 _at.write_int(supported_opt); 01065 _at.write_int(preferred_opt); 01066 _at.cmd_stop(); 01067 01068 _at.resp_start(); 01069 _at.resp_stop(); 01070 01071 return _at.unlock_return_error(); 01072 } 01073 01074 nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt &supported_opt, 01075 Preferred_UE_Opt &preferred_opt) 01076 { 01077 _at.lock(); 01078 01079 _at.cmd_start("AT+CCIOTOPT?"); 01080 _at.cmd_stop(); 01081 01082 _at.resp_start("+CCIOTOPT:"); 01083 _at.read_int(); 01084 if (_at.get_last_error() == NSAPI_ERROR_OK ) { 01085 supported_opt = (Supported_UE_Opt)_at.read_int(); 01086 preferred_opt = (Preferred_UE_Opt)_at.read_int(); 01087 } 01088 01089 _at.resp_stop(); 01090 01091 return _at.unlock_return_error(); 01092 } 01093 01094 nsapi_error_t AT_CellularNetwork::get_rate_control( 01095 CellularNetwork::RateControlExceptionReports &reports, 01096 CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate) 01097 { 01098 01099 _at.lock(); 01100 01101 _at.cmd_start("AT+CGAPNRC="); 01102 _at.write_int(_cid); 01103 _at.cmd_stop(); 01104 01105 _at.resp_start("+CGAPNRC:"); 01106 _at.read_int(); 01107 if (_at.get_last_error() == NSAPI_ERROR_OK ) { 01108 bool comma_found = true; 01109 int next_element = _at.read_int(); 01110 if (next_element >= 0) { 01111 reports = (RateControlExceptionReports)next_element; 01112 tr_debug("reports %d", reports); 01113 next_element = _at.read_int(); 01114 } else { 01115 comma_found = false; 01116 } 01117 01118 if (comma_found && next_element >= 0) { 01119 timeUnit = (RateControlUplinkTimeUnit)next_element; 01120 tr_debug("time %d", timeUnit); 01121 next_element = _at.read_int(); 01122 } else { 01123 comma_found = false; 01124 } 01125 01126 if (comma_found && next_element >= 0) { 01127 uplinkRate = next_element; 01128 tr_debug("rate %d", uplinkRate); 01129 } 01130 } 01131 _at.resp_stop(); 01132 01133 return _at.unlock_return_error(); 01134 } 01135 01136 nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t ¶ms_list) 01137 { 01138 const int ipv6_subnet_size = 128; 01139 const int max_ipv6_size = 64; 01140 char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size); 01141 if (!ipv6_and_subnetmask) { 01142 return NSAPI_ERROR_NO_MEMORY ; 01143 } 01144 01145 char *temp = (char *)malloc(max_ipv6_size); 01146 if (!temp) { 01147 free(ipv6_and_subnetmask); 01148 return NSAPI_ERROR_NO_MEMORY ; 01149 } 01150 01151 _at.lock(); 01152 01153 _at.cmd_start("AT+CGCONTRDP="); 01154 _at.write_int(_cid); 01155 _at.cmd_stop(); 01156 01157 _at.resp_start("+CGCONTRDP:"); 01158 pdpcontext_params_t *params = NULL; 01159 while (_at.info_resp()) { // response can be zero or many +CGDCONT lines 01160 params = params_list.add_new(); 01161 if (!params) { 01162 tr_warn("Could not allocate new pdpcontext_params_t"); 01163 _at.resp_stop(); 01164 _at.unlock(); 01165 params_list.delete_all(); 01166 free(temp); 01167 free(ipv6_and_subnetmask); 01168 return NSAPI_ERROR_NO_MEMORY ; 01169 } 01170 01171 params->cid = _at.read_int(); 01172 params->bearer_id = _at.read_int(); 01173 _at.read_string(params->apn, sizeof(params->apn)); 01174 01175 // rest are optional params 01176 ipv6_and_subnetmask[0] = '\0'; 01177 temp[0] = '\0'; 01178 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01179 separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask)); 01180 ipv6_and_subnetmask[0] = '\0'; 01181 01182 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01183 separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size); 01184 prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size); 01185 ipv6_and_subnetmask[0] = '\0'; 01186 temp[0] = '\0'; 01187 01188 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01189 separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size); 01190 prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size); 01191 ipv6_and_subnetmask[0] = '\0'; 01192 temp[0] = '\0'; 01193 01194 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01195 separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size); 01196 prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size); 01197 ipv6_and_subnetmask[0] = '\0'; 01198 temp[0] = '\0'; 01199 01200 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01201 separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size); 01202 prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size); 01203 ipv6_and_subnetmask[0] = '\0'; 01204 temp[0] = '\0'; 01205 01206 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); 01207 separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size); 01208 prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size); 01209 01210 params->im_signalling_flag = _at.read_int(); 01211 params->lipa_indication = _at.read_int(); 01212 params->ipv4_mtu = _at.read_int(); 01213 params->wlan_offload = _at.read_int(); 01214 params->local_addr_ind = _at.read_int(); 01215 params->non_ip_mtu = _at.read_int(); 01216 params->serving_plmn_rate_control_value = _at.read_int(); 01217 } 01218 _at.resp_stop(); 01219 01220 free(temp); 01221 free(ipv6_and_subnetmask); 01222 01223 return _at.unlock_return_error(); 01224 } 01225 01226 nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp) 01227 { 01228 _at.lock(); 01229 01230 _at.cmd_start("AT+CESQ"); 01231 _at.cmd_stop(); 01232 01233 _at.resp_start("+CESQ:"); 01234 rxlev = _at.read_int(); 01235 ber = _at.read_int(); 01236 rscp = _at.read_int(); 01237 ecno = _at.read_int(); 01238 rsrq = _at.read_int(); 01239 rsrp = _at.read_int(); 01240 _at.resp_stop(); 01241 if (rxlev < 0 || ber < 0 || rscp < 0 || ecno < 0 || rsrq < 0 || rsrp < 0) { 01242 _at.unlock(); 01243 return NSAPI_ERROR_DEVICE_ERROR ; 01244 } 01245 01246 return _at.unlock_return_error(); 01247 } 01248 01249 nsapi_error_t AT_CellularNetwork::get_signal_quality(int &rssi, int &ber) 01250 { 01251 _at.lock(); 01252 01253 _at.cmd_start("AT+CSQ"); 01254 _at.cmd_stop(); 01255 01256 _at.resp_start("+CSQ:"); 01257 rssi = _at.read_int(); 01258 ber = _at.read_int(); 01259 _at.resp_stop(); 01260 if (rssi < 0 || ber < 0) { 01261 _at.unlock(); 01262 return NSAPI_ERROR_DEVICE_ERROR ; 01263 } 01264 01265 return _at.unlock_return_error(); 01266 } 01267 01268 /** Get the last 3GPP error code 01269 * @return see 3GPP TS 27.007 error codes 01270 */ 01271 int AT_CellularNetwork::get_3gpp_error() 01272 { 01273 return _at.get_3gpp_error(); 01274 } 01275 01276 nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &operator_params) 01277 { 01278 _at.lock(); 01279 01280 _at.cmd_start("AT+COPS?"); 01281 _at.cmd_stop(); 01282 01283 _at.resp_start("+COPS:"); 01284 _at.read_int(); //ignore mode 01285 format = _at.read_int(); 01286 01287 if (_at.get_last_error() == NSAPI_ERROR_OK ) { 01288 switch (format) { 01289 case 0: 01290 _at.read_string(operator_params.op_long, sizeof(operator_params.op_long)); 01291 break; 01292 case 1: 01293 _at.read_string(operator_params.op_short, sizeof(operator_params.op_short)); 01294 break; 01295 default: 01296 _at.read_string(operator_params.op_num, sizeof(operator_params.op_num)); 01297 break; 01298 } 01299 operator_params.op_rat = (RadioAccessTechnology)_at.read_int(); 01300 } 01301 01302 _at.resp_stop(); 01303 01304 return _at.unlock_return_error(); 01305 } 01306 01307 nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_names) 01308 { 01309 _at.lock(); 01310 01311 _at.cmd_start("AT+COPN"); 01312 _at.cmd_stop(); 01313 01314 _at.resp_start("+COPN:"); 01315 operator_names_t *names = NULL; 01316 while (_at.info_resp()) { 01317 names = op_names.add_new(); 01318 if (!names) { 01319 tr_warn("Could not allocate new operator_names_t"); 01320 _at.resp_stop(); 01321 _at.unlock(); 01322 op_names.delete_all(); 01323 return NSAPI_ERROR_NO_MEMORY ; 01324 } 01325 _at.read_string(names->numeric, sizeof(names->numeric)); 01326 _at.read_string(names->alpha, sizeof(names->alpha)); 01327 } 01328 01329 _at.resp_stop(); 01330 return _at.unlock_return_error(); 01331 }
Generated on Tue Aug 9 2022 00:37:02 by
