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.
features/cellular/framework/AT/AT_CellularNetwork.cpp@0:38ceb79fef03, 2018-11-28 (annotated)
- Committer:
- kevman
- Date:
- Wed Nov 28 15:10:15 2018 +0000
- Revision:
- 0:38ceb79fef03
RTC modified
Who changed what in which revision?
User | Revision | Line number | New 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 ®_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 ¶ms_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 | } |