Implementation of the CellularInterface for u-blox C030 boards with N2xx modems. Note: requires the N211 module firmware to be at least 06.57 A01.02.

Dependents:   example-ublox-cellular-interface HelloMQTT example-ublox-cellular-interface_r410M example-ublox-mbed-client ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxATCellularInterfaceN2xx.cpp Source File

UbloxATCellularInterfaceN2xx.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 "UbloxATCellularInterfaceN2xx.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 // When calling the SendTo function, the large hex string for the bytes to send is chopped into chunks 
00031 #define SENDTO_CHUNK_SIZE 50
00032 
00033 /**********************************************************************
00034  * PRIVATE METHODS
00035  **********************************************************************/
00036  
00037 // Event thread for asynchronous received data handling.
00038 void UbloxATCellularInterfaceN2xx::handle_event(){
00039     pollfh fhs;
00040     int count;
00041     int at_timeout;
00042 
00043     fhs.fh = _fh;
00044     fhs.events = POLLIN;
00045 
00046     while (true) {
00047         count = poll(&fhs, 1, 1000);
00048         if (count > 0 && (fhs.revents & POLLIN)) {
00049             LOCK();
00050             at_timeout = _at_timeout;
00051             at_set_timeout(10); // Avoid blocking but also make sure we don't
00052                                 // time out if we get ahead of the serial port
00053             _at->debug_on(false); // Debug here screws with the test output
00054             // Let the URCs run
00055             _at->recv(UNNATURAL_STRING);
00056             _at->debug_on(_debug_trace_on);
00057             at_set_timeout(at_timeout);
00058             UNLOCK();
00059         }
00060     }
00061 }
00062 
00063 // Find or create a socket from the list.
00064 UbloxATCellularInterfaceN2xx::SockCtrl * UbloxATCellularInterfaceN2xx::find_socket(int modem_handle)
00065 {
00066     UbloxATCellularInterfaceN2xx::SockCtrl *socket = NULL;
00067 
00068     for (unsigned int x = 0; (socket == NULL) && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) {
00069         if (_sockets[x].modem_handle == modem_handle) {
00070             socket = &(_sockets[x]);
00071         }
00072     }
00073 
00074     return socket;
00075 }
00076 
00077 // Clear out the storage for a socket
00078 void UbloxATCellularInterfaceN2xx::clear_socket(UbloxATCellularInterfaceN2xx::SockCtrl * socket)
00079 {
00080     if (socket != NULL) {
00081         socket->modem_handle = SOCKET_UNUSED;
00082         socket->pending     = 0;
00083         socket->callback    = NULL;
00084         socket->data        = NULL;
00085     }
00086 }
00087 
00088 // Check that a socket pointer is valid
00089 bool UbloxATCellularInterfaceN2xx::check_socket(SockCtrl * socket)
00090 {
00091     bool success = false;
00092 
00093     if (socket != NULL) {
00094         for (unsigned int x = 0; !success && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) {
00095             if (socket == &(_sockets[x])) {
00096                 success = true;
00097             }
00098         }
00099     }
00100 
00101     return success;
00102 }
00103 
00104 // Callback for Socket Read From URC.
00105 void UbloxATCellularInterfaceN2xx::NSONMI_URC()
00106 {
00107     int a;
00108     int b;
00109     char buf[32];
00110     SockCtrl *socket;
00111     
00112     // Note: not calling _at->recv() from here as we're
00113     // already in an _at->recv()
00114     // +UUSORF: <socket>,<length>
00115     if (read_at_to_newline(buf, sizeof (buf)) > 0) {
00116         tr_debug("NSONMI URC");
00117         if (sscanf(buf, ":%d,%d", &a, &b) == 2) {         
00118             socket = find_socket(a);        
00119             if (socket != NULL) {
00120                 socket->pending += b;
00121                 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
00122                          (unsigned int) socket, a, socket->pending);
00123                 if (socket->callback != NULL) {
00124                     tr_debug("***** Calling callback...");
00125                     socket->callback(socket->data);
00126                     tr_debug("***** Callback finished");
00127                 } else {
00128                     tr_debug("No callback found for socket.");
00129                 }
00130             } else {
00131                 tr_debug("Can't find socket with modem handle %d", a);
00132             }
00133         }
00134     }
00135 }
00136 
00137 /**********************************************************************
00138  * PROTECTED METHODS: GENERAL
00139  **********************************************************************/
00140 
00141 // Get the next set of credentials, based on IMSI.
00142 void UbloxATCellularInterfaceN2xx::get_next_credentials(const char * config)
00143 {
00144     if (config) {
00145         _apn    = _APN_GET(config);
00146         _uname  = _APN_GET(config);
00147         _pwd    = _APN_GET(config);
00148     }
00149 
00150     _apn    = _apn     ?  _apn    : "";
00151     _uname  = _uname   ?  _uname  : "";
00152     _pwd    = _pwd     ?  _pwd    : "";
00153 }
00154 
00155 /**********************************************************************
00156  * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS
00157  **********************************************************************/
00158 
00159 // Gain access to us.
00160 NetworkStack *UbloxATCellularInterfaceN2xx::get_stack()
00161 {
00162     return this;
00163 }
00164 
00165 // Create a socket.
00166 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_open(nsapi_socket_t *handle,
00167                                                     nsapi_protocol_t proto)
00168 {
00169     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00170     int modem_handle =0;
00171     SockCtrl *socket;
00172   
00173     if (proto != NSAPI_UDP) {
00174         return NSAPI_ERROR_UNSUPPORTED;
00175     }
00176    
00177     LOCK();
00178 
00179     // Find a free socket
00180     socket = find_socket();
00181     if (socket != NULL) {  
00182         tr_debug("socket_open(%d)", proto);    
00183         if (_at->send("AT+NSOCR=\"DGRAM\",17,%d", _localListenPort) &&            
00184             _at->recv("%d\n", &modem_handle) && 
00185             _at->recv("OK")) {
00186                 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle);
00187                 clear_socket(socket);
00188                 socket->modem_handle = modem_handle;
00189                 *handle = (nsapi_socket_t) socket;
00190                 nsapi_error = NSAPI_ERROR_OK;
00191         } else {
00192             tr_error("Couldn't open socket using AT command");
00193         }
00194     } else {
00195         tr_error("Can't find a socket to use");
00196         nsapi_error = NSAPI_ERROR_NO_MEMORY;
00197     }
00198 
00199     UNLOCK();
00200     return nsapi_error;
00201 }
00202 
00203 
00204 // Close a socket.
00205 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_close(nsapi_socket_t handle)
00206 {
00207     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00208     SockCtrl *socket = (SockCtrl *) handle;
00209     LOCK();
00210 
00211     tr_debug("socket_close(0x%08x)", (unsigned int) handle);
00212 
00213     MBED_ASSERT (check_socket(socket));
00214 
00215     if (_at->send("AT+NSOCL=%d", socket->modem_handle) &&
00216         _at->recv("OK")) {
00217         clear_socket(socket);
00218         nsapi_error = NSAPI_ERROR_OK;
00219     } else {
00220         tr_error("Failed to close socket %d", socket->modem_handle);
00221     }
00222 
00223     UNLOCK();
00224     return nsapi_error;
00225 }
00226 
00227 // Bind a local port to a socket.
00228 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_bind(nsapi_socket_t handle,
00229                                                     const SocketAddress &address)
00230 {
00231     return NSAPI_ERROR_UNSUPPORTED;
00232 }
00233 
00234 // Connect to a socket
00235 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_connect(nsapi_socket_t handle,
00236                                                        const SocketAddress &address)
00237 {
00238 return NSAPI_ERROR_UNSUPPORTED;  
00239 }
00240 
00241 // Send to a socket.
00242 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_send(nsapi_socket_t handle,
00243                                                             const void *data,
00244                                                             nsapi_size_t size)
00245 {
00246     return NSAPI_ERROR_UNSUPPORTED;  
00247 }
00248 
00249 // Send to an IP address.
00250 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_sendto(nsapi_socket_t handle,
00251                                                               const SocketAddress &address,
00252                                                               const void *data,
00253                                                               nsapi_size_t size)
00254 {
00255     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00256     bool success = true;
00257     const char *buf = (const char *) data;
00258     nsapi_size_t blk = MAX_WRITE_SIZE_N2XX;
00259     nsapi_size_t count = size;
00260     SockCtrl *socket = (SockCtrl *) handle;
00261 
00262     tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle,
00263              address.get_ip_address(), address.get_port(), (unsigned int) data, size);
00264 
00265     MBED_ASSERT (check_socket(socket));
00266 
00267     tr_debug("Max Write Size for SendTo: %d", MAX_WRITE_SIZE_N2XX);
00268     if (size > MAX_WRITE_SIZE_N2XX) {
00269         tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE_N2XX);
00270     }
00271 
00272     while ((count > 0) && success) {
00273         if (count < blk) {
00274             blk = count;
00275         }
00276         
00277         // call the AT Helper function to send the bytes
00278         tr_debug("Sending %d bytes....", blk);
00279         int sent = sendto(socket, address, buf, blk);
00280         if (sent < 0) {
00281             tr_error("Something went wrong! %d", sent);
00282             return NSAPI_ERROR_DEVICE_ERROR;
00283         }
00284         
00285         buf += sent;
00286         count -= sent;
00287     }
00288 
00289     if (success) {
00290         nsapi_error_size = size - count;
00291         if (_debug_trace_on) {
00292             tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data);
00293         }
00294     }
00295 
00296     return nsapi_error_size;
00297 }
00298 
00299 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::sendto(SockCtrl *socket, const SocketAddress &address, const char *buf, int size) {
00300     nsapi_size_or_error_t sent = NSAPI_ERROR_DEVICE_ERROR;
00301     int id;
00302         
00303     char *dataStr = (char *) malloc((size * 2) + 1);
00304     if (dataStr == NULL) {
00305         tr_error("Couldn't allocate memory for hex string conversion.");
00306         return NSAPI_ERROR_NO_MEMORY;
00307     }
00308     
00309     tr_debug("Converting byte array to hex string");
00310     bin_to_hex(buf, size, dataStr);
00311     tr_debug("Got hex string");
00312     
00313     // AT+NSOSTF= socket, remote_addr, remote_port, length, data
00314     tr_debug("Writing AT+NSOSTF=<sktid>,<ipaddr>,<port>,<flags>,<size>,<hex string> command...");    
00315     char *cmdStr = (char *) malloc(50);
00316     if (cmdStr == NULL) {
00317         tr_error("Couldn't allocate memory for AT cmd string.");
00318         return NSAPI_ERROR_NO_MEMORY;
00319     }
00320             
00321     int cmdsize = sprintf(cmdStr, "AT+NSOSTF=%d,\"%s\",%d,0x0,%d,\"", socket->modem_handle, address.get_ip_address(), address.get_port(), size);    
00322     tr_debug("%s", cmdStr);
00323     
00324     LOCK();
00325     if (_at->write(cmdStr, cmdsize) && sendATChopped(dataStr)) 
00326     {
00327         tr_debug("Finished sending AT+NSOST comamnd, reading back the 'sent' size...");
00328         if (_at->recv("%d,%d\n", &id, &sent) && _at->recv("OK")) {            
00329             tr_debug("Sent %d bytes on socket %d", sent, id);
00330         } else {
00331             tr_error("Didn't get the Sent size or OK");
00332         }
00333     } else {
00334         tr_error("Didn't send the AT command!");
00335     }
00336     UNLOCK();  
00337 
00338     free(cmdStr);    
00339     free(dataStr);
00340        
00341     return sent;
00342 }
00343 
00344 bool UbloxATCellularInterfaceN2xx::sendATChopped(const char *cmd)
00345 {
00346     char buff[SENDTO_CHUNK_SIZE];
00347     tr_debug("Chopping up large AT text of %d characters.", strlen(cmd));
00348     
00349     while (*cmd != '\0')
00350     {
00351         int i=0;
00352         
00353         for (i=0; i<SENDTO_CHUNK_SIZE; i++) {
00354             buff[i] = *cmd;
00355             
00356             // if we have copied the NULL terminator, we can exit 
00357             if (*cmd == '\0')  
00358                 break;
00359             
00360             // still more characters to copy, so move along
00361             cmd++;
00362         }
00363        
00364        // if we are at the end of the line, use the send command to 
00365        // provide the \r\n terminator for the AT command
00366         if (*cmd == '\0') {
00367             tr_debug("send(%d): %s", i, buff);            
00368             // write the last buffer...
00369             if (!_at->write(buff,i))
00370                 return false;
00371             
00372             // ...send the enclosing quote to complete the AT command
00373             if (!_at->send("\""))
00374                 return false;
00375         } else {
00376             tr_debug("write(50): %s", buff);
00377             if (!_at->write(buff, 50))
00378                 return false;
00379         }
00380      }
00381      
00382      return true;
00383 }
00384 
00385 void UbloxATCellularInterfaceN2xx::bin_to_hex(const char *buff, unsigned int length, char *output)
00386 {
00387     char binHex[] = "0123456789ABCDEF";
00388     
00389     *output = '\0';
00390 
00391     for (; length > 0; --length)
00392     {
00393         unsigned char byte = *buff++;
00394 
00395         *output++ = binHex[(byte >> 4) & 0x0F];
00396         *output++ = binHex[byte & 0x0F];
00397     }
00398     
00399     *output++ = '\0';
00400 }
00401 
00402 // Receive from a socket, TCP style.
00403 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recv(nsapi_socket_t handle,
00404                                                             void *data,
00405                                                             nsapi_size_t size)
00406 {
00407     return NSAPI_ERROR_UNSUPPORTED;
00408 }
00409 
00410 // Receive a packet over a UDP socket.
00411 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recvfrom(nsapi_socket_t handle,
00412                                                                 SocketAddress *address,
00413                                                                 void *data,
00414                                                                 nsapi_size_t size)
00415 {
00416     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00417     bool success = true;
00418     char *buf = (char *) data;
00419     nsapi_size_t read_blk;
00420     nsapi_size_t count = 0;
00421     int at_timeout = _at_timeout;
00422         
00423     char * tmpBuf = NULL;
00424 
00425     Timer timer;
00426     SockCtrl *socket = (SockCtrl *) handle;
00427 
00428     tr_debug("socket_recvfrom(0x%08x, 0x%08x, SIZE=%d)", (unsigned int) handle, (unsigned int) data, size);
00429 
00430     MBED_ASSERT (check_socket(socket));
00431     timer.start();
00432 
00433     while (success && (size > 0)) {
00434         LOCK();
00435         at_timeout = _at_timeout;
00436         at_set_timeout(1000);
00437         
00438         read_blk = MAX_READ_SIZE_N2XX;
00439         if (read_blk > size) {
00440             read_blk = size;
00441         }
00442         
00443         if (socket->pending > 0) {
00444             tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
00445                      (unsigned int) socket, socket->modem_handle, socket->pending);
00446     
00447             tmpBuf = (char *) malloc(read_blk);
00448             if (tmpBuf == NULL) {
00449                 return NSAPI_ERROR_NO_MEMORY;
00450             }
00451             
00452             // call the AT helper function to get the bytes
00453             nsapi_error_size = receivefrom(socket->modem_handle, address, read_blk, tmpBuf);
00454                     
00455             if (nsapi_error_size >= 0) {
00456                 memcpy(buf, tmpBuf, nsapi_error_size);
00457 
00458                 if (read_blk != (uint32_t) nsapi_error_size)
00459                     tr_debug("Requested size is not the same as the returned size.");
00460                 
00461                 socket->pending -= nsapi_error_size;                
00462                 count += nsapi_error_size;
00463                 buf += nsapi_error_size;
00464                 size -= nsapi_error_size;
00465                 
00466                 if (((uint32_t) nsapi_error_size < read_blk) || (nsapi_error_size == MAX_READ_SIZE_N2XX))
00467                     size = 0;     // If we've received less than we asked for, or
00468                                   // the max size, then a whole UDP packet has arrived and
00469                                   // this means DONE.
00470             } else {
00471                 // Should never fail to read when there is pending data
00472                 success = false;
00473             }
00474             free(tmpBuf);
00475         } else if (timer.read_ms() < SOCKET_TIMEOUT) {
00476             // Wait for URCs
00477             tr_debug("Waiting for URC...");
00478             _at->recv(UNNATURAL_STRING);
00479         } else {
00480             tr_debug("Nothing pending...");
00481             if (count == 0) {
00482                 tr_debug("Nothing received, so timeout with block");
00483                 // Timeout with nothing received
00484                 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK;
00485                 success = false;
00486             }
00487             size = 0; // This simply to cause an exit
00488         }
00489         
00490         at_set_timeout(at_timeout);
00491         UNLOCK();
00492     }
00493     timer.stop();
00494 
00495     if (success) {
00496         tr_debug("socket_recvfrom: %d SUCCESS!", count);
00497         nsapi_error_size = count;
00498     } else {
00499        tr_debug("socket_recvfrom: FAILED");
00500     }
00501     
00502     return nsapi_error_size;
00503 }
00504 
00505 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::receivefrom(int modem_handle, SocketAddress *address, int length, char *buf) {
00506     char ipAddress[NSAPI_IP_SIZE];
00507     nsapi_size_or_error_t size;
00508 
00509     memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
00510     
00511     if (length > MAX_READ_SIZE_N2XX) {
00512         return NSAPI_ERROR_UNSUPPORTED;
00513     }
00514     
00515     char * tmpBuf = (char *) malloc(length*2);
00516     if (tmpBuf == NULL)
00517         return NSAPI_ERROR_NO_MEMORY;
00518     
00519     int remaining;
00520     
00521     _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to
00522                       // be able to read packets of any size without
00523                       // losing characters in UARTSerial
00524     
00525     // Ask for x bytes from Socket 
00526     tr_debug("Requesting to read back %d bytes from socket %d", length, modem_handle);
00527     if (_at->send("AT+NSORF=%d,%d", modem_handle, length)) {
00528         unsigned int id, port;
00529         
00530         // ReadFrom header, to get length - if no data then this will time out
00531         if (_at->recv("%d,\"%15[^\"]\",%d,%d,", &id, ipAddress, &port, &size)) {
00532             tr_debug("Socket RecvFrom: #%d: %d", id, size);
00533                 
00534             address->set_ip_address(ipAddress);
00535             address->set_port(port);
00536             
00537             // read the beginning quote for this data
00538             _at->read(tmpBuf, 1);
00539             
00540             // now read hex data
00541             if (_at->read(tmpBuf, size*2) == size*2) {
00542                 
00543                 // convert to bytes
00544                 hex_to_bin(tmpBuf, buf, size);
00545              
00546                 // read the "remaining" value - remembing there is an enclosing quote at the beginning of this read
00547                 if (!_at->recv("\",%d\n", &remaining)) {
00548                     tr_error("Failed reading the 'remaining' value after the received data.");
00549                     size = NSAPI_ERROR_DEVICE_ERROR;
00550                 }
00551             }
00552         }
00553         
00554         // we should get the OK (even if there is no data to read)
00555         if (_at->recv("OK")) {          
00556             tr_debug("Socket RecvFrom: Read %d bytes, %d bytes remaining.", size, remaining);
00557         } else {
00558             tr_error("Socket RecvFrom: Didn't receive OK from AT+NSORF command.");
00559             size = NSAPI_ERROR_DEVICE_ERROR;
00560         }
00561     }
00562     
00563     _at->debug_on(_debug_trace_on);
00564     free(tmpBuf);
00565     
00566     return size;
00567 }
00568 
00569 char UbloxATCellularInterfaceN2xx::hex_char(char c)
00570 {
00571     if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
00572     if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
00573     if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
00574     return 0xFF;
00575 }
00576 
00577 int UbloxATCellularInterfaceN2xx::hex_to_bin(const char* s, char * buff, int length)
00578 {
00579     int result;
00580     if (!s || !buff || length <= 0) return -1;
00581 
00582     for (result = 0; *s; ++result)
00583     {
00584         unsigned char msn = hex_char(*s++);
00585         if (msn == 0xFF) return -1;
00586         unsigned char lsn = hex_char(*s++);
00587         if (lsn == 0xFF) return -1;
00588         unsigned char bin = (msn << 4) + lsn;
00589 
00590         if (length-- <= 0) return -1;
00591         *buff++ = bin;
00592     }
00593     return result;
00594 }
00595 
00596 // Attach an event callback to a socket, required for asynchronous
00597 // data reception
00598 void UbloxATCellularInterfaceN2xx::socket_attach(nsapi_socket_t handle,
00599                                              void (*callback)(void *),
00600                                              void *data)
00601 {
00602     SockCtrl *socket = (SockCtrl *) handle;
00603 
00604     MBED_ASSERT (check_socket(socket));
00605 
00606     socket->callback = callback;
00607     socket->data = data;
00608 }
00609 
00610 // Unsupported TCP server functions.
00611 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_listen(nsapi_socket_t handle,
00612                                                       int backlog)
00613 {
00614     return NSAPI_ERROR_UNSUPPORTED;
00615 }
00616 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_accept(nsapi_socket_t server,
00617                                                       nsapi_socket_t *handle,
00618                                                       SocketAddress *address)
00619 {
00620     return NSAPI_ERROR_UNSUPPORTED;
00621 }
00622 
00623 // Unsupported option functions.
00624 nsapi_error_t UbloxATCellularInterfaceN2xx::setsockopt(nsapi_socket_t handle,
00625                                                    int level, int optname,
00626                                                    const void *optval,
00627                                                    unsigned optlen)
00628 {
00629     return NSAPI_ERROR_UNSUPPORTED;
00630 }
00631 nsapi_error_t UbloxATCellularInterfaceN2xx::getsockopt(nsapi_socket_t handle,
00632                                                    int level, int optname,
00633                                                    void *optval,
00634                                                    unsigned *optlen)
00635 {
00636     return NSAPI_ERROR_UNSUPPORTED;
00637 }
00638 
00639 /**********************************************************************
00640  * PUBLIC METHODS
00641  **********************************************************************/
00642 
00643 // Constructor.
00644 UbloxATCellularInterfaceN2xx::UbloxATCellularInterfaceN2xx(PinName tx,
00645                                                    PinName rx,
00646                                                    int baud,
00647                                                    bool debug_on)
00648 {
00649     _sim_pin_check_change_pending = false;
00650     _sim_pin_check_change_pending_enabled_value = false;
00651     _sim_pin_change_pending = false;
00652     _sim_pin_change_pending_new_pin_value = NULL;
00653     _apn = NULL;
00654     _uname = NULL;
00655     _pwd = NULL;
00656     _connection_status_cb = NULL;
00657     
00658     _localListenPort = 10000;
00659     
00660     tr_debug("UbloxATCellularInterfaceN2xx Constructor");
00661 
00662     // Initialise sockets storage
00663     memset(_sockets, 0, sizeof(_sockets));
00664     for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) {
00665         _sockets[socket].modem_handle = SOCKET_UNUSED;
00666         _sockets[socket].callback = NULL;
00667         _sockets[socket].data = NULL;
00668     }
00669 
00670     // The authentication to use
00671     _auth = NSAPI_SECURITY_UNKNOWN;
00672 
00673     // Nullify the temporary IP address storage
00674     _ip = NULL;
00675 
00676     // Initialise the base class, which starts the AT parser
00677     baseClassInit(tx, rx, baud, debug_on);
00678 
00679     // Start the event handler thread for Rx data
00680     event_thread.start(callback(this, &UbloxATCellularInterfaceN2xx::handle_event));
00681 
00682     // URC handlers for sockets
00683     _at->oob("+NSONMI", callback(this, &UbloxATCellularInterfaceN2xx::NSONMI_URC));
00684 }
00685 
00686 // Destructor.
00687 UbloxATCellularInterfaceN2xx::~UbloxATCellularInterfaceN2xx()
00688 {
00689     // Free _ip if it was ever allocated
00690     free(_ip);
00691 }
00692 
00693 // Set the authentication scheme.
00694 void UbloxATCellularInterfaceN2xx::set_authentication(nsapi_security_t auth)
00695 {
00696     _auth = auth;
00697 }
00698 
00699 // Set APN, user name and password.
00700 void  UbloxATCellularInterfaceN2xx::set_credentials(const char *apn,
00701                                                 const char *uname,
00702                                                 const char *pwd)
00703 {
00704     _apn = apn;
00705     _uname = uname;
00706     _pwd = pwd;
00707 }
00708 
00709 // Set PIN.
00710 void UbloxATCellularInterfaceN2xx::set_sim_pin(const char *pin) {
00711     set_pin(pin);
00712 }
00713 
00714 // Get the IP address of a host.
00715 nsapi_error_t UbloxATCellularInterfaceN2xx::gethostbyname(const char *host,
00716                                                       SocketAddress *address,
00717                                                       nsapi_version_t version)
00718 {
00719     nsapi_error_t nsapiError = NSAPI_ERROR_DEVICE_ERROR;
00720     tr_debug("GetHostByName: host= %s", host);
00721     if (address->set_ip_address(host)) {
00722         tr_debug("OK");
00723         nsapiError = NSAPI_ERROR_OK;
00724     } else {
00725         tr_debug("Failed");
00726         nsapiError = NSAPI_ERROR_UNSUPPORTED;
00727     }
00728 
00729     return nsapiError;
00730 }
00731 
00732 // Make a cellular connection
00733 nsapi_error_t UbloxATCellularInterfaceN2xx::connect(const char *sim_pin,
00734                                                 const char *apn,
00735                                                 const char *uname,
00736                                                 const char *pwd)
00737 {
00738     nsapi_error_t nsapi_error;
00739 
00740     if (sim_pin != NULL) {
00741         _pin = sim_pin;
00742     }
00743 
00744     if (apn != NULL) {
00745         _apn = apn;
00746     }
00747 
00748     if ((uname != NULL) && (pwd != NULL)) {
00749         _uname = uname;
00750         _pwd = pwd;
00751     } else {
00752         _uname = NULL;
00753         _pwd = NULL;
00754     }
00755 
00756     tr_debug("SIM, APN, UName & pwd set, now calling connect()");
00757     nsapi_error = connect();
00758 
00759     return nsapi_error;
00760 }
00761 
00762 bool UbloxATCellularInterfaceN2xx::initialise()
00763 {
00764     return init();
00765 }
00766 
00767 // Make a cellular connection using the IP stack on board the cellular modem
00768 nsapi_error_t UbloxATCellularInterfaceN2xx::connect()
00769 {
00770     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00771     bool registered = false;
00772 
00773     // Set up modem and then register with the network
00774     if (initialise()) {
00775         
00776         tr_debug("Trying to register...");
00777         nsapi_error = NSAPI_ERROR_NO_CONNECTION;    
00778         for (int retries = 0; !registered && (retries < 3); retries++) {
00779             if (nwk_registration()) {
00780                 registered = true;
00781             }
00782         }
00783     }
00784 
00785     // Attempt to establish a connection
00786     if (registered) {
00787         nsapi_error = NSAPI_ERROR_OK;
00788     } else {
00789         tr_debug("Failed to register.");
00790     }
00791 
00792     return nsapi_error;
00793 }
00794 
00795 // User initiated disconnect.
00796 nsapi_error_t UbloxATCellularInterfaceN2xx::disconnect()
00797 {
00798     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00799 
00800     if (nwk_deregistration()) {
00801         nsapi_error = NSAPI_ERROR_OK;
00802         
00803         if (_connection_status_cb) {
00804             _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
00805         }
00806     }
00807 
00808     return nsapi_error;
00809 }
00810 
00811 // Enable or disable SIM PIN check lock.
00812 nsapi_error_t UbloxATCellularInterfaceN2xx::set_sim_pin_check(bool set,
00813                                                           bool immediate,
00814                                                           const char *sim_pin)
00815 {
00816     return NSAPI_ERROR_UNSUPPORTED;
00817 }
00818 
00819 // Change the PIN code for the SIM card.
00820 nsapi_error_t UbloxATCellularInterfaceN2xx::set_new_sim_pin(const char *new_pin,
00821                                                         bool immediate,
00822                                                         const char *old_pin)
00823 {
00824     return NSAPI_ERROR_UNSUPPORTED;
00825 }
00826 
00827 // Determine if the connection is up.
00828 bool UbloxATCellularInterfaceN2xx::is_connected()
00829 {
00830     return get_ip_address() != NULL;
00831 }
00832 
00833 // Get the IP address of the on-board modem IP stack.
00834 const char * UbloxATCellularInterfaceN2xx::get_ip_address()
00835 {
00836     SocketAddress address;
00837     int id;
00838     LOCK();
00839 
00840     if (_ip == NULL)
00841     {
00842         // Temporary storage for an IP address string with terminator
00843         _ip = (char *) malloc(NSAPI_IP_SIZE);
00844     }
00845     
00846     if (_ip != NULL) {                        
00847         memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator
00848         // +CGPADDR - returns a list of IP Addresses per context, just pick the first one as SARA-N2xx only allows 1 context.
00849         if (!_at->send("AT+CGPADDR") ||
00850             !_at->recv("+CGPADDR:%d,%15[^\n]\n", &id, _ip) ||
00851             ! _at->recv("OK") ||
00852             !address.set_ip_address(_ip) ||
00853             !address) {            
00854                 free (_ip);
00855                 _ip = NULL;
00856         }
00857     }
00858 
00859     UNLOCK();
00860     return _ip;
00861 }
00862 
00863 // Get the local network mask.
00864 const char *UbloxATCellularInterfaceN2xx::get_netmask()
00865 {
00866     // Not implemented.
00867     return NULL;
00868 }
00869 
00870 // Get the local gateways.
00871 const char *UbloxATCellularInterfaceN2xx::get_gateway()
00872 {
00873     return get_ip_address();
00874 }
00875 
00876 void UbloxATCellularInterfaceN2xx::set_LocalListenPort(int port) {
00877     _localListenPort = port;
00878 }
00879 
00880 void UbloxATCellularInterfaceN2xx::set_plmn(const char *plmn) {
00881 
00882 }
00883 
00884 // Callback in case the connection is lost.
00885 void UbloxATCellularInterfaceN2xx::connection_status_cb(Callback<void(nsapi_error_t)> cb)
00886 {
00887     _connection_status_cb = cb;
00888 }
00889 
00890 // End of file
00891