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

Committer:
philware
Date:
Tue Dec 12 15:51:45 2017 +0000
Revision:
12:b0757007cc72
Parent:
10:08c5a69437ac
Child:
13:2504d4160042
Don't quit the loop by breaking out of it, set the size = 0 or success to false.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
philware 1:8ea78dce6b36 1 /* Copyright (c) 2017 ublox Limited
philware 1:8ea78dce6b36 2 *
philware 1:8ea78dce6b36 3 * Licensed under the Apache License, Version 2.0 (the "License");
philware 1:8ea78dce6b36 4 * you may not use this file except in compliance with the License.
philware 1:8ea78dce6b36 5 * You may obtain a copy of the License at
philware 1:8ea78dce6b36 6 *
philware 1:8ea78dce6b36 7 * http://www.apache.org/licenses/LICENSE-2.0
philware 1:8ea78dce6b36 8 *
philware 1:8ea78dce6b36 9 * Unless required by applicable law or agreed to in writing, software
philware 1:8ea78dce6b36 10 * distributed under the License is distributed on an "AS IS" BASIS,
philware 1:8ea78dce6b36 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
philware 1:8ea78dce6b36 12 * See the License for the specific language governing permissions and
philware 1:8ea78dce6b36 13 * limitations under the License.
philware 1:8ea78dce6b36 14 */
philware 1:8ea78dce6b36 15
philware 1:8ea78dce6b36 16 #include "UbloxATCellularInterfaceN2xx.h"
philware 1:8ea78dce6b36 17 #include "mbed_poll.h"
philware 1:8ea78dce6b36 18 #include "nsapi.h"
philware 1:8ea78dce6b36 19 #include "APN_db.h"
philware 1:8ea78dce6b36 20 #ifdef FEATURE_COMMON_PAL
philware 1:8ea78dce6b36 21 #include "mbed_trace.h"
philware 1:8ea78dce6b36 22 #define TRACE_GROUP "UACI"
philware 1:8ea78dce6b36 23 #else
philware 1:8ea78dce6b36 24 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
philware 1:8ea78dce6b36 25 #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
philware 1:8ea78dce6b36 26 #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
philware 1:8ea78dce6b36 27 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
philware 1:8ea78dce6b36 28 #endif
philware 1:8ea78dce6b36 29
philware 4:2bf3875a13f1 30 // When calling the SendTo function, the large hex string for the bytes to send is chopped into chunks
philware 4:2bf3875a13f1 31 #define SENDTO_CHUNK_SIZE 50
philware 4:2bf3875a13f1 32
philware 1:8ea78dce6b36 33 /**********************************************************************
philware 1:8ea78dce6b36 34 * PRIVATE METHODS
philware 1:8ea78dce6b36 35 **********************************************************************/
philware 1:8ea78dce6b36 36
philware 1:8ea78dce6b36 37 // Event thread for asynchronous received data handling.
philware 1:8ea78dce6b36 38 void UbloxATCellularInterfaceN2xx::handle_event(){
philware 1:8ea78dce6b36 39 pollfh fhs;
philware 1:8ea78dce6b36 40 int count;
philware 1:8ea78dce6b36 41 int at_timeout;
philware 1:8ea78dce6b36 42
philware 1:8ea78dce6b36 43 fhs.fh = _fh;
philware 1:8ea78dce6b36 44 fhs.events = POLLIN;
philware 1:8ea78dce6b36 45
philware 1:8ea78dce6b36 46 while (true) {
philware 1:8ea78dce6b36 47 count = poll(&fhs, 1, 1000);
philware 1:8ea78dce6b36 48 if (count > 0 && (fhs.revents & POLLIN)) {
philware 1:8ea78dce6b36 49 LOCK();
philware 1:8ea78dce6b36 50 at_timeout = _at_timeout;
philware 1:8ea78dce6b36 51 at_set_timeout(10); // Avoid blocking but also make sure we don't
philware 1:8ea78dce6b36 52 // time out if we get ahead of the serial port
philware 1:8ea78dce6b36 53 _at->debug_on(false); // Debug here screws with the test output
philware 1:8ea78dce6b36 54 // Let the URCs run
philware 1:8ea78dce6b36 55 _at->recv(UNNATURAL_STRING);
philware 1:8ea78dce6b36 56 _at->debug_on(_debug_trace_on);
philware 1:8ea78dce6b36 57 at_set_timeout(at_timeout);
philware 1:8ea78dce6b36 58 UNLOCK();
philware 1:8ea78dce6b36 59 }
philware 1:8ea78dce6b36 60 }
philware 1:8ea78dce6b36 61 }
philware 1:8ea78dce6b36 62
philware 1:8ea78dce6b36 63 // Find or create a socket from the list.
philware 1:8ea78dce6b36 64 UbloxATCellularInterfaceN2xx::SockCtrl * UbloxATCellularInterfaceN2xx::find_socket(int modem_handle)
philware 1:8ea78dce6b36 65 {
philware 1:8ea78dce6b36 66 UbloxATCellularInterfaceN2xx::SockCtrl *socket = NULL;
philware 1:8ea78dce6b36 67
philware 1:8ea78dce6b36 68 for (unsigned int x = 0; (socket == NULL) && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) {
philware 1:8ea78dce6b36 69 if (_sockets[x].modem_handle == modem_handle) {
philware 1:8ea78dce6b36 70 socket = &(_sockets[x]);
philware 1:8ea78dce6b36 71 }
philware 1:8ea78dce6b36 72 }
philware 1:8ea78dce6b36 73
philware 1:8ea78dce6b36 74 return socket;
philware 1:8ea78dce6b36 75 }
philware 1:8ea78dce6b36 76
philware 1:8ea78dce6b36 77 // Clear out the storage for a socket
philware 1:8ea78dce6b36 78 void UbloxATCellularInterfaceN2xx::clear_socket(UbloxATCellularInterfaceN2xx::SockCtrl * socket)
philware 1:8ea78dce6b36 79 {
philware 1:8ea78dce6b36 80 if (socket != NULL) {
philware 1:8ea78dce6b36 81 socket->modem_handle = SOCKET_UNUSED;
philware 1:8ea78dce6b36 82 socket->pending = 0;
philware 1:8ea78dce6b36 83 socket->callback = NULL;
philware 1:8ea78dce6b36 84 socket->data = NULL;
philware 1:8ea78dce6b36 85 }
philware 1:8ea78dce6b36 86 }
philware 1:8ea78dce6b36 87
philware 1:8ea78dce6b36 88 // Check that a socket pointer is valid
philware 1:8ea78dce6b36 89 bool UbloxATCellularInterfaceN2xx::check_socket(SockCtrl * socket)
philware 1:8ea78dce6b36 90 {
philware 1:8ea78dce6b36 91 bool success = false;
philware 1:8ea78dce6b36 92
philware 1:8ea78dce6b36 93 if (socket != NULL) {
philware 1:8ea78dce6b36 94 for (unsigned int x = 0; !success && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) {
philware 1:8ea78dce6b36 95 if (socket == &(_sockets[x])) {
philware 1:8ea78dce6b36 96 success = true;
philware 1:8ea78dce6b36 97 }
philware 1:8ea78dce6b36 98 }
philware 1:8ea78dce6b36 99 }
philware 1:8ea78dce6b36 100
philware 1:8ea78dce6b36 101 return success;
philware 1:8ea78dce6b36 102 }
philware 1:8ea78dce6b36 103
philware 1:8ea78dce6b36 104 // Callback for Socket Read From URC.
philware 1:8ea78dce6b36 105 void UbloxATCellularInterfaceN2xx::NSONMI_URC()
philware 1:8ea78dce6b36 106 {
philware 1:8ea78dce6b36 107 int a;
philware 1:8ea78dce6b36 108 int b;
philware 1:8ea78dce6b36 109 char buf[32];
philware 1:8ea78dce6b36 110 SockCtrl *socket;
philware 1:8ea78dce6b36 111
philware 1:8ea78dce6b36 112 // Note: not calling _at->recv() from here as we're
philware 1:8ea78dce6b36 113 // already in an _at->recv()
philware 1:8ea78dce6b36 114 // +UUSORF: <socket>,<length>
philware 1:8ea78dce6b36 115 if (read_at_to_newline(buf, sizeof (buf)) > 0) {
philware 1:8ea78dce6b36 116 tr_debug("NSONMI URC");
philware 1:8ea78dce6b36 117 if (sscanf(buf, ":%d,%d", &a, &b) == 2) {
philware 1:8ea78dce6b36 118 socket = find_socket(a);
philware 1:8ea78dce6b36 119 if (socket != NULL) {
philware 1:8ea78dce6b36 120 socket->pending += b;
philware 1:8ea78dce6b36 121 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
philware 1:8ea78dce6b36 122 (unsigned int) socket, a, socket->pending);
philware 1:8ea78dce6b36 123 if (socket->callback != NULL) {
philware 1:8ea78dce6b36 124 tr_debug("***** Calling callback...");
philware 1:8ea78dce6b36 125 socket->callback(socket->data);
philware 1:8ea78dce6b36 126 tr_debug("***** Callback finished");
philware 1:8ea78dce6b36 127 } else {
philware 1:8ea78dce6b36 128 tr_debug("No callback found for socket.");
philware 1:8ea78dce6b36 129 }
philware 1:8ea78dce6b36 130 } else {
philware 1:8ea78dce6b36 131 tr_debug("Can't find socket with modem handle %d", a);
philware 1:8ea78dce6b36 132 }
philware 1:8ea78dce6b36 133 }
philware 1:8ea78dce6b36 134 }
philware 1:8ea78dce6b36 135 }
philware 1:8ea78dce6b36 136
philware 1:8ea78dce6b36 137 /**********************************************************************
philware 1:8ea78dce6b36 138 * PROTECTED METHODS: GENERAL
philware 1:8ea78dce6b36 139 **********************************************************************/
philware 1:8ea78dce6b36 140
philware 1:8ea78dce6b36 141 // Get the next set of credentials, based on IMSI.
philware 1:8ea78dce6b36 142 void UbloxATCellularInterfaceN2xx::get_next_credentials(const char * config)
philware 1:8ea78dce6b36 143 {
philware 1:8ea78dce6b36 144 if (config) {
philware 1:8ea78dce6b36 145 _apn = _APN_GET(config);
philware 1:8ea78dce6b36 146 _uname = _APN_GET(config);
philware 1:8ea78dce6b36 147 _pwd = _APN_GET(config);
philware 1:8ea78dce6b36 148 }
philware 1:8ea78dce6b36 149
philware 1:8ea78dce6b36 150 _apn = _apn ? _apn : "";
philware 1:8ea78dce6b36 151 _uname = _uname ? _uname : "";
philware 1:8ea78dce6b36 152 _pwd = _pwd ? _pwd : "";
philware 1:8ea78dce6b36 153 }
philware 1:8ea78dce6b36 154
philware 1:8ea78dce6b36 155 /**********************************************************************
philware 1:8ea78dce6b36 156 * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS
philware 1:8ea78dce6b36 157 **********************************************************************/
philware 1:8ea78dce6b36 158
philware 1:8ea78dce6b36 159 // Gain access to us.
philware 1:8ea78dce6b36 160 NetworkStack *UbloxATCellularInterfaceN2xx::get_stack()
philware 1:8ea78dce6b36 161 {
philware 1:8ea78dce6b36 162 return this;
philware 1:8ea78dce6b36 163 }
philware 1:8ea78dce6b36 164
philware 1:8ea78dce6b36 165 // Create a socket.
philware 1:8ea78dce6b36 166 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_open(nsapi_socket_t *handle,
philware 1:8ea78dce6b36 167 nsapi_protocol_t proto)
philware 1:8ea78dce6b36 168 {
philware 1:8ea78dce6b36 169 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 170 int modem_handle =0;
philware 1:8ea78dce6b36 171 SockCtrl *socket;
philware 1:8ea78dce6b36 172
philware 1:8ea78dce6b36 173 if (proto != NSAPI_UDP) {
philware 1:8ea78dce6b36 174 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 175 }
philware 1:8ea78dce6b36 176
philware 1:8ea78dce6b36 177 LOCK();
philware 1:8ea78dce6b36 178
philware 1:8ea78dce6b36 179 // Find a free socket
philware 1:8ea78dce6b36 180 socket = find_socket();
philware 1:8ea78dce6b36 181 if (socket != NULL) {
philware 1:8ea78dce6b36 182 tr_debug("socket_open(%d)", proto);
philware 9:f6d022f5c4f5 183 if (_at->send("AT+NSOCR=\"DGRAM\",17,%d", _localListenPort) &&
philware 1:8ea78dce6b36 184 _at->recv("%d\n", &modem_handle) &&
philware 1:8ea78dce6b36 185 _at->recv("OK")) {
philware 1:8ea78dce6b36 186 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle);
philware 1:8ea78dce6b36 187 clear_socket(socket);
philware 1:8ea78dce6b36 188 socket->modem_handle = modem_handle;
philware 1:8ea78dce6b36 189 *handle = (nsapi_socket_t) socket;
philware 1:8ea78dce6b36 190 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 191 } else {
philware 1:8ea78dce6b36 192 tr_error("Couldn't open socket using AT command");
philware 1:8ea78dce6b36 193 }
philware 1:8ea78dce6b36 194 } else {
philware 1:8ea78dce6b36 195 tr_error("Can't find a socket to use");
philware 1:8ea78dce6b36 196 nsapi_error = NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 197 }
philware 1:8ea78dce6b36 198
philware 1:8ea78dce6b36 199 UNLOCK();
philware 1:8ea78dce6b36 200 return nsapi_error;
philware 1:8ea78dce6b36 201 }
philware 1:8ea78dce6b36 202
philware 1:8ea78dce6b36 203
philware 1:8ea78dce6b36 204 // Close a socket.
philware 1:8ea78dce6b36 205 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_close(nsapi_socket_t handle)
philware 1:8ea78dce6b36 206 {
philware 1:8ea78dce6b36 207 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 208 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 209 LOCK();
philware 1:8ea78dce6b36 210
philware 1:8ea78dce6b36 211 tr_debug("socket_close(0x%08x)", (unsigned int) handle);
philware 1:8ea78dce6b36 212
philware 1:8ea78dce6b36 213 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 214
philware 1:8ea78dce6b36 215 if (_at->send("AT+NSOCL=%d", socket->modem_handle) &&
philware 1:8ea78dce6b36 216 _at->recv("OK")) {
philware 1:8ea78dce6b36 217 clear_socket(socket);
philware 1:8ea78dce6b36 218 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 219 } else {
philware 1:8ea78dce6b36 220 tr_error("Failed to close socket %d", socket->modem_handle);
philware 1:8ea78dce6b36 221 }
philware 1:8ea78dce6b36 222
philware 1:8ea78dce6b36 223 UNLOCK();
philware 1:8ea78dce6b36 224 return nsapi_error;
philware 1:8ea78dce6b36 225 }
philware 1:8ea78dce6b36 226
philware 1:8ea78dce6b36 227 // Bind a local port to a socket.
philware 1:8ea78dce6b36 228 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_bind(nsapi_socket_t handle,
philware 1:8ea78dce6b36 229 const SocketAddress &address)
philware 1:8ea78dce6b36 230 {
philware 1:8ea78dce6b36 231 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 232 }
philware 1:8ea78dce6b36 233
philware 1:8ea78dce6b36 234 // Connect to a socket
philware 1:8ea78dce6b36 235 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_connect(nsapi_socket_t handle,
philware 1:8ea78dce6b36 236 const SocketAddress &address)
philware 1:8ea78dce6b36 237 {
philware 1:8ea78dce6b36 238 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 239 }
philware 1:8ea78dce6b36 240
philware 1:8ea78dce6b36 241 // Send to a socket.
philware 1:8ea78dce6b36 242 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_send(nsapi_socket_t handle,
philware 1:8ea78dce6b36 243 const void *data,
philware 1:8ea78dce6b36 244 nsapi_size_t size)
philware 1:8ea78dce6b36 245 {
philware 1:8ea78dce6b36 246 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 247 }
philware 1:8ea78dce6b36 248
philware 1:8ea78dce6b36 249 // Send to an IP address.
philware 1:8ea78dce6b36 250 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_sendto(nsapi_socket_t handle,
philware 1:8ea78dce6b36 251 const SocketAddress &address,
philware 1:8ea78dce6b36 252 const void *data,
philware 1:8ea78dce6b36 253 nsapi_size_t size)
philware 1:8ea78dce6b36 254 {
philware 1:8ea78dce6b36 255 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 256 bool success = true;
philware 1:8ea78dce6b36 257 const char *buf = (const char *) data;
rob.meades@u-blox.com 7:69e676f4af84 258 nsapi_size_t blk = MAX_WRITE_SIZE_N2XX;
philware 1:8ea78dce6b36 259 nsapi_size_t count = size;
philware 1:8ea78dce6b36 260 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 261
philware 1:8ea78dce6b36 262 tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle,
philware 1:8ea78dce6b36 263 address.get_ip_address(), address.get_port(), (unsigned int) data, size);
philware 1:8ea78dce6b36 264
philware 1:8ea78dce6b36 265 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 266
rob.meades@u-blox.com 7:69e676f4af84 267 tr_debug("Max Write Size for SendTo: %d", MAX_WRITE_SIZE_N2XX);
rob.meades@u-blox.com 7:69e676f4af84 268 if (size > MAX_WRITE_SIZE_N2XX) {
rob.meades@u-blox.com 7:69e676f4af84 269 tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE_N2XX);
philware 1:8ea78dce6b36 270 }
philware 1:8ea78dce6b36 271
philware 1:8ea78dce6b36 272 while ((count > 0) && success) {
philware 1:8ea78dce6b36 273 if (count < blk) {
philware 1:8ea78dce6b36 274 blk = count;
philware 1:8ea78dce6b36 275 }
philware 1:8ea78dce6b36 276
philware 1:8ea78dce6b36 277 // call the AT Helper function to send the bytes
philware 1:8ea78dce6b36 278 tr_debug("Sending %d bytes....", blk);
philware 1:8ea78dce6b36 279 int sent = sendto(socket, address, buf, blk);
philware 1:8ea78dce6b36 280 if (sent < 0) {
philware 1:8ea78dce6b36 281 tr_error("Something went wrong! %d", sent);
philware 1:8ea78dce6b36 282 return NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 283 }
philware 1:8ea78dce6b36 284
philware 1:8ea78dce6b36 285 buf += sent;
philware 1:8ea78dce6b36 286 count -= sent;
philware 1:8ea78dce6b36 287 }
philware 1:8ea78dce6b36 288
philware 1:8ea78dce6b36 289 if (success) {
philware 1:8ea78dce6b36 290 nsapi_error_size = size - count;
philware 1:8ea78dce6b36 291 if (_debug_trace_on) {
philware 1:8ea78dce6b36 292 tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data);
philware 1:8ea78dce6b36 293 }
philware 1:8ea78dce6b36 294 }
philware 1:8ea78dce6b36 295
philware 1:8ea78dce6b36 296 return nsapi_error_size;
philware 1:8ea78dce6b36 297 }
philware 1:8ea78dce6b36 298
philware 1:8ea78dce6b36 299 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::sendto(SockCtrl *socket, const SocketAddress &address, const char *buf, int size) {
philware 1:8ea78dce6b36 300 nsapi_size_or_error_t sent = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 301 int id;
philware 6:658419981430 302
philware 6:658419981430 303 char *dataStr = (char *) malloc((size * 2) + 1);
philware 6:658419981430 304 if (dataStr == NULL) {
philware 6:658419981430 305 tr_error("Couldn't allocate memory for hex string conversion.");
philware 1:8ea78dce6b36 306 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 307 }
philware 1:8ea78dce6b36 308
philware 1:8ea78dce6b36 309 tr_debug("Converting byte array to hex string");
philware 6:658419981430 310 bin_to_hex(buf, size, dataStr);
philware 1:8ea78dce6b36 311 tr_debug("Got hex string");
philware 1:8ea78dce6b36 312
philware 1:8ea78dce6b36 313 // AT+NSOSTF= socket, remote_addr, remote_port, length, data
philware 6:658419981430 314 tr_debug("Writing AT+NSOSTF=<sktid>,<ipaddr>,<port>,<flags>,<size>,<hex string> command...");
philware 6:658419981430 315 char *cmdStr = (char *) malloc(50);
philware 6:658419981430 316 if (cmdStr == NULL) {
philware 6:658419981430 317 tr_error("Couldn't allocate memory for AT cmd string.");
philware 6:658419981430 318 return NSAPI_ERROR_NO_MEMORY;
philware 6:658419981430 319 }
philware 6:658419981430 320
philware 9:f6d022f5c4f5 321 int cmdsize = sprintf(cmdStr, "AT+NSOSTF=%d,\"%s\",%d,0x0,%d,\"", socket->modem_handle, address.get_ip_address(), address.get_port(), size);
philware 6:658419981430 322 tr_debug("%s", cmdStr);
philware 6:658419981430 323
philware 6:658419981430 324 LOCK();
philware 6:658419981430 325 if (_at->write(cmdStr, cmdsize) && sendATChopped(dataStr))
philware 6:658419981430 326 {
philware 6:658419981430 327 tr_debug("Finished sending AT+NSOST comamnd, reading back the 'sent' size...");
philware 1:8ea78dce6b36 328 if (_at->recv("%d,%d\n", &id, &sent) && _at->recv("OK")) {
philware 6:658419981430 329 tr_debug("Sent %d bytes on socket %d", sent, id);
philware 1:8ea78dce6b36 330 } else {
philware 1:8ea78dce6b36 331 tr_error("Didn't get the Sent size or OK");
philware 1:8ea78dce6b36 332 }
philware 1:8ea78dce6b36 333 } else {
philware 1:8ea78dce6b36 334 tr_error("Didn't send the AT command!");
philware 1:8ea78dce6b36 335 }
philware 6:658419981430 336 UNLOCK();
philware 1:8ea78dce6b36 337
philware 6:658419981430 338 free(cmdStr);
philware 6:658419981430 339 free(dataStr);
philware 6:658419981430 340
philware 1:8ea78dce6b36 341 return sent;
philware 1:8ea78dce6b36 342 }
philware 1:8ea78dce6b36 343
philware 4:2bf3875a13f1 344 bool UbloxATCellularInterfaceN2xx::sendATChopped(const char *cmd)
philware 4:2bf3875a13f1 345 {
philware 4:2bf3875a13f1 346 char buff[SENDTO_CHUNK_SIZE];
philware 6:658419981430 347 tr_debug("Chopping up large AT text of %d characters.", strlen(cmd));
philware 6:658419981430 348
philware 4:2bf3875a13f1 349 while (*cmd != '\0')
philware 4:2bf3875a13f1 350 {
philware 4:2bf3875a13f1 351 int i=0;
philware 4:2bf3875a13f1 352
philware 4:2bf3875a13f1 353 for (i=0; i<SENDTO_CHUNK_SIZE; i++) {
philware 4:2bf3875a13f1 354 buff[i] = *cmd;
philware 4:2bf3875a13f1 355
philware 4:2bf3875a13f1 356 // if we have copied the NULL terminator, we can exit
philware 4:2bf3875a13f1 357 if (*cmd == '\0')
philware 4:2bf3875a13f1 358 break;
philware 4:2bf3875a13f1 359
philware 4:2bf3875a13f1 360 // still more characters to copy, so move along
philware 4:2bf3875a13f1 361 cmd++;
philware 4:2bf3875a13f1 362 }
philware 6:658419981430 363
philware 6:658419981430 364 // if we are at the end of the line, use the send command to
philware 6:658419981430 365 // provide the \r\n terminator for the AT command
philware 4:2bf3875a13f1 366 if (*cmd == '\0') {
philware 9:f6d022f5c4f5 367 tr_debug("send(%d): %s", i, buff);
philware 9:f6d022f5c4f5 368 // write the last buffer...
philware 9:f6d022f5c4f5 369 if (!_at->write(buff,i))
philware 9:f6d022f5c4f5 370 return false;
philware 9:f6d022f5c4f5 371
philware 9:f6d022f5c4f5 372 // ...send the enclosing quote to complete the AT command
philware 9:f6d022f5c4f5 373 if (!_at->send("\""))
philware 4:2bf3875a13f1 374 return false;
philware 4:2bf3875a13f1 375 } else {
philware 6:658419981430 376 tr_debug("write(50): %s", buff);
philware 4:2bf3875a13f1 377 if (!_at->write(buff, 50))
philware 4:2bf3875a13f1 378 return false;
philware 4:2bf3875a13f1 379 }
philware 4:2bf3875a13f1 380 }
philware 4:2bf3875a13f1 381
philware 4:2bf3875a13f1 382 return true;
philware 4:2bf3875a13f1 383 }
philware 4:2bf3875a13f1 384
philware 1:8ea78dce6b36 385 void UbloxATCellularInterfaceN2xx::bin_to_hex(const char *buff, unsigned int length, char *output)
philware 1:8ea78dce6b36 386 {
philware 1:8ea78dce6b36 387 char binHex[] = "0123456789ABCDEF";
philware 1:8ea78dce6b36 388
philware 1:8ea78dce6b36 389 *output = '\0';
philware 1:8ea78dce6b36 390
philware 1:8ea78dce6b36 391 for (; length > 0; --length)
philware 1:8ea78dce6b36 392 {
philware 1:8ea78dce6b36 393 unsigned char byte = *buff++;
philware 1:8ea78dce6b36 394
philware 1:8ea78dce6b36 395 *output++ = binHex[(byte >> 4) & 0x0F];
philware 1:8ea78dce6b36 396 *output++ = binHex[byte & 0x0F];
philware 1:8ea78dce6b36 397 }
philware 1:8ea78dce6b36 398
philware 1:8ea78dce6b36 399 *output++ = '\0';
philware 1:8ea78dce6b36 400 }
philware 1:8ea78dce6b36 401
philware 1:8ea78dce6b36 402 // Receive from a socket, TCP style.
philware 1:8ea78dce6b36 403 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recv(nsapi_socket_t handle,
philware 1:8ea78dce6b36 404 void *data,
philware 1:8ea78dce6b36 405 nsapi_size_t size)
philware 1:8ea78dce6b36 406 {
philware 1:8ea78dce6b36 407 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 408 }
philware 1:8ea78dce6b36 409
philware 1:8ea78dce6b36 410 // Receive a packet over a UDP socket.
philware 1:8ea78dce6b36 411 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recvfrom(nsapi_socket_t handle,
philware 1:8ea78dce6b36 412 SocketAddress *address,
philware 1:8ea78dce6b36 413 void *data,
philware 1:8ea78dce6b36 414 nsapi_size_t size)
philware 1:8ea78dce6b36 415 {
philware 1:8ea78dce6b36 416 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 417 bool success = true;
philware 1:8ea78dce6b36 418 char *buf = (char *) data;
philware 1:8ea78dce6b36 419 nsapi_size_t read_blk;
philware 1:8ea78dce6b36 420 nsapi_size_t count = 0;
philware 6:658419981430 421 int at_timeout = _at_timeout;
philware 6:658419981430 422
philware 1:8ea78dce6b36 423 char * tmpBuf = NULL;
philware 1:8ea78dce6b36 424
philware 1:8ea78dce6b36 425 Timer timer;
philware 1:8ea78dce6b36 426 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 427
philware 6:658419981430 428 tr_debug("socket_recvfrom(0x%08x, 0x%08x, SIZE=%d)", (unsigned int) handle, (unsigned int) data, size);
philware 1:8ea78dce6b36 429
philware 1:8ea78dce6b36 430 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 431 timer.start();
philware 1:8ea78dce6b36 432
philware 1:8ea78dce6b36 433 while (success && (size > 0)) {
philware 1:8ea78dce6b36 434 LOCK();
philware 6:658419981430 435 at_timeout = _at_timeout;
philware 1:8ea78dce6b36 436 at_set_timeout(1000);
philware 6:658419981430 437
rob.meades@u-blox.com 7:69e676f4af84 438 read_blk = MAX_READ_SIZE_N2XX;
philware 6:658419981430 439 if (read_blk > size) {
philware 6:658419981430 440 read_blk = size;
philware 1:8ea78dce6b36 441 }
philware 6:658419981430 442
philware 6:658419981430 443 if (socket->pending > 0) {
philware 6:658419981430 444 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
philware 6:658419981430 445 (unsigned int) socket, socket->modem_handle, socket->pending);
philware 6:658419981430 446
philware 1:8ea78dce6b36 447 tmpBuf = (char *) malloc(read_blk);
philware 1:8ea78dce6b36 448 if (tmpBuf == NULL) {
philware 1:8ea78dce6b36 449 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 450 }
philware 1:8ea78dce6b36 451
philware 1:8ea78dce6b36 452 // call the AT helper function to get the bytes
philware 1:8ea78dce6b36 453 nsapi_error_size = receivefrom(socket->modem_handle, address, read_blk, tmpBuf);
philware 6:658419981430 454
philware 1:8ea78dce6b36 455 if (nsapi_error_size >= 0) {
philware 1:8ea78dce6b36 456 memcpy(buf, tmpBuf, nsapi_error_size);
philware 1:8ea78dce6b36 457
rob.meades@u-blox.com 8:0162c103346a 458 if (read_blk != (uint32_t) nsapi_error_size)
philware 9:f6d022f5c4f5 459 tr_debug("Requested size is not the same as the returned size.");
philware 6:658419981430 460
philware 6:658419981430 461 socket->pending -= nsapi_error_size;
philware 1:8ea78dce6b36 462 count += nsapi_error_size;
philware 1:8ea78dce6b36 463 buf += nsapi_error_size;
philware 6:658419981430 464 size -= nsapi_error_size;
philware 6:658419981430 465
rob.meades@u-blox.com 8:0162c103346a 466 if (((uint32_t) nsapi_error_size < read_blk) || (nsapi_error_size == MAX_READ_SIZE_N2XX))
philware 6:658419981430 467 size = 0; // If we've received less than we asked for, or
philware 6:658419981430 468 // the max size, then a whole UDP packet has arrived and
philware 6:658419981430 469 // this means DONE.
philware 1:8ea78dce6b36 470 } else {
philware 6:658419981430 471 // Should never fail to read when there is pending data
philware 1:8ea78dce6b36 472 success = false;
philware 1:8ea78dce6b36 473 }
philware 1:8ea78dce6b36 474 } else if (timer.read_ms() < SOCKET_TIMEOUT) {
philware 1:8ea78dce6b36 475 // Wait for URCs
philware 6:658419981430 476 tr_debug("Waiting for URC...");
philware 1:8ea78dce6b36 477 _at->recv(UNNATURAL_STRING);
philware 1:8ea78dce6b36 478 } else {
philware 6:658419981430 479 tr_debug("Nothing pending...");
philware 6:658419981430 480 if (count == 0) {
philware 6:658419981430 481 tr_debug("Nothing received, so timeout with block");
philware 6:658419981430 482 // Timeout with nothing received
philware 6:658419981430 483 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK;
philware 6:658419981430 484 success = false;
philware 6:658419981430 485 }
philware 12:b0757007cc72 486 size = 0; // This simply to cause an exit
philware 1:8ea78dce6b36 487 }
philware 6:658419981430 488
philware 1:8ea78dce6b36 489 at_set_timeout(at_timeout);
philware 1:8ea78dce6b36 490 UNLOCK();
philware 1:8ea78dce6b36 491 }
philware 1:8ea78dce6b36 492 timer.stop();
philware 1:8ea78dce6b36 493
philware 1:8ea78dce6b36 494 if (success) {
philware 6:658419981430 495 tr_debug("socket_recvfrom: %d SUCCESS!", count);
philware 1:8ea78dce6b36 496 nsapi_error_size = count;
philware 6:658419981430 497 } else {
philware 6:658419981430 498 tr_debug("socket_recvfrom: FAILED");
philware 1:8ea78dce6b36 499 }
philware 6:658419981430 500
philware 1:8ea78dce6b36 501 return nsapi_error_size;
philware 1:8ea78dce6b36 502 }
philware 1:8ea78dce6b36 503
philware 1:8ea78dce6b36 504 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::receivefrom(int modem_handle, SocketAddress *address, int length, char *buf) {
philware 1:8ea78dce6b36 505 char ipAddress[NSAPI_IP_SIZE];
philware 1:8ea78dce6b36 506 nsapi_size_or_error_t size;
philware 6:658419981430 507
philware 1:8ea78dce6b36 508 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
philware 1:8ea78dce6b36 509
rob.meades@u-blox.com 7:69e676f4af84 510 if (length > MAX_READ_SIZE_N2XX) {
philware 1:8ea78dce6b36 511 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 512 }
philware 1:8ea78dce6b36 513
philware 1:8ea78dce6b36 514 char * tmpBuf = (char *) malloc(length*2);
philware 1:8ea78dce6b36 515 if (tmpBuf == NULL)
philware 1:8ea78dce6b36 516 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 517
philware 6:658419981430 518 int remaining;
philware 6:658419981430 519
philware 6:658419981430 520 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to
philware 6:658419981430 521 // be able to read packets of any size without
philware 6:658419981430 522 // losing characters in UARTSerial
philware 1:8ea78dce6b36 523
philware 1:8ea78dce6b36 524 // Ask for x bytes from Socket
philware 6:658419981430 525 tr_debug("Requesting to read back %d bytes from socket %d", length, modem_handle);
philware 1:8ea78dce6b36 526 if (_at->send("AT+NSORF=%d,%d", modem_handle, length)) {
philware 1:8ea78dce6b36 527 unsigned int id, port;
philware 1:8ea78dce6b36 528
philware 1:8ea78dce6b36 529 // ReadFrom header, to get length - if no data then this will time out
philware 9:f6d022f5c4f5 530 if (_at->recv("%d,\"%15[^\"]\",%d,%d,", &id, ipAddress, &port, &size)) {
philware 1:8ea78dce6b36 531 tr_debug("Socket RecvFrom: #%d: %d", id, size);
philware 1:8ea78dce6b36 532
philware 1:8ea78dce6b36 533 address->set_ip_address(ipAddress);
philware 1:8ea78dce6b36 534 address->set_port(port);
philware 1:8ea78dce6b36 535
philware 9:f6d022f5c4f5 536 // read the beginning quote for this data
philware 9:f6d022f5c4f5 537 _at->read(tmpBuf, 1);
philware 9:f6d022f5c4f5 538
philware 1:8ea78dce6b36 539 // now read hex data
philware 1:8ea78dce6b36 540 if (_at->read(tmpBuf, size*2) == size*2) {
philware 1:8ea78dce6b36 541
philware 1:8ea78dce6b36 542 // convert to bytes
philware 1:8ea78dce6b36 543 hex_to_bin(tmpBuf, buf, size);
philware 1:8ea78dce6b36 544
philware 9:f6d022f5c4f5 545 // read the "remaining" value - remembing there is an enclosing quote at the beginning of this read
philware 9:f6d022f5c4f5 546 if (!_at->recv("\",%d\n", &remaining)) {
philware 6:658419981430 547 tr_error("Failed reading the 'remaining' value after the received data.");
philware 1:8ea78dce6b36 548 size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 549 }
philware 1:8ea78dce6b36 550 }
philware 1:8ea78dce6b36 551 }
philware 1:8ea78dce6b36 552
philware 1:8ea78dce6b36 553 // we should get the OK (even if there is no data to read)
philware 6:658419981430 554 if (_at->recv("OK")) {
philware 6:658419981430 555 tr_debug("Socket RecvFrom: Read %d bytes, %d bytes remaining.", size, remaining);
philware 6:658419981430 556 } else {
philware 6:658419981430 557 tr_error("Socket RecvFrom: Didn't receive OK from AT+NSORF command.");
philware 1:8ea78dce6b36 558 size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 559 }
philware 1:8ea78dce6b36 560 }
philware 1:8ea78dce6b36 561
philware 6:658419981430 562 _at->debug_on(_debug_trace_on);
philware 1:8ea78dce6b36 563 free(tmpBuf);
philware 1:8ea78dce6b36 564
philware 1:8ea78dce6b36 565 return size;
philware 1:8ea78dce6b36 566 }
philware 1:8ea78dce6b36 567
philware 1:8ea78dce6b36 568 char UbloxATCellularInterfaceN2xx::hex_char(char c)
philware 1:8ea78dce6b36 569 {
philware 1:8ea78dce6b36 570 if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
philware 1:8ea78dce6b36 571 if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
philware 1:8ea78dce6b36 572 if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
philware 1:8ea78dce6b36 573 return 0xFF;
philware 1:8ea78dce6b36 574 }
philware 1:8ea78dce6b36 575
philware 1:8ea78dce6b36 576 int UbloxATCellularInterfaceN2xx::hex_to_bin(const char* s, char * buff, int length)
philware 1:8ea78dce6b36 577 {
philware 1:8ea78dce6b36 578 int result;
philware 1:8ea78dce6b36 579 if (!s || !buff || length <= 0) return -1;
philware 1:8ea78dce6b36 580
philware 1:8ea78dce6b36 581 for (result = 0; *s; ++result)
philware 1:8ea78dce6b36 582 {
philware 1:8ea78dce6b36 583 unsigned char msn = hex_char(*s++);
philware 1:8ea78dce6b36 584 if (msn == 0xFF) return -1;
philware 1:8ea78dce6b36 585 unsigned char lsn = hex_char(*s++);
philware 1:8ea78dce6b36 586 if (lsn == 0xFF) return -1;
philware 1:8ea78dce6b36 587 unsigned char bin = (msn << 4) + lsn;
philware 1:8ea78dce6b36 588
philware 1:8ea78dce6b36 589 if (length-- <= 0) return -1;
philware 1:8ea78dce6b36 590 *buff++ = bin;
philware 1:8ea78dce6b36 591 }
philware 1:8ea78dce6b36 592 return result;
philware 1:8ea78dce6b36 593 }
philware 1:8ea78dce6b36 594
philware 1:8ea78dce6b36 595 // Attach an event callback to a socket, required for asynchronous
philware 1:8ea78dce6b36 596 // data reception
philware 1:8ea78dce6b36 597 void UbloxATCellularInterfaceN2xx::socket_attach(nsapi_socket_t handle,
philware 1:8ea78dce6b36 598 void (*callback)(void *),
philware 1:8ea78dce6b36 599 void *data)
philware 1:8ea78dce6b36 600 {
philware 1:8ea78dce6b36 601 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 602
philware 1:8ea78dce6b36 603 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 604
philware 1:8ea78dce6b36 605 socket->callback = callback;
philware 1:8ea78dce6b36 606 socket->data = data;
philware 1:8ea78dce6b36 607 }
philware 1:8ea78dce6b36 608
philware 1:8ea78dce6b36 609 // Unsupported TCP server functions.
philware 1:8ea78dce6b36 610 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_listen(nsapi_socket_t handle,
philware 1:8ea78dce6b36 611 int backlog)
philware 1:8ea78dce6b36 612 {
philware 1:8ea78dce6b36 613 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 614 }
philware 1:8ea78dce6b36 615 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_accept(nsapi_socket_t server,
philware 1:8ea78dce6b36 616 nsapi_socket_t *handle,
philware 1:8ea78dce6b36 617 SocketAddress *address)
philware 1:8ea78dce6b36 618 {
philware 1:8ea78dce6b36 619 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 620 }
philware 1:8ea78dce6b36 621
philware 1:8ea78dce6b36 622 // Unsupported option functions.
philware 1:8ea78dce6b36 623 nsapi_error_t UbloxATCellularInterfaceN2xx::setsockopt(nsapi_socket_t handle,
philware 1:8ea78dce6b36 624 int level, int optname,
philware 1:8ea78dce6b36 625 const void *optval,
philware 1:8ea78dce6b36 626 unsigned optlen)
philware 1:8ea78dce6b36 627 {
philware 1:8ea78dce6b36 628 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 629 }
philware 1:8ea78dce6b36 630 nsapi_error_t UbloxATCellularInterfaceN2xx::getsockopt(nsapi_socket_t handle,
philware 1:8ea78dce6b36 631 int level, int optname,
philware 1:8ea78dce6b36 632 void *optval,
philware 1:8ea78dce6b36 633 unsigned *optlen)
philware 1:8ea78dce6b36 634 {
philware 1:8ea78dce6b36 635 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 636 }
philware 1:8ea78dce6b36 637
philware 1:8ea78dce6b36 638 /**********************************************************************
philware 1:8ea78dce6b36 639 * PUBLIC METHODS
philware 1:8ea78dce6b36 640 **********************************************************************/
philware 1:8ea78dce6b36 641
philware 1:8ea78dce6b36 642 // Constructor.
philware 1:8ea78dce6b36 643 UbloxATCellularInterfaceN2xx::UbloxATCellularInterfaceN2xx(PinName tx,
philware 1:8ea78dce6b36 644 PinName rx,
philware 1:8ea78dce6b36 645 int baud,
philware 1:8ea78dce6b36 646 bool debug_on)
philware 1:8ea78dce6b36 647 {
philware 1:8ea78dce6b36 648 _sim_pin_check_change_pending = false;
philware 1:8ea78dce6b36 649 _sim_pin_check_change_pending_enabled_value = false;
philware 1:8ea78dce6b36 650 _sim_pin_change_pending = false;
philware 1:8ea78dce6b36 651 _sim_pin_change_pending_new_pin_value = NULL;
philware 1:8ea78dce6b36 652 _apn = NULL;
philware 1:8ea78dce6b36 653 _uname = NULL;
philware 1:8ea78dce6b36 654 _pwd = NULL;
philware 1:8ea78dce6b36 655 _connection_status_cb = NULL;
philware 1:8ea78dce6b36 656
philware 1:8ea78dce6b36 657 _localListenPort = 10000;
philware 1:8ea78dce6b36 658
philware 1:8ea78dce6b36 659 tr_debug("UbloxATCellularInterfaceN2xx Constructor");
philware 1:8ea78dce6b36 660
philware 1:8ea78dce6b36 661 // Initialise sockets storage
philware 1:8ea78dce6b36 662 memset(_sockets, 0, sizeof(_sockets));
philware 1:8ea78dce6b36 663 for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) {
philware 1:8ea78dce6b36 664 _sockets[socket].modem_handle = SOCKET_UNUSED;
philware 1:8ea78dce6b36 665 _sockets[socket].callback = NULL;
philware 1:8ea78dce6b36 666 _sockets[socket].data = NULL;
philware 1:8ea78dce6b36 667 }
philware 1:8ea78dce6b36 668
philware 1:8ea78dce6b36 669 // The authentication to use
philware 1:8ea78dce6b36 670 _auth = NSAPI_SECURITY_UNKNOWN;
philware 1:8ea78dce6b36 671
philware 1:8ea78dce6b36 672 // Nullify the temporary IP address storage
philware 1:8ea78dce6b36 673 _ip = NULL;
philware 1:8ea78dce6b36 674
philware 1:8ea78dce6b36 675 // Initialise the base class, which starts the AT parser
philware 1:8ea78dce6b36 676 baseClassInit(tx, rx, baud, debug_on);
philware 1:8ea78dce6b36 677
philware 1:8ea78dce6b36 678 // Start the event handler thread for Rx data
philware 1:8ea78dce6b36 679 event_thread.start(callback(this, &UbloxATCellularInterfaceN2xx::handle_event));
philware 1:8ea78dce6b36 680
philware 1:8ea78dce6b36 681 // URC handlers for sockets
philware 1:8ea78dce6b36 682 _at->oob("+NSONMI", callback(this, &UbloxATCellularInterfaceN2xx::NSONMI_URC));
philware 1:8ea78dce6b36 683 }
philware 1:8ea78dce6b36 684
philware 1:8ea78dce6b36 685 // Destructor.
philware 1:8ea78dce6b36 686 UbloxATCellularInterfaceN2xx::~UbloxATCellularInterfaceN2xx()
philware 1:8ea78dce6b36 687 {
philware 1:8ea78dce6b36 688 // Free _ip if it was ever allocated
philware 1:8ea78dce6b36 689 free(_ip);
philware 1:8ea78dce6b36 690 }
philware 1:8ea78dce6b36 691
philware 1:8ea78dce6b36 692 // Set the authentication scheme.
philware 1:8ea78dce6b36 693 void UbloxATCellularInterfaceN2xx::set_authentication(nsapi_security_t auth)
philware 1:8ea78dce6b36 694 {
philware 1:8ea78dce6b36 695 _auth = auth;
philware 1:8ea78dce6b36 696 }
philware 1:8ea78dce6b36 697
philware 1:8ea78dce6b36 698 // Set APN, user name and password.
philware 1:8ea78dce6b36 699 void UbloxATCellularInterfaceN2xx::set_credentials(const char *apn,
philware 1:8ea78dce6b36 700 const char *uname,
philware 1:8ea78dce6b36 701 const char *pwd)
philware 1:8ea78dce6b36 702 {
philware 1:8ea78dce6b36 703 _apn = apn;
philware 1:8ea78dce6b36 704 _uname = uname;
philware 1:8ea78dce6b36 705 _pwd = pwd;
philware 1:8ea78dce6b36 706 }
philware 1:8ea78dce6b36 707
philware 1:8ea78dce6b36 708 // Set PIN.
philware 1:8ea78dce6b36 709 void UbloxATCellularInterfaceN2xx::set_sim_pin(const char *pin) {
philware 1:8ea78dce6b36 710 set_pin(pin);
philware 1:8ea78dce6b36 711 }
philware 1:8ea78dce6b36 712
philware 1:8ea78dce6b36 713 // Get the IP address of a host.
philware 1:8ea78dce6b36 714 nsapi_error_t UbloxATCellularInterfaceN2xx::gethostbyname(const char *host,
philware 1:8ea78dce6b36 715 SocketAddress *address,
philware 1:8ea78dce6b36 716 nsapi_version_t version)
philware 1:8ea78dce6b36 717 {
philware 1:8ea78dce6b36 718 nsapi_error_t nsapiError = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 719 tr_debug("GetHostByName: host= %s", host);
philware 1:8ea78dce6b36 720 if (address->set_ip_address(host)) {
philware 1:8ea78dce6b36 721 tr_debug("OK");
philware 1:8ea78dce6b36 722 nsapiError = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 723 } else {
philware 1:8ea78dce6b36 724 tr_debug("Failed");
philware 1:8ea78dce6b36 725 nsapiError = NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 726 }
philware 1:8ea78dce6b36 727
philware 1:8ea78dce6b36 728 return nsapiError;
philware 1:8ea78dce6b36 729 }
philware 1:8ea78dce6b36 730
philware 1:8ea78dce6b36 731 // Make a cellular connection
philware 1:8ea78dce6b36 732 nsapi_error_t UbloxATCellularInterfaceN2xx::connect(const char *sim_pin,
philware 1:8ea78dce6b36 733 const char *apn,
philware 1:8ea78dce6b36 734 const char *uname,
philware 1:8ea78dce6b36 735 const char *pwd)
philware 1:8ea78dce6b36 736 {
philware 1:8ea78dce6b36 737 nsapi_error_t nsapi_error;
philware 1:8ea78dce6b36 738
philware 1:8ea78dce6b36 739 if (sim_pin != NULL) {
philware 1:8ea78dce6b36 740 _pin = sim_pin;
philware 1:8ea78dce6b36 741 }
philware 1:8ea78dce6b36 742
philware 1:8ea78dce6b36 743 if (apn != NULL) {
philware 1:8ea78dce6b36 744 _apn = apn;
philware 1:8ea78dce6b36 745 }
philware 1:8ea78dce6b36 746
philware 1:8ea78dce6b36 747 if ((uname != NULL) && (pwd != NULL)) {
philware 1:8ea78dce6b36 748 _uname = uname;
philware 1:8ea78dce6b36 749 _pwd = pwd;
philware 1:8ea78dce6b36 750 } else {
philware 1:8ea78dce6b36 751 _uname = NULL;
philware 1:8ea78dce6b36 752 _pwd = NULL;
philware 1:8ea78dce6b36 753 }
philware 1:8ea78dce6b36 754
philware 1:8ea78dce6b36 755 tr_debug("SIM, APN, UName & pwd set, now calling connect()");
philware 1:8ea78dce6b36 756 nsapi_error = connect();
philware 1:8ea78dce6b36 757
philware 1:8ea78dce6b36 758 return nsapi_error;
philware 1:8ea78dce6b36 759 }
philware 1:8ea78dce6b36 760
philware 4:2bf3875a13f1 761 bool UbloxATCellularInterfaceN2xx::initialise()
philware 4:2bf3875a13f1 762 {
philware 4:2bf3875a13f1 763 return init();
philware 4:2bf3875a13f1 764 }
philware 4:2bf3875a13f1 765
philware 1:8ea78dce6b36 766 // Make a cellular connection using the IP stack on board the cellular modem
philware 1:8ea78dce6b36 767 nsapi_error_t UbloxATCellularInterfaceN2xx::connect()
philware 1:8ea78dce6b36 768 {
philware 1:8ea78dce6b36 769 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 770 bool registered = false;
philware 1:8ea78dce6b36 771
philware 1:8ea78dce6b36 772 // Set up modem and then register with the network
philware 4:2bf3875a13f1 773 if (initialise()) {
philware 1:8ea78dce6b36 774
philware 1:8ea78dce6b36 775 tr_debug("Trying to register...");
philware 1:8ea78dce6b36 776 nsapi_error = NSAPI_ERROR_NO_CONNECTION;
philware 1:8ea78dce6b36 777 for (int retries = 0; !registered && (retries < 3); retries++) {
philware 1:8ea78dce6b36 778 if (nwk_registration()) {
philware 1:8ea78dce6b36 779 registered = true;
philware 1:8ea78dce6b36 780 }
philware 1:8ea78dce6b36 781 }
philware 1:8ea78dce6b36 782 }
philware 1:8ea78dce6b36 783
philware 1:8ea78dce6b36 784 // Attempt to establish a connection
philware 1:8ea78dce6b36 785 if (registered) {
philware 1:8ea78dce6b36 786 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 787 } else {
philware 1:8ea78dce6b36 788 tr_debug("Failed to register.");
philware 1:8ea78dce6b36 789 }
philware 1:8ea78dce6b36 790
philware 1:8ea78dce6b36 791 return nsapi_error;
philware 1:8ea78dce6b36 792 }
philware 1:8ea78dce6b36 793
philware 1:8ea78dce6b36 794 // User initiated disconnect.
philware 1:8ea78dce6b36 795 nsapi_error_t UbloxATCellularInterfaceN2xx::disconnect()
philware 1:8ea78dce6b36 796 {
philware 1:8ea78dce6b36 797 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 798
philware 1:8ea78dce6b36 799 if (nwk_deregistration()) {
philware 1:8ea78dce6b36 800 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 801
philware 1:8ea78dce6b36 802 if (_connection_status_cb) {
philware 1:8ea78dce6b36 803 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
philware 1:8ea78dce6b36 804 }
philware 1:8ea78dce6b36 805 }
philware 1:8ea78dce6b36 806
philware 1:8ea78dce6b36 807 return nsapi_error;
philware 1:8ea78dce6b36 808 }
philware 1:8ea78dce6b36 809
philware 1:8ea78dce6b36 810 // Enable or disable SIM PIN check lock.
philware 1:8ea78dce6b36 811 nsapi_error_t UbloxATCellularInterfaceN2xx::set_sim_pin_check(bool set,
philware 1:8ea78dce6b36 812 bool immediate,
philware 1:8ea78dce6b36 813 const char *sim_pin)
philware 1:8ea78dce6b36 814 {
philware 1:8ea78dce6b36 815 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 816 }
philware 1:8ea78dce6b36 817
philware 1:8ea78dce6b36 818 // Change the PIN code for the SIM card.
philware 1:8ea78dce6b36 819 nsapi_error_t UbloxATCellularInterfaceN2xx::set_new_sim_pin(const char *new_pin,
philware 1:8ea78dce6b36 820 bool immediate,
philware 1:8ea78dce6b36 821 const char *old_pin)
philware 1:8ea78dce6b36 822 {
philware 1:8ea78dce6b36 823 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 824 }
philware 1:8ea78dce6b36 825
philware 1:8ea78dce6b36 826 // Determine if the connection is up.
philware 1:8ea78dce6b36 827 bool UbloxATCellularInterfaceN2xx::is_connected()
philware 1:8ea78dce6b36 828 {
philware 1:8ea78dce6b36 829 return get_ip_address() != NULL;
philware 1:8ea78dce6b36 830 }
philware 1:8ea78dce6b36 831
philware 1:8ea78dce6b36 832 // Get the IP address of the on-board modem IP stack.
philware 1:8ea78dce6b36 833 const char * UbloxATCellularInterfaceN2xx::get_ip_address()
philware 1:8ea78dce6b36 834 {
philware 1:8ea78dce6b36 835 SocketAddress address;
philware 1:8ea78dce6b36 836 int id;
philware 1:8ea78dce6b36 837 LOCK();
philware 1:8ea78dce6b36 838
philware 1:8ea78dce6b36 839 if (_ip == NULL)
philware 1:8ea78dce6b36 840 {
philware 1:8ea78dce6b36 841 // Temporary storage for an IP address string with terminator
philware 1:8ea78dce6b36 842 _ip = (char *) malloc(NSAPI_IP_SIZE);
philware 1:8ea78dce6b36 843 }
philware 1:8ea78dce6b36 844
philware 1:8ea78dce6b36 845 if (_ip != NULL) {
philware 1:8ea78dce6b36 846 memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator
philware 1:8ea78dce6b36 847 // +CGPADDR - returns a list of IP Addresses per context, just pick the first one as SARA-N2xx only allows 1 context.
philware 1:8ea78dce6b36 848 if (!_at->send("AT+CGPADDR") ||
philware 1:8ea78dce6b36 849 !_at->recv("+CGPADDR:%d,%15[^\n]\n", &id, _ip) ||
philware 1:8ea78dce6b36 850 ! _at->recv("OK") ||
philware 1:8ea78dce6b36 851 !address.set_ip_address(_ip) ||
philware 1:8ea78dce6b36 852 !address) {
philware 1:8ea78dce6b36 853 free (_ip);
philware 1:8ea78dce6b36 854 _ip = NULL;
philware 1:8ea78dce6b36 855 }
philware 1:8ea78dce6b36 856 }
philware 1:8ea78dce6b36 857
philware 1:8ea78dce6b36 858 UNLOCK();
philware 1:8ea78dce6b36 859 return _ip;
philware 1:8ea78dce6b36 860 }
philware 1:8ea78dce6b36 861
philware 1:8ea78dce6b36 862 // Get the local network mask.
philware 1:8ea78dce6b36 863 const char *UbloxATCellularInterfaceN2xx::get_netmask()
philware 1:8ea78dce6b36 864 {
philware 1:8ea78dce6b36 865 // Not implemented.
philware 1:8ea78dce6b36 866 return NULL;
philware 1:8ea78dce6b36 867 }
philware 1:8ea78dce6b36 868
philware 1:8ea78dce6b36 869 // Get the local gateways.
philware 1:8ea78dce6b36 870 const char *UbloxATCellularInterfaceN2xx::get_gateway()
philware 1:8ea78dce6b36 871 {
philware 1:8ea78dce6b36 872 return get_ip_address();
philware 1:8ea78dce6b36 873 }
philware 1:8ea78dce6b36 874
philware 1:8ea78dce6b36 875 void UbloxATCellularInterfaceN2xx::set_LocalListenPort(int port) {
philware 1:8ea78dce6b36 876 _localListenPort = port;
philware 1:8ea78dce6b36 877 }
philware 1:8ea78dce6b36 878
philware 1:8ea78dce6b36 879 // Callback in case the connection is lost.
philware 1:8ea78dce6b36 880 void UbloxATCellularInterfaceN2xx::connection_status_cb(Callback<void(nsapi_error_t)> cb)
philware 1:8ea78dce6b36 881 {
philware 1:8ea78dce6b36 882 _connection_status_cb = cb;
philware 1:8ea78dce6b36 883 }
philware 1:8ea78dce6b36 884
philware 1:8ea78dce6b36 885 // End of file
philware 1:8ea78dce6b36 886