Retry
Fork of ublox-at-cellular-interface by
Embed:
(wiki syntax)
Show/hide line numbers
UbloxATCellularInterface.cpp
00001 /* Copyright (c) 2017 ublox Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #include "UbloxATCellularInterface.h" 00017 #include "mbed_poll.h" 00018 #include "nsapi.h" 00019 #include "APN_db.h" 00020 #ifdef FEATURE_COMMON_PAL 00021 #include "mbed_trace.h" 00022 #define TRACE_GROUP "UACI" 00023 #else 00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00025 #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00026 #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00028 #endif 00029 00030 /********************************************************************** 00031 * PRIVATE METHODS 00032 **********************************************************************/ 00033 00034 // Event thread for asynchronous received data handling. 00035 void UbloxATCellularInterface::handle_event(){ 00036 pollfh fhs; 00037 int count; 00038 int at_timeout; 00039 00040 fhs.fh = _fh; 00041 fhs.events = POLLIN; 00042 00043 while (true) { 00044 count = poll(&fhs, 1, 1000); 00045 if (count > 0 && (fhs.revents & POLLIN)) { 00046 LOCK(); 00047 at_timeout = _at_timeout; 00048 at_set_timeout(10); // Avoid blocking but also make sure we don't 00049 // time out if we get ahead of the serial port 00050 _at->debug_on(false); // Debug here screws with the test output 00051 // Let the URCs run 00052 _at->recv(UNNATURAL_STRING); 00053 _at->debug_on(_debug_trace_on); 00054 at_set_timeout(at_timeout); 00055 UNLOCK(); 00056 } 00057 } 00058 } 00059 00060 // Find or create a socket from the list. 00061 UbloxATCellularInterface::SockCtrl * UbloxATCellularInterface::find_socket(int modem_handle) 00062 { 00063 UbloxATCellularInterface::SockCtrl *socket = NULL; 00064 00065 for (unsigned int x = 0; (socket == NULL) && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) { 00066 if (_sockets[x].modem_handle == modem_handle) { 00067 socket = &(_sockets[x]); 00068 } 00069 } 00070 00071 return socket; 00072 } 00073 00074 // Clear out the storage for a socket 00075 void UbloxATCellularInterface::clear_socket(UbloxATCellularInterface::SockCtrl * socket) 00076 { 00077 if (socket != NULL) { 00078 socket->modem_handle = SOCKET_UNUSED; 00079 socket->pending = 0; 00080 socket->callback = NULL; 00081 socket->data = NULL; 00082 } 00083 } 00084 00085 // Check that a socket pointer is valid 00086 bool UbloxATCellularInterface::check_socket(SockCtrl * socket) 00087 { 00088 bool success = false; 00089 00090 if (socket != NULL) { 00091 for (unsigned int x = 0; !success && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) { 00092 if (socket == &(_sockets[x])) { 00093 success = true; 00094 } 00095 } 00096 } 00097 00098 return success; 00099 } 00100 00101 // Convert nsapi_security_t to the modem security numbers 00102 int UbloxATCellularInterface::nsapi_security_to_modem_security(nsapi_security_t nsapi_security) 00103 { 00104 int modem_security = 3; 00105 00106 switch (nsapi_security) 00107 { 00108 case NSAPI_SECURITY_NONE: 00109 modem_security = 0; 00110 break; 00111 case NSAPI_SECURITY_PAP: 00112 modem_security = 1; 00113 break; 00114 case NSAPI_SECURITY_CHAP: 00115 modem_security = 2; 00116 break; 00117 case NSAPI_SECURITY_UNKNOWN: 00118 modem_security = 3; 00119 break; 00120 default: 00121 modem_security = 3; 00122 break; 00123 } 00124 00125 return modem_security; 00126 } 00127 00128 // Callback for Socket Read URC. 00129 void UbloxATCellularInterface::UUSORD_URC() 00130 { 00131 int a; 00132 int b; 00133 char buf[32]; 00134 SockCtrl *socket; 00135 00136 // Note: not calling _at->recv() from here as we're 00137 // already in an _at->recv() 00138 // +UUSORD: <socket>,<length> 00139 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00140 if (sscanf(buf, ": %d,%d", &a, &b) == 2) { 00141 socket = find_socket(a); 00142 if (socket != NULL) { 00143 socket->pending = b; 00144 // No debug prints here as they can affect timing 00145 // and cause data loss in UARTSerial 00146 if (socket->callback != NULL) { 00147 socket->callback(socket->data); 00148 } 00149 } 00150 } 00151 } 00152 } 00153 00154 // Callback for Socket Read From URC. 00155 void UbloxATCellularInterface::UUSORF_URC() 00156 { 00157 int a; 00158 int b; 00159 char buf[32]; 00160 SockCtrl *socket; 00161 00162 // Note: not calling _at->recv() from here as we're 00163 // already in an _at->recv() 00164 // +UUSORF: <socket>,<length> 00165 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00166 if (sscanf(buf, ": %d,%d", &a, &b) == 2) { 00167 socket = find_socket(a); 00168 if (socket != NULL) { 00169 socket->pending = b; 00170 // No debug prints here as they can affect timing 00171 // and cause data loss in UARTSerial 00172 if (socket->callback != NULL) { 00173 socket->callback(socket->data); 00174 } 00175 } 00176 } 00177 } 00178 } 00179 00180 // Callback for Socket Close URC. 00181 void UbloxATCellularInterface::UUSOCL_URC() 00182 { 00183 int a; 00184 char buf[32]; 00185 SockCtrl *socket; 00186 00187 // Note: not calling _at->recv() from here as we're 00188 // already in an _at->recv() 00189 // +UUSOCL: <socket> 00190 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00191 if (sscanf(buf, ": %d", &a) == 1) { 00192 socket = find_socket(a); 00193 tr_debug("Socket 0x%08x: handle %d closed by remote host", 00194 (unsigned int) socket, a); 00195 clear_socket(socket); 00196 } 00197 } 00198 } 00199 00200 // Callback for UUPSDD. 00201 void UbloxATCellularInterface::UUPSDD_URC() 00202 { 00203 int a; 00204 char buf[32]; 00205 SockCtrl *socket; 00206 00207 // Note: not calling _at->recv() from here as we're 00208 // already in an _at->recv() 00209 // +UUPSDD: <socket> 00210 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00211 if (sscanf(buf, ": %d", &a) == 1) { 00212 socket = find_socket(a); 00213 tr_debug("Socket 0x%08x: handle %d connection lost", 00214 (unsigned int) socket, a); 00215 clear_socket(socket); 00216 if (_connection_status_cb) { 00217 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 00218 } 00219 } 00220 } 00221 } 00222 00223 /********************************************************************** 00224 * PROTECTED METHODS: GENERAL 00225 **********************************************************************/ 00226 00227 // Get the next set of credentials, based on IMSI. 00228 void UbloxATCellularInterface::get_next_credentials(const char ** config) 00229 { 00230 if (*config) { 00231 _apn = _APN_GET(*config); 00232 _uname = _APN_GET(*config); 00233 _pwd = _APN_GET(*config); 00234 } 00235 00236 _apn = _apn ? _apn : ""; 00237 _uname = _uname ? _uname : ""; 00238 _pwd = _pwd ? _pwd : ""; 00239 } 00240 00241 // Active a connection profile on board the modem. 00242 // Note: the AT interface should be locked before this is called. 00243 bool UbloxATCellularInterface::activate_profile(const char* apn, 00244 const char* username, 00245 const char* password, 00246 nsapi_security_t auth) 00247 { 00248 bool activated = false; 00249 bool success = false; 00250 int at_timeout = _at_timeout; 00251 SocketAddress address; 00252 00253 // Set up the APN 00254 if (*apn) { 00255 success = _at->send("AT+UPSD=" PROFILE ",1,\"%s\"", apn) && _at->recv("OK"); 00256 } 00257 if (success && *username) { 00258 success = _at->send("AT+UPSD=" PROFILE ",2,\"%s\"", username) && _at->recv("OK"); 00259 } 00260 if (success && *password) { 00261 success = _at->send("AT+UPSD=" PROFILE ",3,\"%s\"", password) && _at->recv("OK"); 00262 } 00263 00264 if (success) { 00265 // Set up dynamic IP address assignment. 00266 success = _at->send("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"") && _at->recv("OK"); 00267 // Set up the authentication protocol 00268 // 0 = none 00269 // 1 = PAP (Password Authentication Protocol) 00270 // 2 = CHAP (Challenge Handshake Authentication Protocol) 00271 for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE); 00272 success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) { 00273 if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) { 00274 if (_at->send("AT+UPSD=" PROFILE ",6,%d", protocol) && _at->recv("OK")) { 00275 // Activate, waiting 30 seconds for the connection to be made 00276 at_set_timeout(30000); 00277 activated = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00278 at_set_timeout(at_timeout); 00279 00280 if(!activated) 00281 { 00282 // Activate, waiting 30 seconds for the connection to be made 00283 at_set_timeout(30000); 00284 activated = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00285 at_set_timeout(at_timeout); 00286 } 00287 } 00288 } 00289 } 00290 } 00291 00292 return activated; 00293 } 00294 00295 // Activate a profile by reusing an external PDP context. 00296 // Note: the AT interface should be locked before this is called. 00297 bool UbloxATCellularInterface::activate_profile_reuse_external(void) 00298 { 00299 bool success = false; 00300 int cid = -1; 00301 char ip[NSAPI_IP_SIZE]; 00302 SocketAddress address; 00303 int t; 00304 int at_timeout = _at_timeout; 00305 00306 //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0 00307 if (_at->send("AT+CGDCONT?")) { 00308 if (_at->recv("+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%*d,%*d,%*d,%*d,%*d,%*d", 00309 &t, ip) && 00310 _at->recv("OK")) { 00311 // Check if the IP address is valid 00312 if (address.set_ip_address(ip)) { 00313 cid = t; 00314 } 00315 } 00316 } 00317 00318 // If a context has been found, use it 00319 if ((cid != -1) && (_at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK"))) { 00320 // Activate, waiting 30 seconds for the connection to be made 00321 at_set_timeout(30000); 00322 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00323 at_set_timeout(at_timeout); 00324 } 00325 00326 return success; 00327 } 00328 00329 // Activate a profile by context ID. 00330 // Note: the AT interface should be locked before this is called. 00331 bool UbloxATCellularInterface::activate_profile_by_cid(int cid, 00332 const char* apn, 00333 const char* username, 00334 const char* password, 00335 nsapi_security_t auth) 00336 { 00337 bool success = false; 00338 int at_timeout = _at_timeout; 00339 00340 if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK") && 00341 _at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, nsapi_security_to_modem_security(auth), 00342 username, password) && _at->recv("OK") && 00343 _at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK")) { 00344 00345 // Wait 30 seconds for the connection to be made 00346 at_set_timeout(30000); 00347 // Activate the protocol 00348 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00349 at_set_timeout(at_timeout); 00350 } 00351 00352 return success; 00353 } 00354 00355 // Connect the on board IP stack of the modem. 00356 bool UbloxATCellularInterface::connect_modem_stack() 00357 { 00358 bool success = false; 00359 int active = 0; 00360 const char * config = NULL; 00361 LOCK(); 00362 00363 // Check the profile 00364 if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) && 00365 _at->recv("OK")) { 00366 if (active == 0) { 00367 // If the caller hasn't entered an APN, try to find it 00368 if (_apn == NULL) { 00369 config = apnconfig(_dev_info.imsi); 00370 } 00371 00372 // Attempt to connect 00373 do { 00374 // Set up APN and IP protocol for PDP context 00375 get_next_credentials(&config); 00376 _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE; 00377 if ((_dev_info.dev != DEV_TOBY_L2) && (_dev_info.dev != DEV_MPCI_L2)) { 00378 success = activate_profile(_apn, _uname, _pwd, _auth); 00379 } else { 00380 success = activate_profile_reuse_external(); 00381 if (success) { 00382 tr_debug("Reusing external context"); 00383 } else { 00384 success = activate_profile_by_cid(1, _apn, _uname, _pwd, _auth); 00385 } 00386 } 00387 } while (!success && config && *config); 00388 } else { 00389 // If the profile is already active, we're good 00390 success = true; 00391 } 00392 } 00393 00394 if (!success) { 00395 tr_error("Failed to connect, check your APN/username/password"); 00396 } 00397 00398 UNLOCK(); 00399 return success; 00400 } 00401 00402 // Disconnect the on board IP stack of the modem. 00403 bool UbloxATCellularInterface::disconnect_modem_stack() 00404 { 00405 bool success = false; 00406 LOCK(); 00407 00408 if (get_ip_address() != NULL) { 00409 if (_at->send("AT+UPSDA=" PROFILE ",4") && _at->recv("OK")) { 00410 success = true; 00411 if (_connection_status_cb) { 00412 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 00413 } 00414 } 00415 } 00416 00417 UNLOCK(); 00418 return success; 00419 } 00420 00421 /********************************************************************** 00422 * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS 00423 **********************************************************************/ 00424 00425 // Gain access to us. 00426 NetworkStack *UbloxATCellularInterface::get_stack() 00427 { 00428 return this; 00429 } 00430 00431 // Create a socket. 00432 nsapi_error_t UbloxATCellularInterface::socket_open(nsapi_socket_t *handle, 00433 nsapi_protocol_t proto) 00434 { 00435 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00436 bool success = false; 00437 int modem_handle; 00438 SockCtrl *socket; 00439 LOCK(); 00440 00441 // Find a free socket 00442 socket = find_socket(); 00443 tr_debug("socket_open(%d)", proto); 00444 00445 if (socket != NULL) { 00446 if (proto == NSAPI_UDP) { 00447 success = _at->send("AT+USOCR=17"); 00448 } else if (proto == NSAPI_TCP) { 00449 success = _at->send("AT+USOCR=6"); 00450 } else { 00451 nsapi_error = NSAPI_ERROR_UNSUPPORTED; 00452 } 00453 00454 if (success) { 00455 nsapi_error = NSAPI_ERROR_NO_SOCKET; 00456 if (_at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00457 _at->recv("OK")) { 00458 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle); 00459 clear_socket(socket); 00460 socket->modem_handle = modem_handle; 00461 *handle = (nsapi_socket_t) socket; 00462 nsapi_error = NSAPI_ERROR_OK; 00463 } 00464 } 00465 } else { 00466 nsapi_error = NSAPI_ERROR_NO_MEMORY; 00467 } 00468 00469 UNLOCK(); 00470 return nsapi_error; 00471 } 00472 00473 // Close a socket. 00474 nsapi_error_t UbloxATCellularInterface::socket_close(nsapi_socket_t handle) 00475 { 00476 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00477 SockCtrl *socket = (SockCtrl *) handle; 00478 LOCK(); 00479 00480 tr_debug("socket_close(0x%08x)", (unsigned int) handle); 00481 00482 MBED_ASSERT (check_socket(socket)); 00483 00484 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00485 _at->recv("OK")) { 00486 clear_socket(socket); 00487 nsapi_error = NSAPI_ERROR_OK; 00488 } 00489 00490 UNLOCK(); 00491 return nsapi_error; 00492 } 00493 00494 // Bind a local port to a socket. 00495 nsapi_error_t UbloxATCellularInterface::socket_bind(nsapi_socket_t handle, 00496 const SocketAddress &address) 00497 { 00498 nsapi_error_t nsapi_error = NSAPI_ERROR_NO_SOCKET; 00499 int proto; 00500 int modem_handle; 00501 SockCtrl savedSocket; 00502 SockCtrl *socket = (SockCtrl *) handle; 00503 LOCK(); 00504 00505 tr_debug("socket_bind(0x%08x, :%d)", (unsigned int) handle, address.get_port()); 00506 00507 MBED_ASSERT (check_socket(socket)); 00508 00509 // Query the socket type 00510 if (_at->send("AT+USOCTL=%d,0", socket->modem_handle) && 00511 _at->recv("+USOCTL: %*d,0,%d\n", &proto) && 00512 _at->recv("OK")) { 00513 savedSocket = *socket; 00514 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00515 // Now close the socket and re-open it with the binding given 00516 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00517 _at->recv("OK")) { 00518 clear_socket(socket); 00519 nsapi_error = NSAPI_ERROR_CONNECTION_LOST; 00520 if (_at->send("AT+USOCR=%d,%d", proto, address.get_port()) && 00521 _at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00522 _at->recv("OK")) { 00523 *socket = savedSocket; 00524 nsapi_error = NSAPI_ERROR_OK; 00525 } 00526 } 00527 } 00528 00529 UNLOCK(); 00530 return nsapi_error; 00531 } 00532 00533 // Connect to a socket 00534 nsapi_error_t UbloxATCellularInterface::socket_connect(nsapi_socket_t handle, 00535 const SocketAddress &address) 00536 { 00537 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00538 SockCtrl *socket = (SockCtrl *) handle; 00539 LOCK(); 00540 00541 tr_debug("socket_connect(0x%08x, %s(:%d))", (unsigned int) handle, 00542 address.get_ip_address(), address.get_port()); 00543 00544 MBED_ASSERT (check_socket(socket)); 00545 00546 if (_at->send("AT+USOCO=%d,\"%s\",%d", socket->modem_handle, 00547 address.get_ip_address(), address.get_port()) && 00548 _at->recv("OK")) { 00549 nsapi_error = NSAPI_ERROR_OK; 00550 } 00551 00552 UNLOCK(); 00553 return nsapi_error; 00554 } 00555 00556 // Send to a socket. 00557 nsapi_size_or_error_t UbloxATCellularInterface::socket_send(nsapi_socket_t handle, 00558 const void *data, 00559 nsapi_size_t size) 00560 { 00561 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00562 bool success = true; 00563 const char *buf = (const char *) data; 00564 nsapi_size_t blk = MAX_WRITE_SIZE; 00565 nsapi_size_t count = size; 00566 SockCtrl *socket = (SockCtrl *) handle; 00567 00568 tr_debug("socket_send(0x%08x, 0x%08x, %d)", (unsigned int) handle, (unsigned int) data, size); 00569 00570 MBED_ASSERT (check_socket(socket)); 00571 00572 while ((count > 0) && success) { 00573 if (count < blk) { 00574 blk = count; 00575 } 00576 LOCK(); 00577 00578 if (_at->send("AT+USOWR=%d,%d", socket->modem_handle, blk) && _at->recv("@")) { 00579 wait_ms(50); 00580 if ((_at->write(buf, blk) < (int) blk) || 00581 !_at->recv("OK")) { 00582 success = false; 00583 } 00584 } else { 00585 success = false; 00586 } 00587 00588 UNLOCK(); 00589 buf += blk; 00590 count -= blk; 00591 } 00592 00593 if (success) { 00594 nsapi_error_size = size - count; 00595 if (_debug_trace_on) { 00596 tr_debug("socket_send: %d \"%*.*s\"", size, size, size, (char *) data); 00597 } 00598 } 00599 00600 return nsapi_error_size; 00601 } 00602 00603 // Send to an IP address. 00604 nsapi_size_or_error_t UbloxATCellularInterface::socket_sendto(nsapi_socket_t handle, 00605 const SocketAddress &address, 00606 const void *data, 00607 nsapi_size_t size) 00608 { 00609 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00610 bool success = true; 00611 const char *buf = (const char *) data; 00612 nsapi_size_t blk = MAX_WRITE_SIZE; 00613 nsapi_size_t count = size; 00614 SockCtrl *socket = (SockCtrl *) handle; 00615 00616 tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle, 00617 address.get_ip_address(), address.get_port(), (unsigned int) data, size); 00618 00619 MBED_ASSERT (check_socket(socket)); 00620 00621 if (size > MAX_WRITE_SIZE) { 00622 tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE); 00623 } 00624 00625 while ((count > 0) && success) { 00626 if (count < blk) { 00627 blk = count; 00628 } 00629 LOCK(); 00630 00631 if (_at->send("AT+USOST=%d,\"%s\",%d,%d", socket->modem_handle, 00632 address.get_ip_address(), address.get_port(), blk) && 00633 _at->recv("@")) { 00634 wait_ms(50); 00635 if ((_at->write(buf, blk) >= (int) blk) && 00636 _at->recv("OK")) { 00637 } else { 00638 success = false; 00639 } 00640 } else { 00641 success = false; 00642 } 00643 00644 UNLOCK(); 00645 buf += blk; 00646 count -= blk; 00647 } 00648 00649 if (success) { 00650 nsapi_error_size = size - count; 00651 if (_debug_trace_on) { 00652 tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data); 00653 } 00654 } 00655 00656 return nsapi_error_size; 00657 } 00658 00659 // Receive from a socket, TCP style. 00660 nsapi_size_or_error_t UbloxATCellularInterface::socket_recv(nsapi_socket_t handle, 00661 void *data, 00662 nsapi_size_t size) 00663 { 00664 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00665 bool success = true; 00666 char *buf = (char *) data; 00667 nsapi_size_t read_blk; 00668 nsapi_size_t count = 0; 00669 unsigned int usord_sz; 00670 int read_sz; 00671 Timer timer; 00672 SockCtrl *socket = (SockCtrl *) handle; 00673 int at_timeout; 00674 00675 tr_debug("socket_recv(0x%08x, 0x%08x, %d)", 00676 (unsigned int) handle, (unsigned int) data, size); 00677 00678 MBED_ASSERT (check_socket(socket)); 00679 00680 timer.start(); 00681 00682 while (success && (size > 0)) { 00683 LOCK(); 00684 at_timeout = _at_timeout; 00685 at_set_timeout(1000); 00686 00687 read_blk = MAX_READ_SIZE; 00688 if (read_blk > size) { 00689 read_blk = size; 00690 } 00691 if (socket->pending > 0) { 00692 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00693 (unsigned int) socket, socket->modem_handle, socket->pending); 00694 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00695 // be able to read packets of any size without 00696 // losing characters in UARTSerial 00697 if (_at->send("AT+USORD=%d,%d", socket->modem_handle, read_blk) && 00698 _at->recv("+USORD: %*d,%d,\"", &usord_sz)) { 00699 socket->pending -= usord_sz; // Must use what +USORD returns here as it 00700 // may be less than we asked for 00701 // Note: insert no debug between _at->recv() and _at->read(), no time... 00702 if (usord_sz > size) { 00703 usord_sz = size; 00704 } 00705 read_sz = _at->read(buf, usord_sz); 00706 if (read_sz > 0) { 00707 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00708 socket->modem_handle); 00709 if (_debug_trace_on) { 00710 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00711 } 00712 count += read_sz; 00713 buf += read_sz; 00714 size -= read_sz; 00715 } else { 00716 // read() should not fail 00717 success = false; 00718 } 00719 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00720 (unsigned int) socket, socket->modem_handle, socket->pending); 00721 // Wait for the "OK" before continuing 00722 _at->recv("OK"); 00723 } else { 00724 // Should never fail to do _at->send()/_at->recv() 00725 success = false; 00726 } 00727 _at->debug_on(_debug_trace_on); 00728 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00729 // Wait for URCs 00730 _at->recv(UNNATURAL_STRING); 00731 } else { 00732 if (count == 0) { 00733 // Timeout with nothing received 00734 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00735 success = false; 00736 } 00737 size = 0; // This simply to cause an exit 00738 } 00739 00740 at_set_timeout(at_timeout); 00741 UNLOCK(); 00742 } 00743 timer.stop(); 00744 00745 if (success) { 00746 nsapi_error_size = count; 00747 } 00748 00749 if (_debug_trace_on) { 00750 tr_debug("socket_recv: %d \"%*.*s\"", count, count, count, buf - count); 00751 } else { 00752 tr_debug("socket_recv: received %d byte(s)", count); 00753 } 00754 00755 return nsapi_error_size; 00756 } 00757 00758 // Receive a packet over a UDP socket. 00759 nsapi_size_or_error_t UbloxATCellularInterface::socket_recvfrom(nsapi_socket_t handle, 00760 SocketAddress *address, 00761 void *data, 00762 nsapi_size_t size) 00763 { 00764 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00765 bool success = true; 00766 char *buf = (char *) data; 00767 nsapi_size_t read_blk; 00768 nsapi_size_t count = 0; 00769 char ipAddress[NSAPI_IP_SIZE]; 00770 int port; 00771 unsigned int usorf_sz; 00772 int read_sz; 00773 Timer timer; 00774 SockCtrl *socket = (SockCtrl *) handle; 00775 int at_timeout; 00776 00777 tr_debug("socket_recvfrom(0x%08x, 0x%08x, %d)", 00778 (unsigned int) handle, (unsigned int) data, size); 00779 00780 MBED_ASSERT (check_socket(socket)); 00781 00782 timer.start(); 00783 00784 while (success && (size > 0)) { 00785 LOCK(); 00786 at_timeout = _at_timeout; 00787 at_set_timeout(1000); 00788 00789 read_blk = MAX_READ_SIZE; 00790 if (read_blk > size) { 00791 read_blk = size; 00792 } 00793 if (socket->pending > 0) { 00794 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00795 (unsigned int) socket, socket->modem_handle, socket->pending); 00796 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 00797 00798 // Note: the maximum length of UDP packet we can receive comes from 00799 // fitting all of the following into one buffer: 00800 // 00801 // +USORF: xx,"max.len.ip.address.ipv4.or.ipv6",yyyyy,wwww,"the_data"\r\n 00802 // 00803 // where xx is the handle, max.len.ip.address.ipv4.or.ipv6 is NSAPI_IP_SIZE, 00804 // yyyyy is the port number (max 65536), wwww is the length of the data and 00805 // the_data is binary data. I make that 29 + 48 + len(the_data), 00806 // so the overhead is 77 bytes. 00807 00808 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00809 // be able to read packets of any size without 00810 // losing characters in UARTSerial 00811 if (_at->send("AT+USORF=%d,%d", socket->modem_handle, read_blk) && 00812 _at->recv("+USORF: %*d,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%d,%d,\"", 00813 ipAddress, &port, &usorf_sz)) { 00814 socket->pending -= usorf_sz; // Must use what +USORF returns here as it 00815 // may be less than we asked for 00816 // Note: insert no debug between _at->recv() and _at->read(), no time... 00817 if (usorf_sz > size) { 00818 usorf_sz = size; 00819 } 00820 read_sz = _at->read(buf, usorf_sz); 00821 if (read_sz > 0) { 00822 address->set_ip_address(ipAddress); 00823 address->set_port(port); 00824 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00825 socket->modem_handle); 00826 if (_debug_trace_on) { 00827 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00828 } 00829 count += read_sz; 00830 buf += read_sz; 00831 size -= read_sz; 00832 if ((usorf_sz < read_blk) || (usorf_sz == MAX_READ_SIZE)) { 00833 size = 0; // If we've received less than we asked for, or 00834 // the max size, then a whole UDP packet has arrived and 00835 // this means DONE. 00836 } 00837 } else { 00838 // read() should not fail 00839 success = false; 00840 } 00841 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00842 (unsigned int) socket, socket->modem_handle, socket->pending); 00843 // Wait for the "OK" before continuing 00844 _at->recv("OK"); 00845 } else { 00846 // Should never fail to do _at->send()/_at->recv() 00847 success = false; 00848 } 00849 _at->debug_on(_debug_trace_on); 00850 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00851 // Wait for URCs 00852 _at->recv(UNNATURAL_STRING); 00853 } else { 00854 if (count == 0) { 00855 // Timeout with nothing received 00856 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00857 success = false; 00858 } 00859 size = 0; // This simply to cause an exit 00860 } 00861 00862 at_set_timeout(at_timeout); 00863 UNLOCK(); 00864 } 00865 timer.stop(); 00866 00867 if (success) { 00868 nsapi_error_size = count; 00869 } 00870 00871 if (_debug_trace_on) { 00872 tr_debug("socket_recvfrom: %d \"%*.*s\"", count, count, count, buf - count); 00873 } else { 00874 tr_debug("socket_recvfrom: received %d byte(s)", count); 00875 } 00876 00877 return nsapi_error_size; 00878 } 00879 00880 // Attach an event callback to a socket, required for asynchronous 00881 // data reception 00882 void UbloxATCellularInterface::socket_attach(nsapi_socket_t handle, 00883 void (*callback)(void *), 00884 void *data) 00885 { 00886 SockCtrl *socket = (SockCtrl *) handle; 00887 00888 MBED_ASSERT (check_socket(socket)); 00889 00890 socket->callback = callback; 00891 socket->data = data; 00892 } 00893 00894 // Unsupported TCP server functions. 00895 nsapi_error_t UbloxATCellularInterface::socket_listen(nsapi_socket_t handle, 00896 int backlog) 00897 { 00898 return NSAPI_ERROR_UNSUPPORTED; 00899 } 00900 nsapi_error_t UbloxATCellularInterface::socket_accept(nsapi_socket_t server, 00901 nsapi_socket_t *handle, 00902 SocketAddress *address) 00903 { 00904 return NSAPI_ERROR_UNSUPPORTED; 00905 } 00906 00907 // Unsupported option functions. 00908 nsapi_error_t UbloxATCellularInterface::setsockopt(nsapi_socket_t handle, 00909 int level, int optname, 00910 const void *optval, 00911 unsigned optlen) 00912 { 00913 return NSAPI_ERROR_UNSUPPORTED; 00914 } 00915 nsapi_error_t UbloxATCellularInterface::getsockopt(nsapi_socket_t handle, 00916 int level, int optname, 00917 void *optval, 00918 unsigned *optlen) 00919 { 00920 return NSAPI_ERROR_UNSUPPORTED; 00921 } 00922 00923 /********************************************************************** 00924 * PUBLIC METHODS 00925 **********************************************************************/ 00926 00927 // Constructor. 00928 UbloxATCellularInterface::UbloxATCellularInterface(PinName tx, 00929 PinName rx, 00930 int baud, 00931 bool debug_on) 00932 { 00933 _sim_pin_check_change_pending = false; 00934 _sim_pin_check_change_pending_enabled_value = false; 00935 _sim_pin_change_pending = false; 00936 _sim_pin_change_pending_new_pin_value = NULL; 00937 _apn = NULL; 00938 _uname = NULL; 00939 _pwd = NULL; 00940 _connection_status_cb = NULL; 00941 00942 // Initialise sockets storage 00943 memset(_sockets, 0, sizeof(_sockets)); 00944 for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) { 00945 _sockets[socket].modem_handle = SOCKET_UNUSED; 00946 _sockets[socket].callback = NULL; 00947 _sockets[socket].data = NULL; 00948 } 00949 00950 // The authentication to use 00951 _auth = NSAPI_SECURITY_UNKNOWN; 00952 00953 // Nullify the temporary IP address storage 00954 _ip = NULL; 00955 00956 // Initialise the base class, which starts the AT parser 00957 baseClassInit(tx, rx, baud, debug_on); 00958 00959 // Start the event handler thread for Rx data 00960 event_thread.start(callback(this, &UbloxATCellularInterface::handle_event)); 00961 00962 // URC handlers for sockets 00963 _at->oob("+UUSORD", callback(this, &UbloxATCellularInterface::UUSORD_URC)); 00964 _at->oob("+UUSORF", callback(this, &UbloxATCellularInterface::UUSORF_URC)); 00965 _at->oob("+UUSOCL", callback(this, &UbloxATCellularInterface::UUSOCL_URC)); 00966 _at->oob("+UUPSDD", callback(this, &UbloxATCellularInterface::UUPSDD_URC)); 00967 } 00968 00969 // Destructor. 00970 UbloxATCellularInterface::~UbloxATCellularInterface() 00971 { 00972 // Free _ip if it was ever allocated 00973 free(_ip); 00974 } 00975 00976 // Set the authentication scheme. 00977 void UbloxATCellularInterface::set_authentication(nsapi_security_t auth) 00978 { 00979 _auth = auth; 00980 } 00981 00982 // Set APN, user name and password. 00983 void UbloxATCellularInterface::set_credentials(const char *apn, 00984 const char *uname, 00985 const char *pwd) 00986 { 00987 _apn = apn; 00988 _uname = uname; 00989 _pwd = pwd; 00990 } 00991 00992 // Set PIN. 00993 void UbloxATCellularInterface::set_sim_pin(const char *pin) { 00994 set_pin(pin); 00995 } 00996 00997 static int count = 0; 00998 00999 // Get the IP address of a host. 01000 nsapi_error_t UbloxATCellularInterface::gethostbyname(const char *host, 01001 SocketAddress *address, 01002 nsapi_version_t version) 01003 { 01004 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01005 int at_timeout; 01006 char ipAddress[NSAPI_IP_SIZE]; 01007 01008 count++; 01009 if (address->set_ip_address(host)) { 01010 nsapi_error = NSAPI_ERROR_OK; 01011 } else { 01012 LOCK(); 01013 // This interrogation can sometimes take longer than the usual 8 seconds 01014 at_timeout = _at_timeout; 01015 at_set_timeout(60000); 01016 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 01017 if (_at->send("AT+UDNSRN=0,\"%s\"", host) && 01018 _at->recv("+UDNSRN: \"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", ipAddress) && 01019 _at->recv("OK")) { 01020 if (address->set_ip_address(ipAddress)) { 01021 nsapi_error = NSAPI_ERROR_OK; 01022 } 01023 } 01024 at_set_timeout(at_timeout); 01025 UNLOCK(); 01026 } 01027 01028 return nsapi_error; 01029 } 01030 01031 // Make a cellular connection 01032 nsapi_error_t UbloxATCellularInterface::connect(const char *sim_pin, 01033 const char *apn, 01034 const char *uname, 01035 const char *pwd) 01036 { 01037 nsapi_error_t nsapi_error; 01038 01039 if (sim_pin != NULL) { 01040 _pin = sim_pin; 01041 } 01042 01043 if (apn != NULL) { 01044 _apn = apn; 01045 } 01046 01047 if ((uname != NULL) && (pwd != NULL)) { 01048 _uname = uname; 01049 _pwd = pwd; 01050 } else { 01051 _uname = NULL; 01052 _pwd = NULL; 01053 } 01054 01055 nsapi_error = connect(); 01056 01057 return nsapi_error; 01058 } 01059 01060 // Make a cellular connection using the IP stack on board the cellular modem 01061 nsapi_error_t UbloxATCellularInterface::connect() 01062 { 01063 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01064 bool registered = false; 01065 01066 // Set up modem and then register with the network 01067 if (init()) { 01068 nsapi_error = NSAPI_ERROR_NO_CONNECTION; 01069 // Perform any pending SIM actions 01070 if (_sim_pin_check_change_pending) { 01071 if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) { 01072 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01073 } 01074 _sim_pin_check_change_pending = false; 01075 } 01076 if (_sim_pin_change_pending) { 01077 if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) { 01078 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01079 } 01080 _sim_pin_change_pending = false; 01081 } 01082 01083 if (nsapi_error == NSAPI_ERROR_NO_CONNECTION) { 01084 for (int retries = 0; !registered && (retries < 3); retries++) { 01085 if (nwk_registration()) { 01086 registered = true;; 01087 } 01088 } 01089 } 01090 } 01091 01092 // Attempt to establish a connection 01093 if (registered && connect_modem_stack()) { 01094 nsapi_error = NSAPI_ERROR_OK; 01095 } 01096 01097 return nsapi_error; 01098 } 01099 01100 // User initiated disconnect. 01101 nsapi_error_t UbloxATCellularInterface::disconnect() 01102 { 01103 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01104 01105 if (disconnect_modem_stack() && nwk_deregistration()) { 01106 nsapi_error = NSAPI_ERROR_OK; 01107 } 01108 01109 return nsapi_error; 01110 } 01111 01112 // Enable or disable SIM PIN check lock. 01113 nsapi_error_t UbloxATCellularInterface::set_sim_pin_check(bool set, 01114 bool immediate, 01115 const char *sim_pin) 01116 { 01117 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01118 01119 if (sim_pin != NULL) { 01120 _pin = sim_pin; 01121 } 01122 01123 if (immediate) { 01124 if (init()) { 01125 if (sim_pin_check_enable(set)) { 01126 nsapi_error = NSAPI_ERROR_OK; 01127 } 01128 } else { 01129 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01130 } 01131 } else { 01132 nsapi_error = NSAPI_ERROR_OK; 01133 _sim_pin_check_change_pending = true; 01134 _sim_pin_check_change_pending_enabled_value = set; 01135 } 01136 01137 return nsapi_error; 01138 } 01139 01140 // Change the PIN code for the SIM card. 01141 nsapi_error_t UbloxATCellularInterface::set_new_sim_pin(const char *new_pin, 01142 bool immediate, 01143 const char *old_pin) 01144 { 01145 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01146 01147 if (old_pin != NULL) { 01148 _pin = old_pin; 01149 } 01150 01151 if (immediate) { 01152 if (init()) { 01153 if (change_sim_pin(new_pin)) { 01154 nsapi_error = NSAPI_ERROR_OK; 01155 } 01156 } else { 01157 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01158 } 01159 } else { 01160 nsapi_error = NSAPI_ERROR_OK; 01161 _sim_pin_change_pending = true; 01162 _sim_pin_change_pending_new_pin_value = new_pin; 01163 } 01164 01165 return nsapi_error; 01166 } 01167 01168 // Determine if the connection is up. 01169 bool UbloxATCellularInterface::is_connected() 01170 { 01171 return get_ip_address() != NULL; 01172 } 01173 01174 // Get the IP address of the on-board modem IP stack. 01175 const char * UbloxATCellularInterface::get_ip_address() 01176 { 01177 SocketAddress address; 01178 LOCK(); 01179 01180 if (_ip == NULL) { 01181 // Temporary storage for an IP address string with terminator 01182 _ip = (char *) malloc(NSAPI_IP_SIZE); 01183 } 01184 01185 if (_ip != NULL) { 01186 memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator 01187 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] 01188 // If we get back a quoted "w.x.y.z" then we have an IP address, 01189 // otherwise we don't. 01190 if (!_at->send("AT+UPSND=" PROFILE ",0") || 01191 !_at->recv("+UPSND: " PROFILE ",0,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", _ip) || 01192 !_at->recv("OK") || 01193 !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one 01194 !address) { // Return null if the address is zero 01195 free (_ip); 01196 _ip = NULL; 01197 } 01198 } 01199 01200 UNLOCK(); 01201 return _ip; 01202 } 01203 01204 // Get the local network mask. 01205 const char *UbloxATCellularInterface::get_netmask() 01206 { 01207 // Not implemented. 01208 return NULL; 01209 } 01210 01211 // Get the local gateways. 01212 const char *UbloxATCellularInterface::get_gateway() 01213 { 01214 return get_ip_address(); 01215 } 01216 01217 // Callback in case the connection is lost. 01218 void UbloxATCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb) 01219 { 01220 _connection_status_cb = cb; 01221 } 01222 01223 // End of file 01224
Generated on Fri Jul 15 2022 01:47:11 by
![doxygen](doxygen.png)