Adding ability to set priority for the Rx thread
Fork of ublox-at-cellular-interface by
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 (_run_event_thread) { 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 } 00281 } 00282 } 00283 00284 return activated; 00285 } 00286 00287 // Activate a profile by reusing an external PDP context. 00288 // Note: the AT interface should be locked before this is called. 00289 bool UbloxATCellularInterface::activate_profile_reuse_external(void) 00290 { 00291 bool success = false; 00292 int cid = -1; 00293 char ip[NSAPI_IP_SIZE]; 00294 SocketAddress address; 00295 int t; 00296 int at_timeout = _at_timeout; 00297 00298 //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0 00299 if (_at->send("AT+CGDCONT?")) { 00300 if (_at->recv("+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%*d,%*d,%*d,%*d,%*d,%*d", 00301 &t, ip) && 00302 _at->recv("OK")) { 00303 // Check if the IP address is valid 00304 if (address.set_ip_address(ip)) { 00305 cid = t; 00306 } 00307 } 00308 } 00309 00310 // If a context has been found, use it 00311 if ((cid != -1) && (_at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK"))) { 00312 // Activate, waiting 30 seconds for the connection to be made 00313 at_set_timeout(30000); 00314 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00315 at_set_timeout(at_timeout); 00316 } 00317 00318 return success; 00319 } 00320 00321 // Activate a profile by context ID. 00322 // Note: the AT interface should be locked before this is called. 00323 bool UbloxATCellularInterface::activate_profile_by_cid(int cid, 00324 const char* apn, 00325 const char* username, 00326 const char* password, 00327 nsapi_security_t auth) 00328 { 00329 bool success = false; 00330 int at_timeout = _at_timeout; 00331 00332 if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK") && 00333 _at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, nsapi_security_to_modem_security(auth), 00334 username, password) && _at->recv("OK") && 00335 _at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK")) { 00336 00337 // Wait 30 seconds for the connection to be made 00338 at_set_timeout(30000); 00339 // Activate the protocol 00340 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00341 at_set_timeout(at_timeout); 00342 } 00343 00344 return success; 00345 } 00346 00347 // Connect the on board IP stack of the modem. 00348 bool UbloxATCellularInterface::connect_modem_stack() 00349 { 00350 bool success = false; 00351 int active = 0; 00352 const char * config = NULL; 00353 LOCK(); 00354 00355 // Check the profile 00356 if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) && 00357 _at->recv("OK")) { 00358 if (active == 0) { 00359 // If the caller hasn't entered an APN, try to find it 00360 if (_apn == NULL) { 00361 config = apnconfig(_dev_info.imsi); 00362 } 00363 00364 // Attempt to connect 00365 do { 00366 // Set up APN and IP protocol for PDP context 00367 get_next_credentials(&config); 00368 _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE; 00369 if ((_dev_info.dev != DEV_TOBY_L2) && (_dev_info.dev != DEV_MPCI_L2)) { 00370 success = activate_profile(_apn, _uname, _pwd, _auth); 00371 } else { 00372 success = activate_profile_reuse_external(); 00373 if (success) { 00374 tr_debug("Reusing external context"); 00375 } else { 00376 success = activate_profile_by_cid(1, _apn, _uname, _pwd, _auth); 00377 } 00378 } 00379 } while (!success && config && *config); 00380 } else { 00381 // If the profile is already active, we're good 00382 success = true; 00383 } 00384 } 00385 00386 if (!success) { 00387 tr_error("Failed to connect, check your APN/username/password"); 00388 } 00389 00390 UNLOCK(); 00391 return success; 00392 } 00393 00394 // Disconnect the on board IP stack of the modem. 00395 bool UbloxATCellularInterface::disconnect_modem_stack() 00396 { 00397 bool success = false; 00398 LOCK(); 00399 00400 if (get_ip_address() != NULL) { 00401 if (_at->send("AT+UPSDA=" PROFILE ",4") && _at->recv("OK")) { 00402 success = true; 00403 if (_connection_status_cb) { 00404 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 00405 } 00406 } 00407 } 00408 00409 UNLOCK(); 00410 return success; 00411 } 00412 00413 /********************************************************************** 00414 * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS 00415 **********************************************************************/ 00416 00417 // Gain access to us. 00418 NetworkStack *UbloxATCellularInterface::get_stack() 00419 { 00420 return this; 00421 } 00422 00423 // Create a socket. 00424 nsapi_error_t UbloxATCellularInterface::socket_open(nsapi_socket_t *handle, 00425 nsapi_protocol_t proto) 00426 { 00427 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00428 bool success = false; 00429 int modem_handle; 00430 SockCtrl *socket; 00431 LOCK(); 00432 00433 // Find a free socket 00434 socket = find_socket(); 00435 tr_debug("socket_open(%d)", proto); 00436 00437 if (socket != NULL) { 00438 if (proto == NSAPI_UDP) { 00439 success = _at->send("AT+USOCR=17"); 00440 } else if (proto == NSAPI_TCP) { 00441 success = _at->send("AT+USOCR=6"); 00442 } else { 00443 nsapi_error = NSAPI_ERROR_UNSUPPORTED; 00444 } 00445 00446 if (success) { 00447 nsapi_error = NSAPI_ERROR_NO_SOCKET; 00448 if (_at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00449 _at->recv("OK")) { 00450 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle); 00451 clear_socket(socket); 00452 socket->modem_handle = modem_handle; 00453 *handle = (nsapi_socket_t) socket; 00454 nsapi_error = NSAPI_ERROR_OK; 00455 } 00456 } 00457 } else { 00458 nsapi_error = NSAPI_ERROR_NO_MEMORY; 00459 } 00460 00461 UNLOCK(); 00462 return nsapi_error; 00463 } 00464 00465 // Close a socket. 00466 nsapi_error_t UbloxATCellularInterface::socket_close(nsapi_socket_t handle) 00467 { 00468 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00469 SockCtrl *socket = (SockCtrl *) handle; 00470 LOCK(); 00471 00472 tr_debug("socket_close(0x%08x)", (unsigned int) handle); 00473 00474 MBED_ASSERT (check_socket(socket)); 00475 00476 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00477 _at->recv("OK")) { 00478 clear_socket(socket); 00479 nsapi_error = NSAPI_ERROR_OK; 00480 } 00481 00482 UNLOCK(); 00483 return nsapi_error; 00484 } 00485 00486 // Bind a local port to a socket. 00487 nsapi_error_t UbloxATCellularInterface::socket_bind(nsapi_socket_t handle, 00488 const SocketAddress &address) 00489 { 00490 nsapi_error_t nsapi_error = NSAPI_ERROR_NO_SOCKET; 00491 int proto; 00492 int modem_handle; 00493 SockCtrl savedSocket; 00494 SockCtrl *socket = (SockCtrl *) handle; 00495 LOCK(); 00496 00497 tr_debug("socket_bind(0x%08x, :%d)", (unsigned int) handle, address.get_port()); 00498 00499 MBED_ASSERT (check_socket(socket)); 00500 00501 // Query the socket type 00502 if (_at->send("AT+USOCTL=%d,0", socket->modem_handle) && 00503 _at->recv("+USOCTL: %*d,0,%d\n", &proto) && 00504 _at->recv("OK")) { 00505 savedSocket = *socket; 00506 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00507 // Now close the socket and re-open it with the binding given 00508 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00509 _at->recv("OK")) { 00510 clear_socket(socket); 00511 nsapi_error = NSAPI_ERROR_CONNECTION_LOST; 00512 if (_at->send("AT+USOCR=%d,%d", proto, address.get_port()) && 00513 _at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00514 _at->recv("OK")) { 00515 *socket = savedSocket; 00516 nsapi_error = NSAPI_ERROR_OK; 00517 } 00518 } 00519 } 00520 00521 UNLOCK(); 00522 return nsapi_error; 00523 } 00524 00525 // Connect to a socket 00526 nsapi_error_t UbloxATCellularInterface::socket_connect(nsapi_socket_t handle, 00527 const SocketAddress &address) 00528 { 00529 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00530 SockCtrl *socket = (SockCtrl *) handle; 00531 LOCK(); 00532 00533 tr_debug("socket_connect(0x%08x, %s(:%d))", (unsigned int) handle, 00534 address.get_ip_address(), address.get_port()); 00535 00536 MBED_ASSERT (check_socket(socket)); 00537 00538 if (_at->send("AT+USOCO=%d,\"%s\",%d", socket->modem_handle, 00539 address.get_ip_address(), address.get_port()) && 00540 _at->recv("OK")) { 00541 nsapi_error = NSAPI_ERROR_OK; 00542 } 00543 00544 UNLOCK(); 00545 return nsapi_error; 00546 } 00547 00548 // Send to a socket. 00549 nsapi_size_or_error_t UbloxATCellularInterface::socket_send(nsapi_socket_t handle, 00550 const void *data, 00551 nsapi_size_t size) 00552 { 00553 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00554 bool success = true; 00555 const char *buf = (const char *) data; 00556 nsapi_size_t blk = MAX_WRITE_SIZE; 00557 nsapi_size_t count = size; 00558 SockCtrl *socket = (SockCtrl *) handle; 00559 00560 tr_debug("socket_send(0x%08x, 0x%08x, %d)", (unsigned int) handle, (unsigned int) data, size); 00561 00562 MBED_ASSERT (check_socket(socket)); 00563 00564 if (socket->modem_handle == SOCKET_UNUSED) { 00565 tr_debug("socket_send: socket closed"); 00566 return NSAPI_ERROR_NO_SOCKET; 00567 } 00568 00569 while ((count > 0) && success) { 00570 if (count < blk) { 00571 blk = count; 00572 } 00573 LOCK(); 00574 00575 if (_at->send("AT+USOWR=%d,%d", socket->modem_handle, blk) && _at->recv("@")) { 00576 wait_ms(50); 00577 if ((_at->write(buf, blk) < (int) blk) || 00578 !_at->recv("OK")) { 00579 success = false; 00580 } 00581 } else { 00582 success = false; 00583 } 00584 00585 UNLOCK(); 00586 buf += blk; 00587 count -= blk; 00588 } 00589 00590 if (success) { 00591 nsapi_error_size = size - count; 00592 if (_debug_trace_on) { 00593 tr_debug("socket_send: %d \"%*.*s\"", size, size, size, (char *) data); 00594 } 00595 } 00596 00597 return nsapi_error_size; 00598 } 00599 00600 // Send to an IP address. 00601 nsapi_size_or_error_t UbloxATCellularInterface::socket_sendto(nsapi_socket_t handle, 00602 const SocketAddress &address, 00603 const void *data, 00604 nsapi_size_t size) 00605 { 00606 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00607 bool success = true; 00608 const char *buf = (const char *) data; 00609 nsapi_size_t blk = MAX_WRITE_SIZE; 00610 nsapi_size_t count = size; 00611 SockCtrl *socket = (SockCtrl *) handle; 00612 00613 tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle, 00614 address.get_ip_address(), address.get_port(), (unsigned int) data, size); 00615 00616 MBED_ASSERT (check_socket(socket)); 00617 00618 if (size > MAX_WRITE_SIZE) { 00619 tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE); 00620 } 00621 00622 while ((count > 0) && success) { 00623 if (count < blk) { 00624 blk = count; 00625 } 00626 LOCK(); 00627 00628 if (_at->send("AT+USOST=%d,\"%s\",%d,%d", socket->modem_handle, 00629 address.get_ip_address(), address.get_port(), blk) && 00630 _at->recv("@")) { 00631 wait_ms(50); 00632 if ((_at->write(buf, blk) >= (int) blk) && 00633 _at->recv("OK")) { 00634 } else { 00635 success = false; 00636 } 00637 } else { 00638 success = false; 00639 } 00640 00641 UNLOCK(); 00642 buf += blk; 00643 count -= blk; 00644 } 00645 00646 if (success) { 00647 nsapi_error_size = size - count; 00648 if (_debug_trace_on) { 00649 tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data); 00650 } 00651 } 00652 00653 return nsapi_error_size; 00654 } 00655 00656 // Receive from a socket, TCP style. 00657 nsapi_size_or_error_t UbloxATCellularInterface::socket_recv(nsapi_socket_t handle, 00658 void *data, 00659 nsapi_size_t size) 00660 { 00661 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00662 bool success = true; 00663 char *buf = (char *) data; 00664 nsapi_size_t read_blk; 00665 nsapi_size_t count = 0; 00666 unsigned int usord_sz; 00667 int read_sz; 00668 Timer timer; 00669 SockCtrl *socket = (SockCtrl *) handle; 00670 int at_timeout; 00671 00672 tr_debug("socket_recv(0x%08x, 0x%08x, %d)", 00673 (unsigned int) handle, (unsigned int) data, size); 00674 00675 MBED_ASSERT (check_socket(socket)); 00676 00677 if (socket->modem_handle == SOCKET_UNUSED) { 00678 tr_debug("socket_recv: socket closed"); 00679 return NSAPI_ERROR_NO_SOCKET; 00680 } 00681 00682 timer.start(); 00683 00684 while (success && (size > 0)) { 00685 LOCK(); 00686 at_timeout = _at_timeout; 00687 at_set_timeout(1000); 00688 00689 read_blk = MAX_READ_SIZE; 00690 if (read_blk > size) { 00691 read_blk = size; 00692 } 00693 if (socket->pending > 0) { 00694 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00695 (unsigned int) socket, socket->modem_handle, socket->pending); 00696 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00697 // be able to read packets of any size without 00698 // losing characters in UARTSerial 00699 if (_at->send("AT+USORD=%d,%d", socket->modem_handle, read_blk) && 00700 _at->recv("+USORD: %*d,%d,\"", &usord_sz)) { 00701 // Must use what +USORD returns here as it may be less or more than we asked for 00702 if (usord_sz > socket->pending) { 00703 socket->pending = 0; 00704 } else { 00705 socket->pending -= usord_sz; 00706 } 00707 // Note: insert no debug between _at->recv() and _at->read(), no time... 00708 if (usord_sz > size) { 00709 usord_sz = size; 00710 } 00711 read_sz = _at->read(buf, usord_sz); 00712 if (read_sz > 0) { 00713 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00714 socket->modem_handle); 00715 if (_debug_trace_on) { 00716 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00717 } 00718 count += read_sz; 00719 buf += read_sz; 00720 size -= read_sz; 00721 } else { 00722 // read() should not fail 00723 success = false; 00724 } 00725 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00726 (unsigned int) socket, socket->modem_handle, socket->pending); 00727 // Wait for the "OK" before continuing 00728 _at->recv("OK"); 00729 } else { 00730 // Should never fail to do _at->send()/_at->recv() 00731 success = false; 00732 } 00733 _at->debug_on(_debug_trace_on); 00734 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00735 // Wait for URCs 00736 _at->recv(UNNATURAL_STRING); 00737 } else { 00738 if (count == 0) { 00739 // Timeout with nothing received 00740 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00741 success = false; 00742 } 00743 size = 0; // This simply to cause an exit 00744 } 00745 00746 at_set_timeout(at_timeout); 00747 UNLOCK(); 00748 } 00749 timer.stop(); 00750 00751 if (success) { 00752 nsapi_error_size = count; 00753 } 00754 00755 if (_debug_trace_on) { 00756 tr_debug("socket_recv: %d \"%*.*s\"", count, count, count, buf - count); 00757 } else { 00758 tr_debug("socket_recv: received %d byte(s)", count); 00759 } 00760 00761 return nsapi_error_size; 00762 } 00763 00764 // Receive a packet over a UDP socket. 00765 nsapi_size_or_error_t UbloxATCellularInterface::socket_recvfrom(nsapi_socket_t handle, 00766 SocketAddress *address, 00767 void *data, 00768 nsapi_size_t size) 00769 { 00770 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00771 bool success = true; 00772 char *buf = (char *) data; 00773 nsapi_size_t read_blk; 00774 nsapi_size_t count = 0; 00775 char ipAddress[NSAPI_IP_SIZE]; 00776 int port; 00777 unsigned int usorf_sz; 00778 int read_sz; 00779 Timer timer; 00780 SockCtrl *socket = (SockCtrl *) handle; 00781 int at_timeout; 00782 00783 tr_debug("socket_recvfrom(0x%08x, 0x%08x, %d)", 00784 (unsigned int) handle, (unsigned int) data, size); 00785 00786 MBED_ASSERT (check_socket(socket)); 00787 00788 timer.start(); 00789 00790 while (success && (size > 0)) { 00791 LOCK(); 00792 at_timeout = _at_timeout; 00793 at_set_timeout(1000); 00794 00795 read_blk = MAX_READ_SIZE; 00796 if (read_blk > size) { 00797 read_blk = size; 00798 } 00799 if (socket->pending > 0) { 00800 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00801 (unsigned int) socket, socket->modem_handle, socket->pending); 00802 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 00803 00804 // Note: the maximum length of UDP packet we can receive comes from 00805 // fitting all of the following into one buffer: 00806 // 00807 // +USORF: xx,"max.len.ip.address.ipv4.or.ipv6",yyyyy,wwww,"the_data"\r\n 00808 // 00809 // where xx is the handle, max.len.ip.address.ipv4.or.ipv6 is NSAPI_IP_SIZE, 00810 // yyyyy is the port number (max 65536), wwww is the length of the data and 00811 // the_data is binary data. I make that 29 + 48 + len(the_data), 00812 // so the overhead is 77 bytes. 00813 00814 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00815 // be able to read packets of any size without 00816 // losing characters in UARTSerial 00817 if (_at->send("AT+USORF=%d,%d", socket->modem_handle, read_blk) && 00818 _at->recv("+USORF: %*d,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%d,%d,\"", 00819 ipAddress, &port, &usorf_sz)) { 00820 // Must use what +USORF returns here as it may be less or more than we asked for 00821 if (usorf_sz > socket->pending) { 00822 socket->pending = 0; 00823 } else { 00824 socket->pending -= usorf_sz; 00825 } 00826 // Note: insert no debug between _at->recv() and _at->read(), no time... 00827 if (usorf_sz > size) { 00828 usorf_sz = size; 00829 } 00830 read_sz = _at->read(buf, usorf_sz); 00831 if (read_sz > 0) { 00832 address->set_ip_address(ipAddress); 00833 address->set_port(port); 00834 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00835 socket->modem_handle); 00836 if (_debug_trace_on) { 00837 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00838 } 00839 count += read_sz; 00840 buf += read_sz; 00841 size -= read_sz; 00842 if ((usorf_sz < read_blk) || (usorf_sz == MAX_READ_SIZE)) { 00843 size = 0; // If we've received less than we asked for, or 00844 // the max size, then a whole UDP packet has arrived and 00845 // this means DONE. 00846 } 00847 } else { 00848 // read() should not fail 00849 success = false; 00850 } 00851 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00852 (unsigned int) socket, socket->modem_handle, socket->pending); 00853 // Wait for the "OK" before continuing 00854 _at->recv("OK"); 00855 } else { 00856 // Should never fail to do _at->send()/_at->recv() 00857 success = false; 00858 } 00859 _at->debug_on(_debug_trace_on); 00860 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00861 // Wait for URCs 00862 _at->recv(UNNATURAL_STRING); 00863 } else { 00864 if (count == 0) { 00865 // Timeout with nothing received 00866 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00867 success = false; 00868 } 00869 size = 0; // This simply to cause an exit 00870 } 00871 00872 at_set_timeout(at_timeout); 00873 UNLOCK(); 00874 } 00875 timer.stop(); 00876 00877 if (success) { 00878 nsapi_error_size = count; 00879 } 00880 00881 if (_debug_trace_on) { 00882 tr_debug("socket_recvfrom: %d \"%*.*s\"", count, count, count, buf - count); 00883 } else { 00884 tr_debug("socket_recvfrom: received %d byte(s)", count); 00885 } 00886 00887 return nsapi_error_size; 00888 } 00889 00890 // Attach an event callback to a socket, required for asynchronous 00891 // data reception 00892 void UbloxATCellularInterface::socket_attach(nsapi_socket_t handle, 00893 void (*callback)(void *), 00894 void *data) 00895 { 00896 SockCtrl *socket = (SockCtrl *) handle; 00897 00898 MBED_ASSERT (check_socket(socket)); 00899 00900 socket->callback = callback; 00901 socket->data = data; 00902 } 00903 00904 // Unsupported TCP server functions. 00905 nsapi_error_t UbloxATCellularInterface::socket_listen(nsapi_socket_t handle, 00906 int backlog) 00907 { 00908 return NSAPI_ERROR_UNSUPPORTED; 00909 } 00910 nsapi_error_t UbloxATCellularInterface::socket_accept(nsapi_socket_t server, 00911 nsapi_socket_t *handle, 00912 SocketAddress *address) 00913 { 00914 return NSAPI_ERROR_UNSUPPORTED; 00915 } 00916 00917 // Unsupported option functions. 00918 nsapi_error_t UbloxATCellularInterface::setsockopt(nsapi_socket_t handle, 00919 int level, int optname, 00920 const void *optval, 00921 unsigned optlen) 00922 { 00923 return NSAPI_ERROR_UNSUPPORTED; 00924 } 00925 nsapi_error_t UbloxATCellularInterface::getsockopt(nsapi_socket_t handle, 00926 int level, int optname, 00927 void *optval, 00928 unsigned *optlen) 00929 { 00930 return NSAPI_ERROR_UNSUPPORTED; 00931 } 00932 00933 /********************************************************************** 00934 * PUBLIC METHODS 00935 **********************************************************************/ 00936 00937 // Constructor. 00938 UbloxATCellularInterface::UbloxATCellularInterface(PinName tx, 00939 PinName rx, 00940 int baud, 00941 bool debug_on, 00942 osPriority priority) 00943 { 00944 _sim_pin_check_change_pending = false; 00945 _sim_pin_check_change_pending_enabled_value = false; 00946 _sim_pin_change_pending = false; 00947 _sim_pin_change_pending_new_pin_value = NULL; 00948 _run_event_thread = true; 00949 _apn = NULL; 00950 _uname = NULL; 00951 _pwd = NULL; 00952 _connection_status_cb = NULL; 00953 00954 // Initialise sockets storage 00955 memset(_sockets, 0, sizeof(_sockets)); 00956 for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) { 00957 _sockets[socket].modem_handle = SOCKET_UNUSED; 00958 _sockets[socket].callback = NULL; 00959 _sockets[socket].data = NULL; 00960 } 00961 00962 // The authentication to use 00963 _auth = NSAPI_SECURITY_UNKNOWN; 00964 00965 // Nullify the temporary IP address storage 00966 _ip = NULL; 00967 00968 // Initialise the base class, which starts the AT parser 00969 baseClassInit(tx, rx, baud, debug_on); 00970 00971 // Start the event handler thread for Rx data 00972 event_thread.start(callback(this, &UbloxATCellularInterface::handle_event)); 00973 event_thread.set_priority(priority); 00974 00975 // URC handlers for sockets 00976 _at->oob("+UUSORD", callback(this, &UbloxATCellularInterface::UUSORD_URC)); 00977 _at->oob("+UUSORF", callback(this, &UbloxATCellularInterface::UUSORF_URC)); 00978 _at->oob("+UUSOCL", callback(this, &UbloxATCellularInterface::UUSOCL_URC)); 00979 _at->oob("+UUPSDD", callback(this, &UbloxATCellularInterface::UUPSDD_URC)); 00980 } 00981 00982 // Destructor. 00983 UbloxATCellularInterface::~UbloxATCellularInterface() 00984 { 00985 // Let the event thread shut down tidily 00986 _run_event_thread = false; 00987 event_thread.join(); 00988 00989 // Free _ip if it was ever allocated 00990 free(_ip); 00991 } 00992 00993 // Set the authentication scheme. 00994 void UbloxATCellularInterface::set_authentication(nsapi_security_t auth) 00995 { 00996 _auth = auth; 00997 } 00998 00999 // Set APN, user name and password. 01000 void UbloxATCellularInterface::set_credentials(const char *apn, 01001 const char *uname, 01002 const char *pwd) 01003 { 01004 _apn = apn; 01005 _uname = uname; 01006 _pwd = pwd; 01007 } 01008 01009 // Set PIN. 01010 void UbloxATCellularInterface::set_sim_pin(const char *pin) 01011 { 01012 set_pin(pin); 01013 } 01014 01015 // Get the IP address of a host. 01016 nsapi_error_t UbloxATCellularInterface::gethostbyname(const char *host, 01017 SocketAddress *address, 01018 nsapi_version_t version) 01019 { 01020 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01021 int at_timeout; 01022 char ipAddress[NSAPI_IP_SIZE]; 01023 01024 if (address->set_ip_address(host)) { 01025 nsapi_error = NSAPI_ERROR_OK; 01026 } else { 01027 LOCK(); 01028 // This interrogation can sometimes take longer than the usual 8 seconds 01029 at_timeout = _at_timeout; 01030 at_set_timeout(60000); 01031 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 01032 if (_at->send("AT+UDNSRN=0,\"%s\"", host) && 01033 _at->recv("+UDNSRN: \"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", ipAddress) && 01034 _at->recv("OK")) { 01035 if (address->set_ip_address(ipAddress)) { 01036 nsapi_error = NSAPI_ERROR_OK; 01037 } 01038 } 01039 at_set_timeout(at_timeout); 01040 UNLOCK(); 01041 } 01042 01043 return nsapi_error; 01044 } 01045 01046 // Make a cellular connection 01047 nsapi_error_t UbloxATCellularInterface::connect(const char *sim_pin, 01048 const char *apn, 01049 const char *uname, 01050 const char *pwd) 01051 { 01052 nsapi_error_t nsapi_error; 01053 01054 if (sim_pin != NULL) { 01055 _pin = sim_pin; 01056 } 01057 01058 if (apn != NULL) { 01059 _apn = apn; 01060 } 01061 01062 if ((uname != NULL) && (pwd != NULL)) { 01063 _uname = uname; 01064 _pwd = pwd; 01065 } else { 01066 _uname = NULL; 01067 _pwd = NULL; 01068 } 01069 01070 nsapi_error = connect(); 01071 01072 return nsapi_error; 01073 } 01074 01075 // Make a cellular connection using the IP stack on board the cellular modem 01076 nsapi_error_t UbloxATCellularInterface::connect() 01077 { 01078 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01079 bool registered = false; 01080 01081 // Set up modem and then register with the network 01082 if (init()) { 01083 nsapi_error = NSAPI_ERROR_NO_CONNECTION; 01084 // Perform any pending SIM actions 01085 if (_sim_pin_check_change_pending) { 01086 if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) { 01087 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01088 } 01089 _sim_pin_check_change_pending = false; 01090 } 01091 if (_sim_pin_change_pending) { 01092 if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) { 01093 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01094 } 01095 _sim_pin_change_pending = false; 01096 } 01097 01098 if (nsapi_error == NSAPI_ERROR_NO_CONNECTION) { 01099 for (int retries = 0; !registered && (retries < 3); retries++) { 01100 if (nwk_registration()) { 01101 registered = true;; 01102 } 01103 } 01104 } 01105 } 01106 01107 // Attempt to establish a connection 01108 #ifdef TARGET_UBLOX_C030_R410M 01109 if (registered) { 01110 #else 01111 if (registered && connect_modem_stack()) { 01112 #endif 01113 nsapi_error = NSAPI_ERROR_OK; 01114 } 01115 01116 return nsapi_error; 01117 } 01118 01119 // User initiated disconnect. 01120 nsapi_error_t UbloxATCellularInterface::disconnect() 01121 { 01122 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01123 01124 if (disconnect_modem_stack() && nwk_deregistration()) { 01125 nsapi_error = NSAPI_ERROR_OK; 01126 } 01127 01128 return nsapi_error; 01129 } 01130 01131 // Enable or disable SIM PIN check lock. 01132 nsapi_error_t UbloxATCellularInterface::set_sim_pin_check(bool set, 01133 bool immediate, 01134 const char *sim_pin) 01135 { 01136 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01137 01138 if (sim_pin != NULL) { 01139 _pin = sim_pin; 01140 } 01141 01142 if (immediate) { 01143 if (init()) { 01144 if (sim_pin_check_enable(set)) { 01145 nsapi_error = NSAPI_ERROR_OK; 01146 } 01147 } else { 01148 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01149 } 01150 } else { 01151 nsapi_error = NSAPI_ERROR_OK; 01152 _sim_pin_check_change_pending = true; 01153 _sim_pin_check_change_pending_enabled_value = set; 01154 } 01155 01156 return nsapi_error; 01157 } 01158 01159 // Change the PIN code for the SIM card. 01160 nsapi_error_t UbloxATCellularInterface::set_new_sim_pin(const char *new_pin, 01161 bool immediate, 01162 const char *old_pin) 01163 { 01164 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01165 01166 if (old_pin != NULL) { 01167 _pin = old_pin; 01168 } 01169 01170 if (immediate) { 01171 if (init()) { 01172 if (change_sim_pin(new_pin)) { 01173 nsapi_error = NSAPI_ERROR_OK; 01174 } 01175 } else { 01176 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01177 } 01178 } else { 01179 nsapi_error = NSAPI_ERROR_OK; 01180 _sim_pin_change_pending = true; 01181 _sim_pin_change_pending_new_pin_value = new_pin; 01182 } 01183 01184 return nsapi_error; 01185 } 01186 01187 // Determine if the connection is up. 01188 bool UbloxATCellularInterface::is_connected() 01189 { 01190 return get_ip_address() != NULL; 01191 } 01192 01193 // Get the IP address of the on-board modem IP stack. 01194 const char * UbloxATCellularInterface::get_ip_address() 01195 { 01196 SocketAddress address; 01197 LOCK(); 01198 01199 if (_ip == NULL) { 01200 // Temporary storage for an IP address string with terminator 01201 _ip = (char *) malloc(NSAPI_IP_SIZE); 01202 } 01203 01204 if (_ip != NULL) { 01205 memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator 01206 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] 01207 // If we get back a quoted "w.x.y.z" then we have an IP address, 01208 // otherwise we don't. 01209 if (!_at->send("AT+UPSND=" PROFILE ",0") || 01210 !_at->recv("+UPSND: " PROFILE ",0,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", _ip) || 01211 !_at->recv("OK") || 01212 !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one 01213 !address) { // Return null if the address is zero 01214 free (_ip); 01215 _ip = NULL; 01216 } 01217 } 01218 01219 UNLOCK(); 01220 return _ip; 01221 } 01222 01223 // Get the local network mask. 01224 const char *UbloxATCellularInterface::get_netmask() 01225 { 01226 // Not implemented. 01227 return NULL; 01228 } 01229 01230 // Get the local gateways. 01231 const char *UbloxATCellularInterface::get_gateway() 01232 { 01233 return get_ip_address(); 01234 } 01235 01236 // Callback in case the connection is lost. 01237 void UbloxATCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb) 01238 { 01239 _connection_status_cb = cb; 01240 } 01241 01242 // End of file 01243
Generated on Thu Jul 21 2022 15:13:48 by
![doxygen](doxygen.png)