Kev Mann / mbed-dev-OS5_10_4
Committer:
kevman
Date:
Wed Nov 28 15:10:15 2018 +0000
Revision:
0:38ceb79fef03
RTC modified

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 0:38ceb79fef03 1 /*
kevman 0:38ceb79fef03 2 * Copyright (c) 2017, Arm Limited and affiliates.
kevman 0:38ceb79fef03 3 * SPDX-License-Identifier: Apache-2.0
kevman 0:38ceb79fef03 4 *
kevman 0:38ceb79fef03 5 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 0:38ceb79fef03 6 * you may not use this file except in compliance with the License.
kevman 0:38ceb79fef03 7 * You may obtain a copy of the License at
kevman 0:38ceb79fef03 8 *
kevman 0:38ceb79fef03 9 * http://www.apache.org/licenses/LICENSE-2.0
kevman 0:38ceb79fef03 10 *
kevman 0:38ceb79fef03 11 * Unless required by applicable law or agreed to in writing, software
kevman 0:38ceb79fef03 12 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 0:38ceb79fef03 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 0:38ceb79fef03 14 * See the License for the specific language governing permissions and
kevman 0:38ceb79fef03 15 * limitations under the License.
kevman 0:38ceb79fef03 16 */
kevman 0:38ceb79fef03 17
kevman 0:38ceb79fef03 18 #include <stdlib.h>
kevman 0:38ceb79fef03 19 #include "AT_CellularNetwork.h"
kevman 0:38ceb79fef03 20 #include "nsapi_ppp.h"
kevman 0:38ceb79fef03 21 #include "CellularUtil.h"
kevman 0:38ceb79fef03 22 #include "CellularLog.h"
kevman 0:38ceb79fef03 23 #include "CellularCommon.h"
kevman 0:38ceb79fef03 24
kevman 0:38ceb79fef03 25 using namespace std;
kevman 0:38ceb79fef03 26 using namespace mbed_cellular_util;
kevman 0:38ceb79fef03 27 using namespace mbed;
kevman 0:38ceb79fef03 28
kevman 0:38ceb79fef03 29 struct at_reg_t {
kevman 0:38ceb79fef03 30 const CellularNetwork::RegistrationType type;
kevman 0:38ceb79fef03 31 const char *const cmd;
kevman 0:38ceb79fef03 32 const char *const urc_prefix;
kevman 0:38ceb79fef03 33 };
kevman 0:38ceb79fef03 34
kevman 0:38ceb79fef03 35 static const at_reg_t at_reg[] = {
kevman 0:38ceb79fef03 36 { CellularNetwork::C_EREG, "AT+CEREG", "+CEREG:"},
kevman 0:38ceb79fef03 37 { CellularNetwork::C_GREG, "AT+CGREG", "+CGREG:"},
kevman 0:38ceb79fef03 38 { CellularNetwork::C_REG, "AT+CREG", "+CREG:"}
kevman 0:38ceb79fef03 39 };
kevman 0:38ceb79fef03 40
kevman 0:38ceb79fef03 41 AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler),
kevman 0:38ceb79fef03 42 _stack(NULL), _apn(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK),
kevman 0:38ceb79fef03 43 _ip_stack_type(DEFAULT_STACK), _cid(-1), _connection_status_cb(NULL), _op_act(RAT_UNKNOWN),
kevman 0:38ceb79fef03 44 _authentication_type(CHAP), _cell_id(-1), _connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false),
kevman 0:38ceb79fef03 45 _is_context_active(false), _reg_status(NotRegistered), _current_act(RAT_UNKNOWN)
kevman 0:38ceb79fef03 46 {
kevman 0:38ceb79fef03 47 }
kevman 0:38ceb79fef03 48
kevman 0:38ceb79fef03 49 AT_CellularNetwork::~AT_CellularNetwork()
kevman 0:38ceb79fef03 50 {
kevman 0:38ceb79fef03 51 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 52 (void)disconnect();
kevman 0:38ceb79fef03 53 #else
kevman 0:38ceb79fef03 54 delete _stack;
kevman 0:38ceb79fef03 55 #endif // NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 56
kevman 0:38ceb79fef03 57 for (int type = 0; type < CellularNetwork::C_MAX; type++) {
kevman 0:38ceb79fef03 58 if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
kevman 0:38ceb79fef03 59 _at.remove_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]);
kevman 0:38ceb79fef03 60 }
kevman 0:38ceb79fef03 61 }
kevman 0:38ceb79fef03 62
kevman 0:38ceb79fef03 63 _at.remove_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
kevman 0:38ceb79fef03 64 _at.remove_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
kevman 0:38ceb79fef03 65 free_credentials();
kevman 0:38ceb79fef03 66 }
kevman 0:38ceb79fef03 67
kevman 0:38ceb79fef03 68 nsapi_error_t AT_CellularNetwork::init()
kevman 0:38ceb79fef03 69 {
kevman 0:38ceb79fef03 70 _urc_funcs[C_EREG] = callback(this, &AT_CellularNetwork::urc_cereg);
kevman 0:38ceb79fef03 71 _urc_funcs[C_GREG] = callback(this, &AT_CellularNetwork::urc_cgreg);
kevman 0:38ceb79fef03 72 _urc_funcs[C_REG] = callback(this, &AT_CellularNetwork::urc_creg);
kevman 0:38ceb79fef03 73
kevman 0:38ceb79fef03 74 for (int type = 0; type < CellularNetwork::C_MAX; type++) {
kevman 0:38ceb79fef03 75 if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
kevman 0:38ceb79fef03 76 if (_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]) != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 77 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 78 }
kevman 0:38ceb79fef03 79 }
kevman 0:38ceb79fef03 80 }
kevman 0:38ceb79fef03 81
kevman 0:38ceb79fef03 82 return _at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
kevman 0:38ceb79fef03 83 }
kevman 0:38ceb79fef03 84
kevman 0:38ceb79fef03 85 void AT_CellularNetwork::free_credentials()
kevman 0:38ceb79fef03 86 {
kevman 0:38ceb79fef03 87 if (_uname) {
kevman 0:38ceb79fef03 88 free(_uname);
kevman 0:38ceb79fef03 89 _uname = NULL;
kevman 0:38ceb79fef03 90 }
kevman 0:38ceb79fef03 91
kevman 0:38ceb79fef03 92 if (_pwd) {
kevman 0:38ceb79fef03 93 free(_pwd);
kevman 0:38ceb79fef03 94 _pwd = NULL;
kevman 0:38ceb79fef03 95 }
kevman 0:38ceb79fef03 96
kevman 0:38ceb79fef03 97 if (_apn) {
kevman 0:38ceb79fef03 98 free(_apn);
kevman 0:38ceb79fef03 99 _apn = NULL;
kevman 0:38ceb79fef03 100 }
kevman 0:38ceb79fef03 101 }
kevman 0:38ceb79fef03 102
kevman 0:38ceb79fef03 103 void AT_CellularNetwork::urc_no_carrier()
kevman 0:38ceb79fef03 104 {
kevman 0:38ceb79fef03 105 tr_error("Data call failed: no carrier");
kevman 0:38ceb79fef03 106 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 107 }
kevman 0:38ceb79fef03 108
kevman 0:38ceb79fef03 109 void AT_CellularNetwork::urc_cgev()
kevman 0:38ceb79fef03 110 {
kevman 0:38ceb79fef03 111 char buf[13];
kevman 0:38ceb79fef03 112 if (_at.read_string(buf, 13) < 8) { // smallest string length we wan't to compare is 8
kevman 0:38ceb79fef03 113 return;
kevman 0:38ceb79fef03 114 }
kevman 0:38ceb79fef03 115 tr_debug("urc_cgev: %s", buf);
kevman 0:38ceb79fef03 116
kevman 0:38ceb79fef03 117 bool call_cb = false;
kevman 0:38ceb79fef03 118 // 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.
kevman 0:38ceb79fef03 119
kevman 0:38ceb79fef03 120 if (memcmp(buf, "NW DETACH", 9) == 0) { // The network has forced a PS detach
kevman 0:38ceb79fef03 121 call_cb = true;
kevman 0:38ceb79fef03 122 } else if (memcmp(buf, "ME DETACH", 9) == 0) {// The mobile termination has forced a PS detach.
kevman 0:38ceb79fef03 123 call_cb = true;
kevman 0:38ceb79fef03 124 } else if (memcmp(buf, "NW DEACT", 8) == 0) {// The network has forced a context deactivation
kevman 0:38ceb79fef03 125 call_cb = true;
kevman 0:38ceb79fef03 126 } else if (memcmp(buf, "ME DEACT", 8) == 0) {// The mobile termination has forced a context deactivation
kevman 0:38ceb79fef03 127 call_cb = true;
kevman 0:38ceb79fef03 128 } else if (memcmp(buf, "NW PDN DEACT", 12) == 0) {// The network has deactivated a context
kevman 0:38ceb79fef03 129 call_cb = true;
kevman 0:38ceb79fef03 130 } else if (memcmp(buf, "ME PDN DEACT", 12) == 0) {// The mobile termination has deactivated a context.
kevman 0:38ceb79fef03 131 call_cb = true;
kevman 0:38ceb79fef03 132 }
kevman 0:38ceb79fef03 133
kevman 0:38ceb79fef03 134 if (call_cb) {
kevman 0:38ceb79fef03 135 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 136 }
kevman 0:38ceb79fef03 137 }
kevman 0:38ceb79fef03 138
kevman 0:38ceb79fef03 139 void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
kevman 0:38ceb79fef03 140 {
kevman 0:38ceb79fef03 141 RegistrationStatus reg_status = NotRegistered;
kevman 0:38ceb79fef03 142 int lac = -1, cell_id = -1, act = -1;
kevman 0:38ceb79fef03 143
kevman 0:38ceb79fef03 144 read_reg_params(type, reg_status, lac, cell_id, act);
kevman 0:38ceb79fef03 145
kevman 0:38ceb79fef03 146 #if MBED_CONF_MBED_TRACE_ENABLE
kevman 0:38ceb79fef03 147 switch (reg_status) {
kevman 0:38ceb79fef03 148 case NotRegistered:
kevman 0:38ceb79fef03 149 tr_warn("not registered");
kevman 0:38ceb79fef03 150 break;
kevman 0:38ceb79fef03 151 case RegistrationDenied:
kevman 0:38ceb79fef03 152 tr_warn("registration denied");
kevman 0:38ceb79fef03 153 break;
kevman 0:38ceb79fef03 154 case Unknown:
kevman 0:38ceb79fef03 155 tr_warn("registration status unknown");
kevman 0:38ceb79fef03 156 break;
kevman 0:38ceb79fef03 157 default:
kevman 0:38ceb79fef03 158 break;
kevman 0:38ceb79fef03 159 }
kevman 0:38ceb79fef03 160 #endif
kevman 0:38ceb79fef03 161
kevman 0:38ceb79fef03 162 if (_at.get_last_error() == NSAPI_ERROR_OK && _connection_status_cb) {
kevman 0:38ceb79fef03 163 tr_debug("stat: %d, lac: %d, cellID: %d, act: %d", reg_status, lac, cell_id, act);
kevman 0:38ceb79fef03 164 if (act != -1 && (RadioAccessTechnology)act != _current_act) {
kevman 0:38ceb79fef03 165 _current_act = (RadioAccessTechnology)act;
kevman 0:38ceb79fef03 166 _connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, _current_act);
kevman 0:38ceb79fef03 167 }
kevman 0:38ceb79fef03 168 if (reg_status != _reg_status) {
kevman 0:38ceb79fef03 169 _reg_status = reg_status;
kevman 0:38ceb79fef03 170 _connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, _reg_status);
kevman 0:38ceb79fef03 171 }
kevman 0:38ceb79fef03 172 if (cell_id != -1 && cell_id != _cell_id) {
kevman 0:38ceb79fef03 173 _cell_id = cell_id;
kevman 0:38ceb79fef03 174 _connection_status_cb((nsapi_event_t)CellularCellIDChanged, _cell_id);
kevman 0:38ceb79fef03 175 }
kevman 0:38ceb79fef03 176 }
kevman 0:38ceb79fef03 177 }
kevman 0:38ceb79fef03 178
kevman 0:38ceb79fef03 179 void AT_CellularNetwork::urc_creg()
kevman 0:38ceb79fef03 180 {
kevman 0:38ceb79fef03 181 tr_debug("urc_creg");
kevman 0:38ceb79fef03 182 read_reg_params_and_compare(C_REG);
kevman 0:38ceb79fef03 183 }
kevman 0:38ceb79fef03 184
kevman 0:38ceb79fef03 185 void AT_CellularNetwork::urc_cereg()
kevman 0:38ceb79fef03 186 {
kevman 0:38ceb79fef03 187 tr_debug("urc_cereg");
kevman 0:38ceb79fef03 188 read_reg_params_and_compare(C_EREG);
kevman 0:38ceb79fef03 189 }
kevman 0:38ceb79fef03 190
kevman 0:38ceb79fef03 191 void AT_CellularNetwork::urc_cgreg()
kevman 0:38ceb79fef03 192 {
kevman 0:38ceb79fef03 193 tr_debug("urc_cgreg");
kevman 0:38ceb79fef03 194 read_reg_params_and_compare(C_GREG);
kevman 0:38ceb79fef03 195 }
kevman 0:38ceb79fef03 196
kevman 0:38ceb79fef03 197 nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
kevman 0:38ceb79fef03 198 const char *username, const char *password)
kevman 0:38ceb79fef03 199 {
kevman 0:38ceb79fef03 200 free_credentials();
kevman 0:38ceb79fef03 201
kevman 0:38ceb79fef03 202 size_t len;
kevman 0:38ceb79fef03 203 if (apn && (len = strlen(apn)) > 0) {
kevman 0:38ceb79fef03 204 _apn = (char *)malloc(len * sizeof(char) + 1);
kevman 0:38ceb79fef03 205 if (_apn) {
kevman 0:38ceb79fef03 206 memcpy(_apn, apn, len + 1);
kevman 0:38ceb79fef03 207 } else {
kevman 0:38ceb79fef03 208 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 209 }
kevman 0:38ceb79fef03 210 }
kevman 0:38ceb79fef03 211
kevman 0:38ceb79fef03 212 if (username && (len = strlen(username)) > 0) {
kevman 0:38ceb79fef03 213 if (!is_supported(AT_CGAUTH)) { // APN authentication is needed with username/password
kevman 0:38ceb79fef03 214 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 215 }
kevman 0:38ceb79fef03 216 _uname = (char *)malloc(len * sizeof(char) + 1);
kevman 0:38ceb79fef03 217 if (_uname) {
kevman 0:38ceb79fef03 218 memcpy(_uname, username, len + 1);
kevman 0:38ceb79fef03 219 } else {
kevman 0:38ceb79fef03 220 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 221 }
kevman 0:38ceb79fef03 222 }
kevman 0:38ceb79fef03 223
kevman 0:38ceb79fef03 224 if (password && (len = strlen(password)) > 0) {
kevman 0:38ceb79fef03 225 _pwd = (char *)malloc(len * sizeof(char) + 1);
kevman 0:38ceb79fef03 226 if (_pwd) {
kevman 0:38ceb79fef03 227 memcpy(_pwd, password, len + 1);
kevman 0:38ceb79fef03 228 } else {
kevman 0:38ceb79fef03 229 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 230 }
kevman 0:38ceb79fef03 231 }
kevman 0:38ceb79fef03 232
kevman 0:38ceb79fef03 233 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 234 }
kevman 0:38ceb79fef03 235
kevman 0:38ceb79fef03 236 nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
kevman 0:38ceb79fef03 237 AuthenticationType type, const char *username, const char *password)
kevman 0:38ceb79fef03 238 {
kevman 0:38ceb79fef03 239 nsapi_error_t err = set_credentials(apn, username, password);
kevman 0:38ceb79fef03 240 if (err) {
kevman 0:38ceb79fef03 241 return err;
kevman 0:38ceb79fef03 242 }
kevman 0:38ceb79fef03 243
kevman 0:38ceb79fef03 244 _authentication_type = type;
kevman 0:38ceb79fef03 245
kevman 0:38ceb79fef03 246 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 247 }
kevman 0:38ceb79fef03 248
kevman 0:38ceb79fef03 249 nsapi_error_t AT_CellularNetwork::connect(const char *apn,
kevman 0:38ceb79fef03 250 const char *username, const char *password)
kevman 0:38ceb79fef03 251 {
kevman 0:38ceb79fef03 252 nsapi_error_t err = set_credentials(apn, username, password);
kevman 0:38ceb79fef03 253 if (err) {
kevman 0:38ceb79fef03 254 return err;
kevman 0:38ceb79fef03 255 }
kevman 0:38ceb79fef03 256
kevman 0:38ceb79fef03 257 return connect();
kevman 0:38ceb79fef03 258 }
kevman 0:38ceb79fef03 259
kevman 0:38ceb79fef03 260 nsapi_error_t AT_CellularNetwork::delete_current_context()
kevman 0:38ceb79fef03 261 {
kevman 0:38ceb79fef03 262 tr_info("Delete context %d", _cid);
kevman 0:38ceb79fef03 263 _at.clear_error();
kevman 0:38ceb79fef03 264 _at.cmd_start("AT+CGDCONT=");
kevman 0:38ceb79fef03 265 _at.write_int(_cid);
kevman 0:38ceb79fef03 266 _at.cmd_stop();
kevman 0:38ceb79fef03 267 _at.resp_start();
kevman 0:38ceb79fef03 268 _at.resp_stop();
kevman 0:38ceb79fef03 269
kevman 0:38ceb79fef03 270 if (_at.get_last_error() == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 271 _cid = -1;
kevman 0:38ceb79fef03 272 _new_context_set = false;
kevman 0:38ceb79fef03 273 }
kevman 0:38ceb79fef03 274
kevman 0:38ceb79fef03 275 return _at.get_last_error();
kevman 0:38ceb79fef03 276 }
kevman 0:38ceb79fef03 277
kevman 0:38ceb79fef03 278 nsapi_error_t AT_CellularNetwork::activate_context()
kevman 0:38ceb79fef03 279 {
kevman 0:38ceb79fef03 280 _at.lock();
kevman 0:38ceb79fef03 281
kevman 0:38ceb79fef03 282 nsapi_error_t err = NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 283
kevman 0:38ceb79fef03 284 // try to find or create context with suitable stack
kevman 0:38ceb79fef03 285 if (!get_context()) {
kevman 0:38ceb79fef03 286 err = NSAPI_ERROR_NO_CONNECTION;
kevman 0:38ceb79fef03 287 }
kevman 0:38ceb79fef03 288
kevman 0:38ceb79fef03 289 if (err != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 290 _at.unlock();
kevman 0:38ceb79fef03 291 tr_error("Failed to activate network context! (%d)", err);
kevman 0:38ceb79fef03 292 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 293
kevman 0:38ceb79fef03 294 return err;
kevman 0:38ceb79fef03 295 }
kevman 0:38ceb79fef03 296
kevman 0:38ceb79fef03 297 // do check for stack to validate that we have support for stack
kevman 0:38ceb79fef03 298 _stack = get_stack();
kevman 0:38ceb79fef03 299 if (!_stack) {
kevman 0:38ceb79fef03 300 tr_error("No cellular stack!");
kevman 0:38ceb79fef03 301 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 302 }
kevman 0:38ceb79fef03 303
kevman 0:38ceb79fef03 304 _is_context_active = false;
kevman 0:38ceb79fef03 305 _at.cmd_start("AT+CGACT?");
kevman 0:38ceb79fef03 306 _at.cmd_stop();
kevman 0:38ceb79fef03 307 _at.resp_start("+CGACT:");
kevman 0:38ceb79fef03 308 while (_at.info_resp()) {
kevman 0:38ceb79fef03 309 int context_id = _at.read_int();
kevman 0:38ceb79fef03 310 int context_activation_state = _at.read_int();
kevman 0:38ceb79fef03 311 if (context_id == _cid && context_activation_state == 1) {
kevman 0:38ceb79fef03 312 _is_context_active = true;
kevman 0:38ceb79fef03 313 }
kevman 0:38ceb79fef03 314 }
kevman 0:38ceb79fef03 315 _at.resp_stop();
kevman 0:38ceb79fef03 316
kevman 0:38ceb79fef03 317 if (!_is_context_active) {
kevman 0:38ceb79fef03 318 // authenticate before activating or modifying context
kevman 0:38ceb79fef03 319 nsapi_error_t err = do_user_authentication();
kevman 0:38ceb79fef03 320 if (err != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 321 tr_error("Cellular authentication failed!");
kevman 0:38ceb79fef03 322 return err;
kevman 0:38ceb79fef03 323 }
kevman 0:38ceb79fef03 324
kevman 0:38ceb79fef03 325 tr_info("Activate PDP context %d", _cid);
kevman 0:38ceb79fef03 326 _at.cmd_start("AT+CGACT=1,");
kevman 0:38ceb79fef03 327 _at.write_int(_cid);
kevman 0:38ceb79fef03 328 _at.cmd_stop();
kevman 0:38ceb79fef03 329 _at.resp_start();
kevman 0:38ceb79fef03 330 _at.resp_stop();
kevman 0:38ceb79fef03 331 }
kevman 0:38ceb79fef03 332
kevman 0:38ceb79fef03 333 err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
kevman 0:38ceb79fef03 334
kevman 0:38ceb79fef03 335 // If new PDP context was created and failed to activate, delete it
kevman 0:38ceb79fef03 336 if (err != NSAPI_ERROR_OK && _new_context_set) {
kevman 0:38ceb79fef03 337 delete_current_context();
kevman 0:38ceb79fef03 338 } else if (err == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 339 _is_context_active = true;
kevman 0:38ceb79fef03 340 }
kevman 0:38ceb79fef03 341
kevman 0:38ceb79fef03 342 _at.unlock();
kevman 0:38ceb79fef03 343
kevman 0:38ceb79fef03 344 return err;
kevman 0:38ceb79fef03 345 }
kevman 0:38ceb79fef03 346
kevman 0:38ceb79fef03 347 nsapi_error_t AT_CellularNetwork::connect()
kevman 0:38ceb79fef03 348 {
kevman 0:38ceb79fef03 349 call_network_cb(NSAPI_STATUS_CONNECTING);
kevman 0:38ceb79fef03 350
kevman 0:38ceb79fef03 351 nsapi_error_t err = NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 352 if (!_is_context_active) {
kevman 0:38ceb79fef03 353 err = activate_context();
kevman 0:38ceb79fef03 354 }
kevman 0:38ceb79fef03 355 if (err) {
kevman 0:38ceb79fef03 356 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 357 return err;
kevman 0:38ceb79fef03 358 }
kevman 0:38ceb79fef03 359
kevman 0:38ceb79fef03 360 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 361 _at.lock();
kevman 0:38ceb79fef03 362 err = open_data_channel();
kevman 0:38ceb79fef03 363 _at.unlock();
kevman 0:38ceb79fef03 364 if (err != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 365 tr_error("Failed to open data channel!");
kevman 0:38ceb79fef03 366 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 367 return err;
kevman 0:38ceb79fef03 368 }
kevman 0:38ceb79fef03 369 #else
kevman 0:38ceb79fef03 370 // additional urc to get better disconnect info for application. Not critical so not returning an error in case of failure
kevman 0:38ceb79fef03 371 err = _at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
kevman 0:38ceb79fef03 372 if (err == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 373 _at.lock();
kevman 0:38ceb79fef03 374 _at.cmd_start("AT+CGEREP=1");
kevman 0:38ceb79fef03 375 _at.cmd_stop();
kevman 0:38ceb79fef03 376 _at.resp_start();
kevman 0:38ceb79fef03 377 _at.resp_stop();
kevman 0:38ceb79fef03 378 _at.unlock();
kevman 0:38ceb79fef03 379 }
kevman 0:38ceb79fef03 380
kevman 0:38ceb79fef03 381 call_network_cb(NSAPI_STATUS_GLOBAL_UP);
kevman 0:38ceb79fef03 382 #endif
kevman 0:38ceb79fef03 383
kevman 0:38ceb79fef03 384 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 385 }
kevman 0:38ceb79fef03 386
kevman 0:38ceb79fef03 387 nsapi_error_t AT_CellularNetwork::open_data_channel()
kevman 0:38ceb79fef03 388 {
kevman 0:38ceb79fef03 389 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 390 tr_info("Open data channel in PPP mode");
kevman 0:38ceb79fef03 391 if (is_supported(AT_CGDATA)) {
kevman 0:38ceb79fef03 392 _at.cmd_start("AT+CGDATA=\"PPP\",");
kevman 0:38ceb79fef03 393 _at.write_int(_cid);
kevman 0:38ceb79fef03 394 } else {
kevman 0:38ceb79fef03 395 MBED_ASSERT(_cid >= 0 && _cid <= 99);
kevman 0:38ceb79fef03 396 char cmd_buf[sizeof("ATD*99***xx#")];
kevman 0:38ceb79fef03 397 std::sprintf(cmd_buf, "ATD*99***%d#", _cid);
kevman 0:38ceb79fef03 398 _at.cmd_start(cmd_buf);
kevman 0:38ceb79fef03 399 }
kevman 0:38ceb79fef03 400 _at.cmd_stop();
kevman 0:38ceb79fef03 401
kevman 0:38ceb79fef03 402 _at.resp_start("CONNECT", true);
kevman 0:38ceb79fef03 403 if (_at.get_last_error()) {
kevman 0:38ceb79fef03 404 tr_error("Failed to CONNECT");
kevman 0:38ceb79fef03 405 return _at.get_last_error();
kevman 0:38ceb79fef03 406 }
kevman 0:38ceb79fef03 407
kevman 0:38ceb79fef03 408 _at.set_is_filehandle_usable(false);
kevman 0:38ceb79fef03 409
kevman 0:38ceb79fef03 410 /* Initialize PPP
kevman 0:38ceb79fef03 411 * If blocking: mbed_ppp_init() is a blocking call, it will block until
kevman 0:38ceb79fef03 412 connected, or timeout after 30 seconds*/
kevman 0:38ceb79fef03 413 return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), NULL, NULL, _ip_stack_type);
kevman 0:38ceb79fef03 414 #else
kevman 0:38ceb79fef03 415 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 416 #endif // #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 417 }
kevman 0:38ceb79fef03 418
kevman 0:38ceb79fef03 419 /**
kevman 0:38ceb79fef03 420 * User initiated disconnect
kevman 0:38ceb79fef03 421 *
kevman 0:38ceb79fef03 422 * Disconnects from PPP connection only and brings down the underlying network
kevman 0:38ceb79fef03 423 * interface
kevman 0:38ceb79fef03 424 */
kevman 0:38ceb79fef03 425 nsapi_error_t AT_CellularNetwork::disconnect()
kevman 0:38ceb79fef03 426 {
kevman 0:38ceb79fef03 427 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 428 nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
kevman 0:38ceb79fef03 429 // after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
kevman 0:38ceb79fef03 430 // will set the correct sigio and nonblocking
kevman 0:38ceb79fef03 431 _at.lock();
kevman 0:38ceb79fef03 432 _at.set_file_handle(_at.get_file_handle());
kevman 0:38ceb79fef03 433 _at.set_is_filehandle_usable(true);
kevman 0:38ceb79fef03 434 _at.unlock();
kevman 0:38ceb79fef03 435 return err;
kevman 0:38ceb79fef03 436 #else
kevman 0:38ceb79fef03 437 _at.lock();
kevman 0:38ceb79fef03 438
kevman 0:38ceb79fef03 439 _is_context_active = false;
kevman 0:38ceb79fef03 440 size_t active_contexts_count = 0;
kevman 0:38ceb79fef03 441 _at.cmd_start("AT+CGACT?");
kevman 0:38ceb79fef03 442 _at.cmd_stop();
kevman 0:38ceb79fef03 443 _at.resp_start("+CGACT:");
kevman 0:38ceb79fef03 444 while (_at.info_resp()) {
kevman 0:38ceb79fef03 445 int context_id = _at.read_int();
kevman 0:38ceb79fef03 446 int context_activation_state = _at.read_int();
kevman 0:38ceb79fef03 447 if (context_activation_state == 1) {
kevman 0:38ceb79fef03 448 active_contexts_count++;
kevman 0:38ceb79fef03 449 if (context_id == _cid) {
kevman 0:38ceb79fef03 450 _is_context_active = true;
kevman 0:38ceb79fef03 451 }
kevman 0:38ceb79fef03 452 }
kevman 0:38ceb79fef03 453 }
kevman 0:38ceb79fef03 454 _at.resp_stop();
kevman 0:38ceb79fef03 455
kevman 0:38ceb79fef03 456 // 3GPP TS 27.007:
kevman 0:38ceb79fef03 457 // For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR
kevman 0:38ceb79fef03 458 if (_is_context_active && (_current_act < RAT_E_UTRAN || active_contexts_count > 1)) {
kevman 0:38ceb79fef03 459 _at.cmd_start("AT+CGACT=0,");
kevman 0:38ceb79fef03 460 _at.write_int(_cid);
kevman 0:38ceb79fef03 461 _at.cmd_stop();
kevman 0:38ceb79fef03 462 _at.resp_start();
kevman 0:38ceb79fef03 463 _at.resp_stop();
kevman 0:38ceb79fef03 464 }
kevman 0:38ceb79fef03 465
kevman 0:38ceb79fef03 466 _at.restore_at_timeout();
kevman 0:38ceb79fef03 467
kevman 0:38ceb79fef03 468 _at.remove_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
kevman 0:38ceb79fef03 469 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 470
kevman 0:38ceb79fef03 471 return _at.unlock_return_error();
kevman 0:38ceb79fef03 472 #endif
kevman 0:38ceb79fef03 473 }
kevman 0:38ceb79fef03 474
kevman 0:38ceb79fef03 475 void AT_CellularNetwork::call_network_cb(nsapi_connection_status_t status)
kevman 0:38ceb79fef03 476 {
kevman 0:38ceb79fef03 477 if (_connect_status != status) {
kevman 0:38ceb79fef03 478 _connect_status = status;
kevman 0:38ceb79fef03 479 if (_connection_status_cb) {
kevman 0:38ceb79fef03 480 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
kevman 0:38ceb79fef03 481 }
kevman 0:38ceb79fef03 482 }
kevman 0:38ceb79fef03 483 }
kevman 0:38ceb79fef03 484
kevman 0:38ceb79fef03 485 void AT_CellularNetwork::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
kevman 0:38ceb79fef03 486 {
kevman 0:38ceb79fef03 487 _connection_status_cb = status_cb;
kevman 0:38ceb79fef03 488 }
kevman 0:38ceb79fef03 489
kevman 0:38ceb79fef03 490 nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const
kevman 0:38ceb79fef03 491 {
kevman 0:38ceb79fef03 492 return _connect_status;
kevman 0:38ceb79fef03 493 }
kevman 0:38ceb79fef03 494
kevman 0:38ceb79fef03 495 nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking)
kevman 0:38ceb79fef03 496 {
kevman 0:38ceb79fef03 497 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 498 return nsapi_ppp_set_blocking(blocking);
kevman 0:38ceb79fef03 499 #else
kevman 0:38ceb79fef03 500 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 501 #endif
kevman 0:38ceb79fef03 502 }
kevman 0:38ceb79fef03 503
kevman 0:38ceb79fef03 504 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 505 void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter)
kevman 0:38ceb79fef03 506 {
kevman 0:38ceb79fef03 507 _connect_status = (nsapi_connection_status_t)parameter;
kevman 0:38ceb79fef03 508
kevman 0:38ceb79fef03 509 if (_connection_status_cb) {
kevman 0:38ceb79fef03 510 _connection_status_cb(event, parameter);
kevman 0:38ceb79fef03 511 }
kevman 0:38ceb79fef03 512 }
kevman 0:38ceb79fef03 513 #endif
kevman 0:38ceb79fef03 514
kevman 0:38ceb79fef03 515 nsapi_error_t AT_CellularNetwork::do_user_authentication()
kevman 0:38ceb79fef03 516 {
kevman 0:38ceb79fef03 517 // if user has defined user name and password we need to call CGAUTH before activating or modifying context
kevman 0:38ceb79fef03 518 if (_pwd && _uname) {
kevman 0:38ceb79fef03 519 if (!is_supported(AT_CGAUTH)) {
kevman 0:38ceb79fef03 520 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 521 }
kevman 0:38ceb79fef03 522 _at.cmd_start("AT+CGAUTH=");
kevman 0:38ceb79fef03 523 _at.write_int(_cid);
kevman 0:38ceb79fef03 524 _at.write_int(_authentication_type);
kevman 0:38ceb79fef03 525 _at.write_string(_uname);
kevman 0:38ceb79fef03 526 _at.write_string(_pwd);
kevman 0:38ceb79fef03 527 _at.cmd_stop();
kevman 0:38ceb79fef03 528 _at.resp_start();
kevman 0:38ceb79fef03 529 _at.resp_stop();
kevman 0:38ceb79fef03 530 if (_at.get_last_error() != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 531 return NSAPI_ERROR_AUTH_FAILURE;
kevman 0:38ceb79fef03 532 }
kevman 0:38ceb79fef03 533 }
kevman 0:38ceb79fef03 534
kevman 0:38ceb79fef03 535 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 536 }
kevman 0:38ceb79fef03 537
kevman 0:38ceb79fef03 538 bool AT_CellularNetwork::set_new_context(int cid)
kevman 0:38ceb79fef03 539 {
kevman 0:38ceb79fef03 540 nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
kevman 0:38ceb79fef03 541
kevman 0:38ceb79fef03 542 if (tmp_stack == DEFAULT_STACK) {
kevman 0:38ceb79fef03 543 bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
kevman 0:38ceb79fef03 544 bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
kevman 0:38ceb79fef03 545
kevman 0:38ceb79fef03 546 if (modem_supports_ipv6 && modem_supports_ipv4) {
kevman 0:38ceb79fef03 547 tmp_stack = IPV4V6_STACK;
kevman 0:38ceb79fef03 548 } else if (modem_supports_ipv6) {
kevman 0:38ceb79fef03 549 tmp_stack = IPV6_STACK;
kevman 0:38ceb79fef03 550 } else if (modem_supports_ipv4) {
kevman 0:38ceb79fef03 551 tmp_stack = IPV4_STACK;
kevman 0:38ceb79fef03 552 }
kevman 0:38ceb79fef03 553 }
kevman 0:38ceb79fef03 554
kevman 0:38ceb79fef03 555 char pdp_type[8 + 1] = {0};
kevman 0:38ceb79fef03 556
kevman 0:38ceb79fef03 557 switch (tmp_stack) {
kevman 0:38ceb79fef03 558 case IPV4_STACK:
kevman 0:38ceb79fef03 559 strncpy(pdp_type, "IP", sizeof(pdp_type));
kevman 0:38ceb79fef03 560 break;
kevman 0:38ceb79fef03 561 case IPV6_STACK:
kevman 0:38ceb79fef03 562 strncpy(pdp_type, "IPV6", sizeof(pdp_type));
kevman 0:38ceb79fef03 563 break;
kevman 0:38ceb79fef03 564 case IPV4V6_STACK:
kevman 0:38ceb79fef03 565 strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4
kevman 0:38ceb79fef03 566 break;
kevman 0:38ceb79fef03 567 default:
kevman 0:38ceb79fef03 568 break;
kevman 0:38ceb79fef03 569 }
kevman 0:38ceb79fef03 570
kevman 0:38ceb79fef03 571 //apn: "If the value is null or omitted, then the subscription value will be requested."
kevman 0:38ceb79fef03 572 bool success = false;
kevman 0:38ceb79fef03 573 _at.cmd_start("AT+CGDCONT=");
kevman 0:38ceb79fef03 574 _at.write_int(cid);
kevman 0:38ceb79fef03 575 _at.write_string(pdp_type);
kevman 0:38ceb79fef03 576 _at.write_string(_apn);
kevman 0:38ceb79fef03 577 _at.cmd_stop();
kevman 0:38ceb79fef03 578 _at.resp_start();
kevman 0:38ceb79fef03 579 _at.resp_stop();
kevman 0:38ceb79fef03 580 success = (_at.get_last_error() == NSAPI_ERROR_OK);
kevman 0:38ceb79fef03 581
kevman 0:38ceb79fef03 582 // Fall back to ipv4
kevman 0:38ceb79fef03 583 if (!success && tmp_stack == IPV4V6_STACK) {
kevman 0:38ceb79fef03 584 tmp_stack = IPV4_STACK;
kevman 0:38ceb79fef03 585 _at.cmd_start("AT+FCLASS=0;+CGDCONT=");
kevman 0:38ceb79fef03 586 _at.write_int(cid);
kevman 0:38ceb79fef03 587 _at.write_string("IP");
kevman 0:38ceb79fef03 588 _at.write_string(_apn);
kevman 0:38ceb79fef03 589 _at.cmd_stop();
kevman 0:38ceb79fef03 590 _at.resp_start();
kevman 0:38ceb79fef03 591 _at.resp_stop();
kevman 0:38ceb79fef03 592 success = (_at.get_last_error() == NSAPI_ERROR_OK);
kevman 0:38ceb79fef03 593 }
kevman 0:38ceb79fef03 594
kevman 0:38ceb79fef03 595 if (success) {
kevman 0:38ceb79fef03 596 _ip_stack_type = tmp_stack;
kevman 0:38ceb79fef03 597 _cid = cid;
kevman 0:38ceb79fef03 598 _new_context_set = true;
kevman 0:38ceb79fef03 599 tr_info("New PDP context id %d was created", _cid);
kevman 0:38ceb79fef03 600 }
kevman 0:38ceb79fef03 601
kevman 0:38ceb79fef03 602 return success;
kevman 0:38ceb79fef03 603 }
kevman 0:38ceb79fef03 604
kevman 0:38ceb79fef03 605 bool AT_CellularNetwork::get_context()
kevman 0:38ceb79fef03 606 {
kevman 0:38ceb79fef03 607 if (_apn) {
kevman 0:38ceb79fef03 608 tr_debug("APN in use: %s", _apn);
kevman 0:38ceb79fef03 609 } else {
kevman 0:38ceb79fef03 610 tr_debug("NO APN");
kevman 0:38ceb79fef03 611 }
kevman 0:38ceb79fef03 612
kevman 0:38ceb79fef03 613 _at.cmd_start("AT+CGDCONT?");
kevman 0:38ceb79fef03 614 _at.cmd_stop();
kevman 0:38ceb79fef03 615 _at.resp_start("+CGDCONT:");
kevman 0:38ceb79fef03 616 _cid = -1;
kevman 0:38ceb79fef03 617 int cid_max = 0; // needed when creating new context
kevman 0:38ceb79fef03 618 char apn[MAX_ACCESSPOINT_NAME_LENGTH];
kevman 0:38ceb79fef03 619 int apn_len = 0;
kevman 0:38ceb79fef03 620
kevman 0:38ceb79fef03 621 bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
kevman 0:38ceb79fef03 622 bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
kevman 0:38ceb79fef03 623
kevman 0:38ceb79fef03 624 while (_at.info_resp()) {
kevman 0:38ceb79fef03 625 int cid = _at.read_int();
kevman 0:38ceb79fef03 626 if (cid > cid_max) {
kevman 0:38ceb79fef03 627 cid_max = cid;
kevman 0:38ceb79fef03 628 }
kevman 0:38ceb79fef03 629 char pdp_type_from_context[10];
kevman 0:38ceb79fef03 630 int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
kevman 0:38ceb79fef03 631 if (pdp_type_len > 0) {
kevman 0:38ceb79fef03 632 apn_len = _at.read_string(apn, sizeof(apn) - 1);
kevman 0:38ceb79fef03 633 if (apn_len >= 0) {
kevman 0:38ceb79fef03 634 if (_apn && (strcmp(apn, _apn) != 0)) {
kevman 0:38ceb79fef03 635 continue;
kevman 0:38ceb79fef03 636 }
kevman 0:38ceb79fef03 637 nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
kevman 0:38ceb79fef03 638 // Accept dual PDP context for IPv4/IPv6 only modems
kevman 0:38ceb79fef03 639 if (pdp_stack != DEFAULT_STACK && (get_modem_stack_type(pdp_stack) || pdp_stack == IPV4V6_STACK)) {
kevman 0:38ceb79fef03 640 if (_ip_stack_type_requested == IPV4_STACK) {
kevman 0:38ceb79fef03 641 if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
kevman 0:38ceb79fef03 642 _ip_stack_type = _ip_stack_type_requested;
kevman 0:38ceb79fef03 643 _cid = cid;
kevman 0:38ceb79fef03 644 break;
kevman 0:38ceb79fef03 645 }
kevman 0:38ceb79fef03 646 } else if (_ip_stack_type_requested == IPV6_STACK) {
kevman 0:38ceb79fef03 647 if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
kevman 0:38ceb79fef03 648 _ip_stack_type = _ip_stack_type_requested;
kevman 0:38ceb79fef03 649 _cid = cid;
kevman 0:38ceb79fef03 650 break;
kevman 0:38ceb79fef03 651 }
kevman 0:38ceb79fef03 652 } else {
kevman 0:38ceb79fef03 653 // requested dual stack or stack is not specified
kevman 0:38ceb79fef03 654 // If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6.
kevman 0:38ceb79fef03 655 if (pdp_stack == IPV4V6_STACK) {
kevman 0:38ceb79fef03 656 if (modem_supports_ipv6) {
kevman 0:38ceb79fef03 657 _ip_stack_type = IPV6_STACK;
kevman 0:38ceb79fef03 658 _cid = cid;
kevman 0:38ceb79fef03 659 break;
kevman 0:38ceb79fef03 660 } else if (modem_supports_ipv4) {
kevman 0:38ceb79fef03 661 _ip_stack_type = IPV4_STACK;
kevman 0:38ceb79fef03 662 _cid = cid;
kevman 0:38ceb79fef03 663 break;
kevman 0:38ceb79fef03 664 }
kevman 0:38ceb79fef03 665 // If PDP is IPV4 or IPV6 they are already checked if supported
kevman 0:38ceb79fef03 666 } else {
kevman 0:38ceb79fef03 667 _ip_stack_type = pdp_stack;
kevman 0:38ceb79fef03 668 _cid = cid;
kevman 0:38ceb79fef03 669
kevman 0:38ceb79fef03 670 if (pdp_stack == IPV6_STACK) {
kevman 0:38ceb79fef03 671 break;
kevman 0:38ceb79fef03 672 }
kevman 0:38ceb79fef03 673 if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) {
kevman 0:38ceb79fef03 674 break;
kevman 0:38ceb79fef03 675 }
kevman 0:38ceb79fef03 676 }
kevman 0:38ceb79fef03 677 }
kevman 0:38ceb79fef03 678 }
kevman 0:38ceb79fef03 679 }
kevman 0:38ceb79fef03 680 }
kevman 0:38ceb79fef03 681 }
kevman 0:38ceb79fef03 682 _at.resp_stop();
kevman 0:38ceb79fef03 683 if (_cid == -1) { // no suitable context was found so create a new one
kevman 0:38ceb79fef03 684 if (!set_new_context(cid_max + 1)) {
kevman 0:38ceb79fef03 685 return false;
kevman 0:38ceb79fef03 686 }
kevman 0:38ceb79fef03 687 }
kevman 0:38ceb79fef03 688
kevman 0:38ceb79fef03 689 // save the apn
kevman 0:38ceb79fef03 690 if (apn_len > 0 && !_apn) {
kevman 0:38ceb79fef03 691 _apn = (char *)malloc(apn_len * sizeof(char) + 1);
kevman 0:38ceb79fef03 692 if (_apn) {
kevman 0:38ceb79fef03 693 memcpy(_apn, apn, apn_len + 1);
kevman 0:38ceb79fef03 694 } else {
kevman 0:38ceb79fef03 695 return false;
kevman 0:38ceb79fef03 696 }
kevman 0:38ceb79fef03 697 }
kevman 0:38ceb79fef03 698
kevman 0:38ceb79fef03 699 tr_debug("Context id %d", _cid);
kevman 0:38ceb79fef03 700 return true;
kevman 0:38ceb79fef03 701 }
kevman 0:38ceb79fef03 702
kevman 0:38ceb79fef03 703 nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type)
kevman 0:38ceb79fef03 704 {
kevman 0:38ceb79fef03 705 nsapi_ip_stack_t stack = DEFAULT_STACK;
kevman 0:38ceb79fef03 706 int len = strlen(pdp_type);
kevman 0:38ceb79fef03 707
kevman 0:38ceb79fef03 708 if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
kevman 0:38ceb79fef03 709 stack = IPV4V6_STACK;
kevman 0:38ceb79fef03 710 } else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
kevman 0:38ceb79fef03 711 stack = IPV6_STACK;
kevman 0:38ceb79fef03 712 } else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
kevman 0:38ceb79fef03 713 stack = IPV4_STACK;
kevman 0:38ceb79fef03 714 }
kevman 0:38ceb79fef03 715 return stack;
kevman 0:38ceb79fef03 716 }
kevman 0:38ceb79fef03 717
kevman 0:38ceb79fef03 718 nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
kevman 0:38ceb79fef03 719 {
kevman 0:38ceb79fef03 720 int index = (int)type;
kevman 0:38ceb79fef03 721 MBED_ASSERT(index >= 0 && index < C_MAX);
kevman 0:38ceb79fef03 722
kevman 0:38ceb79fef03 723 RegistrationMode mode = has_registration(type);
kevman 0:38ceb79fef03 724 if (mode == RegistrationModeDisable) {
kevman 0:38ceb79fef03 725 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 726 } else {
kevman 0:38ceb79fef03 727 _at.lock();
kevman 0:38ceb79fef03 728 if (urc_on) {
kevman 0:38ceb79fef03 729 _at.cmd_start(at_reg[index].cmd);
kevman 0:38ceb79fef03 730 const uint8_t ch_eq = '=';
kevman 0:38ceb79fef03 731 _at.write_bytes(&ch_eq, 1);
kevman 0:38ceb79fef03 732 _at.write_int((int)mode);
kevman 0:38ceb79fef03 733 _at.cmd_stop();
kevman 0:38ceb79fef03 734 } else {
kevman 0:38ceb79fef03 735 _at.cmd_start(at_reg[index].cmd);
kevman 0:38ceb79fef03 736 _at.write_string("=0", false);
kevman 0:38ceb79fef03 737 _at.cmd_stop();
kevman 0:38ceb79fef03 738 }
kevman 0:38ceb79fef03 739
kevman 0:38ceb79fef03 740 _at.resp_start();
kevman 0:38ceb79fef03 741 _at.resp_stop();
kevman 0:38ceb79fef03 742 return _at.unlock_return_error();
kevman 0:38ceb79fef03 743 }
kevman 0:38ceb79fef03 744 }
kevman 0:38ceb79fef03 745
kevman 0:38ceb79fef03 746 nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode &mode)
kevman 0:38ceb79fef03 747 {
kevman 0:38ceb79fef03 748 _at.lock();
kevman 0:38ceb79fef03 749 _at.cmd_start("AT+COPS?");
kevman 0:38ceb79fef03 750 _at.cmd_stop();
kevman 0:38ceb79fef03 751 _at.resp_start("+COPS:");
kevman 0:38ceb79fef03 752 mode = (NWRegisteringMode)_at.read_int();
kevman 0:38ceb79fef03 753 _at.resp_stop();
kevman 0:38ceb79fef03 754
kevman 0:38ceb79fef03 755 return _at.unlock_return_error();
kevman 0:38ceb79fef03 756 }
kevman 0:38ceb79fef03 757
kevman 0:38ceb79fef03 758 nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
kevman 0:38ceb79fef03 759 {
kevman 0:38ceb79fef03 760 _at.lock();
kevman 0:38ceb79fef03 761
kevman 0:38ceb79fef03 762 if (!plmn) {
kevman 0:38ceb79fef03 763 tr_debug("Automatic network registration");
kevman 0:38ceb79fef03 764 _at.cmd_start("AT+COPS?");
kevman 0:38ceb79fef03 765 _at.cmd_stop();
kevman 0:38ceb79fef03 766 _at.resp_start("+COPS:");
kevman 0:38ceb79fef03 767 int mode = _at.read_int();
kevman 0:38ceb79fef03 768 _at.resp_stop();
kevman 0:38ceb79fef03 769 if (mode != 0) {
kevman 0:38ceb79fef03 770 _at.clear_error();
kevman 0:38ceb79fef03 771 _at.cmd_start("AT+COPS=0");
kevman 0:38ceb79fef03 772 _at.cmd_stop();
kevman 0:38ceb79fef03 773 _at.resp_start();
kevman 0:38ceb79fef03 774 _at.resp_stop();
kevman 0:38ceb79fef03 775 }
kevman 0:38ceb79fef03 776 } else {
kevman 0:38ceb79fef03 777 tr_debug("Manual network registration to %s", plmn);
kevman 0:38ceb79fef03 778 _at.cmd_start("AT+COPS=4,2,");
kevman 0:38ceb79fef03 779 _at.write_string(plmn);
kevman 0:38ceb79fef03 780 _at.cmd_stop();
kevman 0:38ceb79fef03 781 _at.resp_start();
kevman 0:38ceb79fef03 782 _at.resp_stop();
kevman 0:38ceb79fef03 783 }
kevman 0:38ceb79fef03 784
kevman 0:38ceb79fef03 785 return _at.unlock_return_error();
kevman 0:38ceb79fef03 786 }
kevman 0:38ceb79fef03 787
kevman 0:38ceb79fef03 788 void AT_CellularNetwork::read_reg_params(RegistrationType type, RegistrationStatus &reg_status, int &lac, int &cell_id, int &act)
kevman 0:38ceb79fef03 789 {
kevman 0:38ceb79fef03 790 const int LAC_LENGTH = 5, CELL_ID_LENGTH = 9;
kevman 0:38ceb79fef03 791 char lac_string[LAC_LENGTH] = {0}, cell_id_string[CELL_ID_LENGTH] = {0};
kevman 0:38ceb79fef03 792 bool lac_read = false, cell_id_read = false;
kevman 0:38ceb79fef03 793
kevman 0:38ceb79fef03 794 reg_status = (RegistrationStatus)_at.read_int();
kevman 0:38ceb79fef03 795
kevman 0:38ceb79fef03 796 int len = _at.read_string(lac_string, LAC_LENGTH);
kevman 0:38ceb79fef03 797 if (memcmp(lac_string, "ffff", LAC_LENGTH - 1) && len >= 0) {
kevman 0:38ceb79fef03 798 lac_read = true;
kevman 0:38ceb79fef03 799 }
kevman 0:38ceb79fef03 800
kevman 0:38ceb79fef03 801 len = _at.read_string(cell_id_string, CELL_ID_LENGTH);
kevman 0:38ceb79fef03 802 if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH - 1) && len >= 0) {
kevman 0:38ceb79fef03 803 cell_id_read = true;
kevman 0:38ceb79fef03 804 }
kevman 0:38ceb79fef03 805
kevman 0:38ceb79fef03 806 act = _at.read_int();
kevman 0:38ceb79fef03 807
kevman 0:38ceb79fef03 808 if (lac_read) {
kevman 0:38ceb79fef03 809 lac = hex_str_to_int(lac_string, LAC_LENGTH);
kevman 0:38ceb79fef03 810 tr_debug("lac %s %d", lac_string, lac);
kevman 0:38ceb79fef03 811 }
kevman 0:38ceb79fef03 812
kevman 0:38ceb79fef03 813 if (cell_id_read) {
kevman 0:38ceb79fef03 814 cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH);
kevman 0:38ceb79fef03 815 tr_debug("cell_id %s %d", cell_id_string, cell_id);
kevman 0:38ceb79fef03 816 }
kevman 0:38ceb79fef03 817 }
kevman 0:38ceb79fef03 818
kevman 0:38ceb79fef03 819 nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status)
kevman 0:38ceb79fef03 820 {
kevman 0:38ceb79fef03 821 int i = (int)type;
kevman 0:38ceb79fef03 822 MBED_ASSERT(i >= 0 && i < C_MAX);
kevman 0:38ceb79fef03 823
kevman 0:38ceb79fef03 824 if (has_registration(at_reg[i].type) == RegistrationModeDisable) {
kevman 0:38ceb79fef03 825 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 826 }
kevman 0:38ceb79fef03 827
kevman 0:38ceb79fef03 828 _at.lock();
kevman 0:38ceb79fef03 829
kevman 0:38ceb79fef03 830 const char *rsp[] = { "+CEREG:", "+CGREG:", "+CREG:"};
kevman 0:38ceb79fef03 831 _at.cmd_start(at_reg[i].cmd);
kevman 0:38ceb79fef03 832 _at.write_string("?", false);
kevman 0:38ceb79fef03 833 _at.cmd_stop();
kevman 0:38ceb79fef03 834 _at.resp_start(rsp[i]);
kevman 0:38ceb79fef03 835
kevman 0:38ceb79fef03 836 (void)_at.read_int(); // ignore urc mode subparam
kevman 0:38ceb79fef03 837 int lac = -1, cell_id = -1, act = -1;
kevman 0:38ceb79fef03 838 read_reg_params(type, status, lac, cell_id, act);
kevman 0:38ceb79fef03 839 _at.resp_stop();
kevman 0:38ceb79fef03 840 _reg_status = status;
kevman 0:38ceb79fef03 841
kevman 0:38ceb79fef03 842 if (cell_id != -1) {
kevman 0:38ceb79fef03 843 _cell_id = cell_id;
kevman 0:38ceb79fef03 844 }
kevman 0:38ceb79fef03 845 if (act != -1) {
kevman 0:38ceb79fef03 846 _current_act = (RadioAccessTechnology)act;
kevman 0:38ceb79fef03 847 }
kevman 0:38ceb79fef03 848
kevman 0:38ceb79fef03 849 return _at.unlock_return_error();
kevman 0:38ceb79fef03 850 }
kevman 0:38ceb79fef03 851
kevman 0:38ceb79fef03 852 nsapi_error_t AT_CellularNetwork::get_cell_id(int &cell_id)
kevman 0:38ceb79fef03 853 {
kevman 0:38ceb79fef03 854 cell_id = _cell_id;
kevman 0:38ceb79fef03 855 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 856 }
kevman 0:38ceb79fef03 857
kevman 0:38ceb79fef03 858 AT_CellularNetwork::RegistrationMode AT_CellularNetwork::has_registration(RegistrationType reg_type)
kevman 0:38ceb79fef03 859 {
kevman 0:38ceb79fef03 860 (void)reg_type;
kevman 0:38ceb79fef03 861 return RegistrationModeLAC;
kevman 0:38ceb79fef03 862 }
kevman 0:38ceb79fef03 863
kevman 0:38ceb79fef03 864 nsapi_error_t AT_CellularNetwork::set_attach(int /*timeout*/)
kevman 0:38ceb79fef03 865 {
kevman 0:38ceb79fef03 866 _at.lock();
kevman 0:38ceb79fef03 867
kevman 0:38ceb79fef03 868 _at.cmd_start("AT+CGATT?");
kevman 0:38ceb79fef03 869 _at.cmd_stop();
kevman 0:38ceb79fef03 870 _at.resp_start("+CGATT:");
kevman 0:38ceb79fef03 871 int attached_state = _at.read_int();
kevman 0:38ceb79fef03 872 _at.resp_stop();
kevman 0:38ceb79fef03 873 if (attached_state != 1) {
kevman 0:38ceb79fef03 874 tr_debug("Network attach");
kevman 0:38ceb79fef03 875 _at.cmd_start("AT+CGATT=1");
kevman 0:38ceb79fef03 876 _at.cmd_stop();
kevman 0:38ceb79fef03 877 _at.resp_start();
kevman 0:38ceb79fef03 878 _at.resp_stop();
kevman 0:38ceb79fef03 879 }
kevman 0:38ceb79fef03 880
kevman 0:38ceb79fef03 881 return _at.unlock_return_error();
kevman 0:38ceb79fef03 882 }
kevman 0:38ceb79fef03 883
kevman 0:38ceb79fef03 884 nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status)
kevman 0:38ceb79fef03 885 {
kevman 0:38ceb79fef03 886 _at.lock();
kevman 0:38ceb79fef03 887
kevman 0:38ceb79fef03 888 _at.cmd_start("AT+CGATT?");
kevman 0:38ceb79fef03 889 _at.cmd_stop();
kevman 0:38ceb79fef03 890
kevman 0:38ceb79fef03 891 _at.resp_start("+CGATT:");
kevman 0:38ceb79fef03 892 if (_at.info_resp()) {
kevman 0:38ceb79fef03 893 int attach_status = _at.read_int();
kevman 0:38ceb79fef03 894 status = (attach_status == 1) ? Attached : Detached;
kevman 0:38ceb79fef03 895 }
kevman 0:38ceb79fef03 896 _at.resp_stop();
kevman 0:38ceb79fef03 897
kevman 0:38ceb79fef03 898 return _at.unlock_return_error();
kevman 0:38ceb79fef03 899 }
kevman 0:38ceb79fef03 900
kevman 0:38ceb79fef03 901 nsapi_error_t AT_CellularNetwork::detach()
kevman 0:38ceb79fef03 902 {
kevman 0:38ceb79fef03 903 _at.lock();
kevman 0:38ceb79fef03 904
kevman 0:38ceb79fef03 905 tr_debug("Network detach");
kevman 0:38ceb79fef03 906 _at.cmd_start("AT+CGATT=0");
kevman 0:38ceb79fef03 907 _at.cmd_stop();
kevman 0:38ceb79fef03 908 _at.resp_start();
kevman 0:38ceb79fef03 909 _at.resp_stop();
kevman 0:38ceb79fef03 910
kevman 0:38ceb79fef03 911 call_network_cb(NSAPI_STATUS_DISCONNECTED);
kevman 0:38ceb79fef03 912
kevman 0:38ceb79fef03 913 return _at.unlock_return_error();
kevman 0:38ceb79fef03 914 }
kevman 0:38ceb79fef03 915
kevman 0:38ceb79fef03 916 nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer)
kevman 0:38ceb79fef03 917 {
kevman 0:38ceb79fef03 918 // If apn is set
kevman 0:38ceb79fef03 919 if (_apn) {
kevman 0:38ceb79fef03 920 _at.lock();
kevman 0:38ceb79fef03 921 _at.cmd_start("AT+CABTRDP=");
kevman 0:38ceb79fef03 922 _at.write_string(_apn);
kevman 0:38ceb79fef03 923 _at.cmd_stop();
kevman 0:38ceb79fef03 924 _at.resp_start("+CABTRDP:");
kevman 0:38ceb79fef03 925 if (_at.info_resp()) {
kevman 0:38ceb79fef03 926 _at.skip_param();
kevman 0:38ceb79fef03 927 backoff_timer = _at.read_int();
kevman 0:38ceb79fef03 928 }
kevman 0:38ceb79fef03 929 _at.resp_stop();
kevman 0:38ceb79fef03 930 return _at.unlock_return_error();
kevman 0:38ceb79fef03 931 }
kevman 0:38ceb79fef03 932
kevman 0:38ceb79fef03 933 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 934 }
kevman 0:38ceb79fef03 935
kevman 0:38ceb79fef03 936 NetworkStack *AT_CellularNetwork::get_stack()
kevman 0:38ceb79fef03 937 {
kevman 0:38ceb79fef03 938 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 939 // use lwIP/PPP if modem does not have IP stack
kevman 0:38ceb79fef03 940 if (!_stack) {
kevman 0:38ceb79fef03 941 _stack = nsapi_ppp_get_stack();
kevman 0:38ceb79fef03 942 }
kevman 0:38ceb79fef03 943 #endif
kevman 0:38ceb79fef03 944 return _stack;
kevman 0:38ceb79fef03 945 }
kevman 0:38ceb79fef03 946
kevman 0:38ceb79fef03 947 const char *AT_CellularNetwork::get_ip_address()
kevman 0:38ceb79fef03 948 {
kevman 0:38ceb79fef03 949 #if NSAPI_PPP_AVAILABLE
kevman 0:38ceb79fef03 950 return nsapi_ppp_get_ip_addr(_at.get_file_handle());
kevman 0:38ceb79fef03 951 #else
kevman 0:38ceb79fef03 952 if (!_stack) {
kevman 0:38ceb79fef03 953 _stack = get_stack();
kevman 0:38ceb79fef03 954 }
kevman 0:38ceb79fef03 955 if (_stack) {
kevman 0:38ceb79fef03 956 return _stack->get_ip_address();
kevman 0:38ceb79fef03 957 }
kevman 0:38ceb79fef03 958 return NULL;
kevman 0:38ceb79fef03 959 #endif
kevman 0:38ceb79fef03 960 }
kevman 0:38ceb79fef03 961
kevman 0:38ceb79fef03 962 nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type)
kevman 0:38ceb79fef03 963 {
kevman 0:38ceb79fef03 964 if (get_modem_stack_type(stack_type)) {
kevman 0:38ceb79fef03 965 _ip_stack_type_requested = stack_type;
kevman 0:38ceb79fef03 966 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 967 } else {
kevman 0:38ceb79fef03 968 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 969 }
kevman 0:38ceb79fef03 970 }
kevman 0:38ceb79fef03 971
kevman 0:38ceb79fef03 972 nsapi_ip_stack_t AT_CellularNetwork::get_stack_type()
kevman 0:38ceb79fef03 973 {
kevman 0:38ceb79fef03 974 return _ip_stack_type;
kevman 0:38ceb79fef03 975 }
kevman 0:38ceb79fef03 976
kevman 0:38ceb79fef03 977 bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
kevman 0:38ceb79fef03 978 {
kevman 0:38ceb79fef03 979 if (requested_stack == _ip_stack_type) {
kevman 0:38ceb79fef03 980 return true;
kevman 0:38ceb79fef03 981 } else {
kevman 0:38ceb79fef03 982 return false;
kevman 0:38ceb79fef03 983 }
kevman 0:38ceb79fef03 984 }
kevman 0:38ceb79fef03 985
kevman 0:38ceb79fef03 986 nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
kevman 0:38ceb79fef03 987 {
kevman 0:38ceb79fef03 988 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 989 }
kevman 0:38ceb79fef03 990
kevman 0:38ceb79fef03 991 nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology &rat)
kevman 0:38ceb79fef03 992 {
kevman 0:38ceb79fef03 993 rat = _current_act;
kevman 0:38ceb79fef03 994 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 995 }
kevman 0:38ceb79fef03 996
kevman 0:38ceb79fef03 997 nsapi_error_t AT_CellularNetwork::set_access_technology(RadioAccessTechnology opAct)
kevman 0:38ceb79fef03 998 {
kevman 0:38ceb79fef03 999 if (opAct == RAT_UNKNOWN) {
kevman 0:38ceb79fef03 1000 return NSAPI_ERROR_UNSUPPORTED;
kevman 0:38ceb79fef03 1001 }
kevman 0:38ceb79fef03 1002
kevman 0:38ceb79fef03 1003 _op_act = opAct;
kevman 0:38ceb79fef03 1004
kevman 0:38ceb79fef03 1005 return set_access_technology_impl(opAct);
kevman 0:38ceb79fef03 1006 }
kevman 0:38ceb79fef03 1007
kevman 0:38ceb79fef03 1008 nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount)
kevman 0:38ceb79fef03 1009 {
kevman 0:38ceb79fef03 1010 int idx = 0;
kevman 0:38ceb79fef03 1011
kevman 0:38ceb79fef03 1012 _at.lock();
kevman 0:38ceb79fef03 1013
kevman 0:38ceb79fef03 1014 _at.cmd_start("AT+COPS=?");
kevman 0:38ceb79fef03 1015 _at.cmd_stop();
kevman 0:38ceb79fef03 1016
kevman 0:38ceb79fef03 1017 _at.resp_start("+COPS:");
kevman 0:38ceb79fef03 1018
kevman 0:38ceb79fef03 1019 int ret, error_code = -1;
kevman 0:38ceb79fef03 1020 operator_t *op = NULL;
kevman 0:38ceb79fef03 1021
kevman 0:38ceb79fef03 1022 while (_at.info_elem('(')) {
kevman 0:38ceb79fef03 1023
kevman 0:38ceb79fef03 1024 op = operators.add_new();
kevman 0:38ceb79fef03 1025 if (!op) {
kevman 0:38ceb79fef03 1026 tr_warn("Could not allocate new operator");
kevman 0:38ceb79fef03 1027 _at.resp_stop();
kevman 0:38ceb79fef03 1028 _at.unlock();
kevman 0:38ceb79fef03 1029 operators.delete_all();
kevman 0:38ceb79fef03 1030 opsCount = 0;
kevman 0:38ceb79fef03 1031 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 1032 }
kevman 0:38ceb79fef03 1033
kevman 0:38ceb79fef03 1034 op->op_status = (operator_t::Status)_at.read_int();
kevman 0:38ceb79fef03 1035 _at.read_string(op->op_long, sizeof(op->op_long));
kevman 0:38ceb79fef03 1036 _at.read_string(op->op_short, sizeof(op->op_short));
kevman 0:38ceb79fef03 1037 _at.read_string(op->op_num, sizeof(op->op_num));
kevman 0:38ceb79fef03 1038
kevman 0:38ceb79fef03 1039 // Optional - try read an int
kevman 0:38ceb79fef03 1040 ret = _at.read_int();
kevman 0:38ceb79fef03 1041 op->op_rat = (ret == error_code) ? RAT_UNKNOWN : (RadioAccessTechnology)ret;
kevman 0:38ceb79fef03 1042
kevman 0:38ceb79fef03 1043 if ((_op_act == RAT_UNKNOWN) ||
kevman 0:38ceb79fef03 1044 ((op->op_rat != RAT_UNKNOWN) && (op->op_rat == _op_act))) {
kevman 0:38ceb79fef03 1045 idx++;
kevman 0:38ceb79fef03 1046 } else {
kevman 0:38ceb79fef03 1047 operators.delete_last();
kevman 0:38ceb79fef03 1048 }
kevman 0:38ceb79fef03 1049 }
kevman 0:38ceb79fef03 1050
kevman 0:38ceb79fef03 1051 _at.resp_stop();
kevman 0:38ceb79fef03 1052
kevman 0:38ceb79fef03 1053 opsCount = idx;
kevman 0:38ceb79fef03 1054 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1055 }
kevman 0:38ceb79fef03 1056
kevman 0:38ceb79fef03 1057 nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt,
kevman 0:38ceb79fef03 1058 Preferred_UE_Opt preferred_opt)
kevman 0:38ceb79fef03 1059 {
kevman 0:38ceb79fef03 1060 _at.lock();
kevman 0:38ceb79fef03 1061
kevman 0:38ceb79fef03 1062 _at.cmd_start("AT+CCIOTOPT=");
kevman 0:38ceb79fef03 1063 _at.write_int(_cid);
kevman 0:38ceb79fef03 1064 _at.write_int(supported_opt);
kevman 0:38ceb79fef03 1065 _at.write_int(preferred_opt);
kevman 0:38ceb79fef03 1066 _at.cmd_stop();
kevman 0:38ceb79fef03 1067
kevman 0:38ceb79fef03 1068 _at.resp_start();
kevman 0:38ceb79fef03 1069 _at.resp_stop();
kevman 0:38ceb79fef03 1070
kevman 0:38ceb79fef03 1071 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1072 }
kevman 0:38ceb79fef03 1073
kevman 0:38ceb79fef03 1074 nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
kevman 0:38ceb79fef03 1075 Preferred_UE_Opt &preferred_opt)
kevman 0:38ceb79fef03 1076 {
kevman 0:38ceb79fef03 1077 _at.lock();
kevman 0:38ceb79fef03 1078
kevman 0:38ceb79fef03 1079 _at.cmd_start("AT+CCIOTOPT?");
kevman 0:38ceb79fef03 1080 _at.cmd_stop();
kevman 0:38ceb79fef03 1081
kevman 0:38ceb79fef03 1082 _at.resp_start("+CCIOTOPT:");
kevman 0:38ceb79fef03 1083 _at.read_int();
kevman 0:38ceb79fef03 1084 if (_at.get_last_error() == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 1085 supported_opt = (Supported_UE_Opt)_at.read_int();
kevman 0:38ceb79fef03 1086 preferred_opt = (Preferred_UE_Opt)_at.read_int();
kevman 0:38ceb79fef03 1087 }
kevman 0:38ceb79fef03 1088
kevman 0:38ceb79fef03 1089 _at.resp_stop();
kevman 0:38ceb79fef03 1090
kevman 0:38ceb79fef03 1091 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1092 }
kevman 0:38ceb79fef03 1093
kevman 0:38ceb79fef03 1094 nsapi_error_t AT_CellularNetwork::get_rate_control(
kevman 0:38ceb79fef03 1095 CellularNetwork::RateControlExceptionReports &reports,
kevman 0:38ceb79fef03 1096 CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
kevman 0:38ceb79fef03 1097 {
kevman 0:38ceb79fef03 1098
kevman 0:38ceb79fef03 1099 _at.lock();
kevman 0:38ceb79fef03 1100
kevman 0:38ceb79fef03 1101 _at.cmd_start("AT+CGAPNRC=");
kevman 0:38ceb79fef03 1102 _at.write_int(_cid);
kevman 0:38ceb79fef03 1103 _at.cmd_stop();
kevman 0:38ceb79fef03 1104
kevman 0:38ceb79fef03 1105 _at.resp_start("+CGAPNRC:");
kevman 0:38ceb79fef03 1106 _at.read_int();
kevman 0:38ceb79fef03 1107 if (_at.get_last_error() == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 1108 bool comma_found = true;
kevman 0:38ceb79fef03 1109 int next_element = _at.read_int();
kevman 0:38ceb79fef03 1110 if (next_element >= 0) {
kevman 0:38ceb79fef03 1111 reports = (RateControlExceptionReports)next_element;
kevman 0:38ceb79fef03 1112 tr_debug("reports %d", reports);
kevman 0:38ceb79fef03 1113 next_element = _at.read_int();
kevman 0:38ceb79fef03 1114 } else {
kevman 0:38ceb79fef03 1115 comma_found = false;
kevman 0:38ceb79fef03 1116 }
kevman 0:38ceb79fef03 1117
kevman 0:38ceb79fef03 1118 if (comma_found && next_element >= 0) {
kevman 0:38ceb79fef03 1119 timeUnit = (RateControlUplinkTimeUnit)next_element;
kevman 0:38ceb79fef03 1120 tr_debug("time %d", timeUnit);
kevman 0:38ceb79fef03 1121 next_element = _at.read_int();
kevman 0:38ceb79fef03 1122 } else {
kevman 0:38ceb79fef03 1123 comma_found = false;
kevman 0:38ceb79fef03 1124 }
kevman 0:38ceb79fef03 1125
kevman 0:38ceb79fef03 1126 if (comma_found && next_element >= 0) {
kevman 0:38ceb79fef03 1127 uplinkRate = next_element;
kevman 0:38ceb79fef03 1128 tr_debug("rate %d", uplinkRate);
kevman 0:38ceb79fef03 1129 }
kevman 0:38ceb79fef03 1130 }
kevman 0:38ceb79fef03 1131 _at.resp_stop();
kevman 0:38ceb79fef03 1132
kevman 0:38ceb79fef03 1133 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1134 }
kevman 0:38ceb79fef03 1135
kevman 0:38ceb79fef03 1136 nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t &params_list)
kevman 0:38ceb79fef03 1137 {
kevman 0:38ceb79fef03 1138 const int ipv6_subnet_size = 128;
kevman 0:38ceb79fef03 1139 const int max_ipv6_size = 64;
kevman 0:38ceb79fef03 1140 char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size);
kevman 0:38ceb79fef03 1141 if (!ipv6_and_subnetmask) {
kevman 0:38ceb79fef03 1142 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 1143 }
kevman 0:38ceb79fef03 1144
kevman 0:38ceb79fef03 1145 char *temp = (char *)malloc(max_ipv6_size);
kevman 0:38ceb79fef03 1146 if (!temp) {
kevman 0:38ceb79fef03 1147 free(ipv6_and_subnetmask);
kevman 0:38ceb79fef03 1148 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 1149 }
kevman 0:38ceb79fef03 1150
kevman 0:38ceb79fef03 1151 _at.lock();
kevman 0:38ceb79fef03 1152
kevman 0:38ceb79fef03 1153 _at.cmd_start("AT+CGCONTRDP=");
kevman 0:38ceb79fef03 1154 _at.write_int(_cid);
kevman 0:38ceb79fef03 1155 _at.cmd_stop();
kevman 0:38ceb79fef03 1156
kevman 0:38ceb79fef03 1157 _at.resp_start("+CGCONTRDP:");
kevman 0:38ceb79fef03 1158 pdpcontext_params_t *params = NULL;
kevman 0:38ceb79fef03 1159 while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
kevman 0:38ceb79fef03 1160 params = params_list.add_new();
kevman 0:38ceb79fef03 1161 if (!params) {
kevman 0:38ceb79fef03 1162 tr_warn("Could not allocate new pdpcontext_params_t");
kevman 0:38ceb79fef03 1163 _at.resp_stop();
kevman 0:38ceb79fef03 1164 _at.unlock();
kevman 0:38ceb79fef03 1165 params_list.delete_all();
kevman 0:38ceb79fef03 1166 free(temp);
kevman 0:38ceb79fef03 1167 free(ipv6_and_subnetmask);
kevman 0:38ceb79fef03 1168 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 1169 }
kevman 0:38ceb79fef03 1170
kevman 0:38ceb79fef03 1171 params->cid = _at.read_int();
kevman 0:38ceb79fef03 1172 params->bearer_id = _at.read_int();
kevman 0:38ceb79fef03 1173 _at.read_string(params->apn, sizeof(params->apn));
kevman 0:38ceb79fef03 1174
kevman 0:38ceb79fef03 1175 // rest are optional params
kevman 0:38ceb79fef03 1176 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1177 temp[0] = '\0';
kevman 0:38ceb79fef03 1178 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1179 separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
kevman 0:38ceb79fef03 1180 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1181
kevman 0:38ceb79fef03 1182 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1183 separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1184 prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1185 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1186 temp[0] = '\0';
kevman 0:38ceb79fef03 1187
kevman 0:38ceb79fef03 1188 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1189 separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1190 prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1191 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1192 temp[0] = '\0';
kevman 0:38ceb79fef03 1193
kevman 0:38ceb79fef03 1194 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1195 separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1196 prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1197 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1198 temp[0] = '\0';
kevman 0:38ceb79fef03 1199
kevman 0:38ceb79fef03 1200 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1201 separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1202 prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1203 ipv6_and_subnetmask[0] = '\0';
kevman 0:38ceb79fef03 1204 temp[0] = '\0';
kevman 0:38ceb79fef03 1205
kevman 0:38ceb79fef03 1206 _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
kevman 0:38ceb79fef03 1207 separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1208 prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
kevman 0:38ceb79fef03 1209
kevman 0:38ceb79fef03 1210 params->im_signalling_flag = _at.read_int();
kevman 0:38ceb79fef03 1211 params->lipa_indication = _at.read_int();
kevman 0:38ceb79fef03 1212 params->ipv4_mtu = _at.read_int();
kevman 0:38ceb79fef03 1213 params->wlan_offload = _at.read_int();
kevman 0:38ceb79fef03 1214 params->local_addr_ind = _at.read_int();
kevman 0:38ceb79fef03 1215 params->non_ip_mtu = _at.read_int();
kevman 0:38ceb79fef03 1216 params->serving_plmn_rate_control_value = _at.read_int();
kevman 0:38ceb79fef03 1217 }
kevman 0:38ceb79fef03 1218 _at.resp_stop();
kevman 0:38ceb79fef03 1219
kevman 0:38ceb79fef03 1220 free(temp);
kevman 0:38ceb79fef03 1221 free(ipv6_and_subnetmask);
kevman 0:38ceb79fef03 1222
kevman 0:38ceb79fef03 1223 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1224 }
kevman 0:38ceb79fef03 1225
kevman 0:38ceb79fef03 1226 nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp)
kevman 0:38ceb79fef03 1227 {
kevman 0:38ceb79fef03 1228 _at.lock();
kevman 0:38ceb79fef03 1229
kevman 0:38ceb79fef03 1230 _at.cmd_start("AT+CESQ");
kevman 0:38ceb79fef03 1231 _at.cmd_stop();
kevman 0:38ceb79fef03 1232
kevman 0:38ceb79fef03 1233 _at.resp_start("+CESQ:");
kevman 0:38ceb79fef03 1234 rxlev = _at.read_int();
kevman 0:38ceb79fef03 1235 ber = _at.read_int();
kevman 0:38ceb79fef03 1236 rscp = _at.read_int();
kevman 0:38ceb79fef03 1237 ecno = _at.read_int();
kevman 0:38ceb79fef03 1238 rsrq = _at.read_int();
kevman 0:38ceb79fef03 1239 rsrp = _at.read_int();
kevman 0:38ceb79fef03 1240 _at.resp_stop();
kevman 0:38ceb79fef03 1241 if (rxlev < 0 || ber < 0 || rscp < 0 || ecno < 0 || rsrq < 0 || rsrp < 0) {
kevman 0:38ceb79fef03 1242 _at.unlock();
kevman 0:38ceb79fef03 1243 return NSAPI_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 1244 }
kevman 0:38ceb79fef03 1245
kevman 0:38ceb79fef03 1246 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1247 }
kevman 0:38ceb79fef03 1248
kevman 0:38ceb79fef03 1249 nsapi_error_t AT_CellularNetwork::get_signal_quality(int &rssi, int &ber)
kevman 0:38ceb79fef03 1250 {
kevman 0:38ceb79fef03 1251 _at.lock();
kevman 0:38ceb79fef03 1252
kevman 0:38ceb79fef03 1253 _at.cmd_start("AT+CSQ");
kevman 0:38ceb79fef03 1254 _at.cmd_stop();
kevman 0:38ceb79fef03 1255
kevman 0:38ceb79fef03 1256 _at.resp_start("+CSQ:");
kevman 0:38ceb79fef03 1257 rssi = _at.read_int();
kevman 0:38ceb79fef03 1258 ber = _at.read_int();
kevman 0:38ceb79fef03 1259 _at.resp_stop();
kevman 0:38ceb79fef03 1260 if (rssi < 0 || ber < 0) {
kevman 0:38ceb79fef03 1261 _at.unlock();
kevman 0:38ceb79fef03 1262 return NSAPI_ERROR_DEVICE_ERROR;
kevman 0:38ceb79fef03 1263 }
kevman 0:38ceb79fef03 1264
kevman 0:38ceb79fef03 1265 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1266 }
kevman 0:38ceb79fef03 1267
kevman 0:38ceb79fef03 1268 /** Get the last 3GPP error code
kevman 0:38ceb79fef03 1269 * @return see 3GPP TS 27.007 error codes
kevman 0:38ceb79fef03 1270 */
kevman 0:38ceb79fef03 1271 int AT_CellularNetwork::get_3gpp_error()
kevman 0:38ceb79fef03 1272 {
kevman 0:38ceb79fef03 1273 return _at.get_3gpp_error();
kevman 0:38ceb79fef03 1274 }
kevman 0:38ceb79fef03 1275
kevman 0:38ceb79fef03 1276 nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &operator_params)
kevman 0:38ceb79fef03 1277 {
kevman 0:38ceb79fef03 1278 _at.lock();
kevman 0:38ceb79fef03 1279
kevman 0:38ceb79fef03 1280 _at.cmd_start("AT+COPS?");
kevman 0:38ceb79fef03 1281 _at.cmd_stop();
kevman 0:38ceb79fef03 1282
kevman 0:38ceb79fef03 1283 _at.resp_start("+COPS:");
kevman 0:38ceb79fef03 1284 _at.read_int(); //ignore mode
kevman 0:38ceb79fef03 1285 format = _at.read_int();
kevman 0:38ceb79fef03 1286
kevman 0:38ceb79fef03 1287 if (_at.get_last_error() == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 1288 switch (format) {
kevman 0:38ceb79fef03 1289 case 0:
kevman 0:38ceb79fef03 1290 _at.read_string(operator_params.op_long, sizeof(operator_params.op_long));
kevman 0:38ceb79fef03 1291 break;
kevman 0:38ceb79fef03 1292 case 1:
kevman 0:38ceb79fef03 1293 _at.read_string(operator_params.op_short, sizeof(operator_params.op_short));
kevman 0:38ceb79fef03 1294 break;
kevman 0:38ceb79fef03 1295 default:
kevman 0:38ceb79fef03 1296 _at.read_string(operator_params.op_num, sizeof(operator_params.op_num));
kevman 0:38ceb79fef03 1297 break;
kevman 0:38ceb79fef03 1298 }
kevman 0:38ceb79fef03 1299 operator_params.op_rat = (RadioAccessTechnology)_at.read_int();
kevman 0:38ceb79fef03 1300 }
kevman 0:38ceb79fef03 1301
kevman 0:38ceb79fef03 1302 _at.resp_stop();
kevman 0:38ceb79fef03 1303
kevman 0:38ceb79fef03 1304 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1305 }
kevman 0:38ceb79fef03 1306
kevman 0:38ceb79fef03 1307 nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_names)
kevman 0:38ceb79fef03 1308 {
kevman 0:38ceb79fef03 1309 _at.lock();
kevman 0:38ceb79fef03 1310
kevman 0:38ceb79fef03 1311 _at.cmd_start("AT+COPN");
kevman 0:38ceb79fef03 1312 _at.cmd_stop();
kevman 0:38ceb79fef03 1313
kevman 0:38ceb79fef03 1314 _at.resp_start("+COPN:");
kevman 0:38ceb79fef03 1315 operator_names_t *names = NULL;
kevman 0:38ceb79fef03 1316 while (_at.info_resp()) {
kevman 0:38ceb79fef03 1317 names = op_names.add_new();
kevman 0:38ceb79fef03 1318 if (!names) {
kevman 0:38ceb79fef03 1319 tr_warn("Could not allocate new operator_names_t");
kevman 0:38ceb79fef03 1320 _at.resp_stop();
kevman 0:38ceb79fef03 1321 _at.unlock();
kevman 0:38ceb79fef03 1322 op_names.delete_all();
kevman 0:38ceb79fef03 1323 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 1324 }
kevman 0:38ceb79fef03 1325 _at.read_string(names->numeric, sizeof(names->numeric));
kevman 0:38ceb79fef03 1326 _at.read_string(names->alpha, sizeof(names->alpha));
kevman 0:38ceb79fef03 1327 }
kevman 0:38ceb79fef03 1328
kevman 0:38ceb79fef03 1329 _at.resp_stop();
kevman 0:38ceb79fef03 1330 return _at.unlock_return_error();
kevman 0:38ceb79fef03 1331 }