ublox-at-cellular-interface-n2xx

Committer:
philware
Date:
Tue Aug 22 16:37:30 2017 +0100
Revision:
4:2bf3875a13f1
Parent:
1:8ea78dce6b36
Child:
6:658419981430
Adding a SendATChopped() function to chop up very long AT command strings for the SendTo() function.

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 1:8ea78dce6b36 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;
philware 1:8ea78dce6b36 258 nsapi_size_t blk = MAX_WRITE_SIZE;
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
philware 1:8ea78dce6b36 267 tr_debug("Max Write Size for SendTo: %d", MAX_WRITE_SIZE);
philware 1:8ea78dce6b36 268 if (size > MAX_WRITE_SIZE) {
philware 1:8ea78dce6b36 269 tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE);
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 1:8ea78dce6b36 302
philware 1:8ea78dce6b36 303 tr_debug("Malloc %d * 2 + 1 bytes", size);
philware 1:8ea78dce6b36 304 char *str = (char *) malloc((size * 2) + 1);
philware 1:8ea78dce6b36 305 if (str == NULL) {
philware 1:8ea78dce6b36 306 tr_error("Nope, could allocate it!");
philware 1:8ea78dce6b36 307 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 308 }
philware 1:8ea78dce6b36 309
philware 1:8ea78dce6b36 310 tr_debug("Converting byte array to hex string");
philware 1:8ea78dce6b36 311 bin_to_hex(buf, size, str);
philware 1:8ea78dce6b36 312 tr_debug("Got hex string");
philware 1:8ea78dce6b36 313
philware 1:8ea78dce6b36 314 LOCK();
philware 1:8ea78dce6b36 315
philware 1:8ea78dce6b36 316 // AT+NSOSTF= socket, remote_addr, remote_port, length, data
philware 4:2bf3875a13f1 317 tr_debug("Writing AT+NSOSTF=<sktid>,<ipaddr>,<port>,<flags>,<size>,<hex string> command...");
philware 4:2bf3875a13f1 318 char cmd[50];
philware 4:2bf3875a13f1 319 int cmdsize = sprintf(cmd, "AT+NSOSTF=%d,%s,%d,0x0,%d,", socket->modem_handle, address.get_ip_address(), address.get_port(), size);
philware 4:2bf3875a13f1 320 if (_at->write(cmd, cmdsize+1) && sendATChopped(str)) {
philware 1:8ea78dce6b36 321 tr_debug("Reading back the Sent Size...");
philware 1:8ea78dce6b36 322 if (_at->recv("%d,%d\n", &id, &sent) && _at->recv("OK")) {
philware 1:8ea78dce6b36 323 tr_debug("Received %d bytes on socket %d", sent, id);
philware 1:8ea78dce6b36 324 } else {
philware 1:8ea78dce6b36 325 tr_error("Didn't get the Sent size or OK");
philware 1:8ea78dce6b36 326 }
philware 1:8ea78dce6b36 327 } else {
philware 1:8ea78dce6b36 328 tr_error("Didn't send the AT command!");
philware 1:8ea78dce6b36 329 }
philware 1:8ea78dce6b36 330
philware 1:8ea78dce6b36 331 UNLOCK();
philware 1:8ea78dce6b36 332 free(str);
philware 1:8ea78dce6b36 333
philware 1:8ea78dce6b36 334 return sent;
philware 1:8ea78dce6b36 335 }
philware 1:8ea78dce6b36 336
philware 4:2bf3875a13f1 337 bool UbloxATCellularInterfaceN2xx::sendATChopped(const char *cmd)
philware 4:2bf3875a13f1 338 {
philware 4:2bf3875a13f1 339 char buff[SENDTO_CHUNK_SIZE];
philware 4:2bf3875a13f1 340 while (*cmd != '\0')
philware 4:2bf3875a13f1 341 {
philware 4:2bf3875a13f1 342 int i=0;
philware 4:2bf3875a13f1 343
philware 4:2bf3875a13f1 344 tr_debug("Copying up to 50 chars... ");
philware 4:2bf3875a13f1 345 for (i=0; i<SENDTO_CHUNK_SIZE; i++) {
philware 4:2bf3875a13f1 346 buff[i] = *cmd;
philware 4:2bf3875a13f1 347
philware 4:2bf3875a13f1 348 // if we have copied the NULL terminator, we can exit
philware 4:2bf3875a13f1 349 if (*cmd == '\0')
philware 4:2bf3875a13f1 350 break;
philware 4:2bf3875a13f1 351
philware 4:2bf3875a13f1 352 // still more characters to copy, so move along
philware 4:2bf3875a13f1 353 cmd++;
philware 4:2bf3875a13f1 354 }
philware 4:2bf3875a13f1 355 tr_debug("Copied %d chars. ", i);
philware 4:2bf3875a13f1 356
philware 4:2bf3875a13f1 357 if (*cmd == '\0') {
philware 4:2bf3875a13f1 358 tr_debug("send()\n");
philware 4:2bf3875a13f1 359 if (!_at->send(buff))
philware 4:2bf3875a13f1 360 return false;
philware 4:2bf3875a13f1 361 } else {
philware 4:2bf3875a13f1 362 tr_debug("write()\n");
philware 4:2bf3875a13f1 363 if (!_at->write(buff, 50))
philware 4:2bf3875a13f1 364 return false;
philware 4:2bf3875a13f1 365 }
philware 4:2bf3875a13f1 366 }
philware 4:2bf3875a13f1 367
philware 4:2bf3875a13f1 368 return true;
philware 4:2bf3875a13f1 369 }
philware 4:2bf3875a13f1 370
philware 1:8ea78dce6b36 371 void UbloxATCellularInterfaceN2xx::bin_to_hex(const char *buff, unsigned int length, char *output)
philware 1:8ea78dce6b36 372 {
philware 1:8ea78dce6b36 373 char binHex[] = "0123456789ABCDEF";
philware 1:8ea78dce6b36 374
philware 1:8ea78dce6b36 375 *output = '\0';
philware 1:8ea78dce6b36 376
philware 1:8ea78dce6b36 377 for (; length > 0; --length)
philware 1:8ea78dce6b36 378 {
philware 1:8ea78dce6b36 379 unsigned char byte = *buff++;
philware 1:8ea78dce6b36 380
philware 1:8ea78dce6b36 381 *output++ = binHex[(byte >> 4) & 0x0F];
philware 1:8ea78dce6b36 382 *output++ = binHex[byte & 0x0F];
philware 1:8ea78dce6b36 383 }
philware 1:8ea78dce6b36 384
philware 1:8ea78dce6b36 385 *output++ = '\0';
philware 1:8ea78dce6b36 386 }
philware 1:8ea78dce6b36 387
philware 1:8ea78dce6b36 388 // Receive from a socket, TCP style.
philware 1:8ea78dce6b36 389 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recv(nsapi_socket_t handle,
philware 1:8ea78dce6b36 390 void *data,
philware 1:8ea78dce6b36 391 nsapi_size_t size)
philware 1:8ea78dce6b36 392 {
philware 1:8ea78dce6b36 393 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 394 }
philware 1:8ea78dce6b36 395
philware 1:8ea78dce6b36 396 // Receive a packet over a UDP socket.
philware 1:8ea78dce6b36 397 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::socket_recvfrom(nsapi_socket_t handle,
philware 1:8ea78dce6b36 398 SocketAddress *address,
philware 1:8ea78dce6b36 399 void *data,
philware 1:8ea78dce6b36 400 nsapi_size_t size)
philware 1:8ea78dce6b36 401 {
philware 1:8ea78dce6b36 402 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 403 bool success = true;
philware 1:8ea78dce6b36 404 char *buf = (char *) data;
philware 1:8ea78dce6b36 405 nsapi_size_t read_blk;
philware 1:8ea78dce6b36 406 nsapi_size_t count = 0;
philware 1:8ea78dce6b36 407 char ipAddress[NSAPI_IP_SIZE];
philware 1:8ea78dce6b36 408
philware 1:8ea78dce6b36 409 char * tmpBuf = NULL;
philware 1:8ea78dce6b36 410
philware 1:8ea78dce6b36 411 Timer timer;
philware 1:8ea78dce6b36 412 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 413 int at_timeout = _at_timeout;
philware 1:8ea78dce6b36 414
philware 1:8ea78dce6b36 415 tr_debug("socket_recvfrom(0x%08x, 0x%08x, %d)", (unsigned int) handle,
philware 1:8ea78dce6b36 416 (unsigned int) data, size);
philware 1:8ea78dce6b36 417
philware 1:8ea78dce6b36 418 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 419
philware 1:8ea78dce6b36 420 timer.start();
philware 1:8ea78dce6b36 421
philware 1:8ea78dce6b36 422 while (success && (size > 0)) {
philware 1:8ea78dce6b36 423 LOCK();
philware 1:8ea78dce6b36 424 at_set_timeout(1000);
philware 1:8ea78dce6b36 425
philware 1:8ea78dce6b36 426 read_blk = socket->pending;
philware 1:8ea78dce6b36 427 if (read_blk > MAX_READ_SIZE) {
philware 1:8ea78dce6b36 428 read_blk = MAX_READ_SIZE;
philware 1:8ea78dce6b36 429 }
philware 1:8ea78dce6b36 430 if (read_blk > 0) {
philware 1:8ea78dce6b36 431 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
philware 1:8ea78dce6b36 432
philware 1:8ea78dce6b36 433 tmpBuf = (char *) malloc(read_blk);
philware 1:8ea78dce6b36 434 if (tmpBuf == NULL) {
philware 1:8ea78dce6b36 435 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 436 }
philware 1:8ea78dce6b36 437
philware 1:8ea78dce6b36 438 // call the AT helper function to get the bytes
philware 1:8ea78dce6b36 439 nsapi_error_size = receivefrom(socket->modem_handle, address, read_blk, tmpBuf);
philware 1:8ea78dce6b36 440
philware 1:8ea78dce6b36 441 if (nsapi_error_size >= 0) {
philware 1:8ea78dce6b36 442 memcpy(buf, tmpBuf, nsapi_error_size);
philware 1:8ea78dce6b36 443
philware 1:8ea78dce6b36 444 socket->pending -= read_blk;
philware 1:8ea78dce6b36 445 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending",
philware 1:8ea78dce6b36 446 (unsigned int) socket, socket->modem_handle, socket->pending);
philware 1:8ea78dce6b36 447
philware 1:8ea78dce6b36 448 count += nsapi_error_size;
philware 1:8ea78dce6b36 449 buf += nsapi_error_size;
philware 1:8ea78dce6b36 450 size = 0; // A UDP packet arrives in one piece, so this means DONE.
philware 1:8ea78dce6b36 451 } else {
philware 1:8ea78dce6b36 452 // Should never fail to read when there is pending data
philware 1:8ea78dce6b36 453 success = false;
philware 1:8ea78dce6b36 454 }
philware 1:8ea78dce6b36 455 } else if (timer.read_ms() < SOCKET_TIMEOUT) {
philware 1:8ea78dce6b36 456 // Wait for URCs
philware 1:8ea78dce6b36 457 _at->recv(UNNATURAL_STRING);
philware 1:8ea78dce6b36 458 } else {
philware 1:8ea78dce6b36 459 // Timeout with nothing received
philware 1:8ea78dce6b36 460 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK;
philware 1:8ea78dce6b36 461 success = false;
philware 1:8ea78dce6b36 462 }
philware 1:8ea78dce6b36 463
philware 1:8ea78dce6b36 464 at_set_timeout(at_timeout);
philware 1:8ea78dce6b36 465 UNLOCK();
philware 1:8ea78dce6b36 466 }
philware 1:8ea78dce6b36 467 timer.stop();
philware 1:8ea78dce6b36 468
philware 1:8ea78dce6b36 469 if (success) {
philware 1:8ea78dce6b36 470 nsapi_error_size = count;
philware 1:8ea78dce6b36 471 }
philware 1:8ea78dce6b36 472
philware 1:8ea78dce6b36 473 tr_debug("socket_recvfrom: %d \"%*.*s\"", count, count, count, buf - count);
philware 1:8ea78dce6b36 474
philware 1:8ea78dce6b36 475 return nsapi_error_size;
philware 1:8ea78dce6b36 476 }
philware 1:8ea78dce6b36 477
philware 1:8ea78dce6b36 478 nsapi_size_or_error_t UbloxATCellularInterfaceN2xx::receivefrom(int modem_handle, SocketAddress *address, int length, char *buf) {
philware 1:8ea78dce6b36 479 char ipAddress[NSAPI_IP_SIZE];
philware 1:8ea78dce6b36 480 nsapi_size_or_error_t size;
philware 1:8ea78dce6b36 481
philware 1:8ea78dce6b36 482 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
philware 1:8ea78dce6b36 483
philware 1:8ea78dce6b36 484 if (length > MAX_READ_SIZE) {
philware 1:8ea78dce6b36 485 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 486 }
philware 1:8ea78dce6b36 487
philware 1:8ea78dce6b36 488 char * tmpBuf = (char *) malloc(length*2);
philware 1:8ea78dce6b36 489 if (tmpBuf == NULL)
philware 1:8ea78dce6b36 490 return NSAPI_ERROR_NO_MEMORY;
philware 1:8ea78dce6b36 491
philware 1:8ea78dce6b36 492 LOCK();
philware 1:8ea78dce6b36 493
philware 1:8ea78dce6b36 494 // Ask for x bytes from Socket
philware 1:8ea78dce6b36 495 if (_at->send("AT+NSORF=%d,%d", modem_handle, length)) {
philware 1:8ea78dce6b36 496 unsigned int id, port;
philware 1:8ea78dce6b36 497
philware 1:8ea78dce6b36 498 // ReadFrom header, to get length - if no data then this will time out
philware 1:8ea78dce6b36 499 if (_at->recv("%d,%15[^,],%d,%d,", &id, ipAddress, &port, &size)) {
philware 1:8ea78dce6b36 500 tr_debug("Socket RecvFrom: #%d: %d", id, size);
philware 1:8ea78dce6b36 501
philware 1:8ea78dce6b36 502 address->set_ip_address(ipAddress);
philware 1:8ea78dce6b36 503 address->set_port(port);
philware 1:8ea78dce6b36 504
philware 1:8ea78dce6b36 505 // now read hex data
philware 1:8ea78dce6b36 506 if (_at->read(tmpBuf, size*2) == size*2) {
philware 1:8ea78dce6b36 507
philware 1:8ea78dce6b36 508 // convert to bytes
philware 1:8ea78dce6b36 509 hex_to_bin(tmpBuf, buf, size);
philware 1:8ea78dce6b36 510
philware 1:8ea78dce6b36 511 // read the "remaining" value
philware 1:8ea78dce6b36 512 char remaining[4];
philware 1:8ea78dce6b36 513 if (!_at->recv(",%3[^\n]\n", remaining)) {
philware 1:8ea78dce6b36 514 size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 515 }
philware 1:8ea78dce6b36 516 }
philware 1:8ea78dce6b36 517 }
philware 1:8ea78dce6b36 518
philware 1:8ea78dce6b36 519 // we should get the OK (even if there is no data to read)
philware 1:8ea78dce6b36 520 if (!_at->recv("OK")) {
philware 1:8ea78dce6b36 521 size = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 522 }
philware 1:8ea78dce6b36 523 }
philware 1:8ea78dce6b36 524
philware 1:8ea78dce6b36 525 UNLOCK();
philware 1:8ea78dce6b36 526
philware 1:8ea78dce6b36 527 free(tmpBuf);
philware 1:8ea78dce6b36 528
philware 1:8ea78dce6b36 529 return size;
philware 1:8ea78dce6b36 530 }
philware 1:8ea78dce6b36 531
philware 1:8ea78dce6b36 532 char UbloxATCellularInterfaceN2xx::hex_char(char c)
philware 1:8ea78dce6b36 533 {
philware 1:8ea78dce6b36 534 if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
philware 1:8ea78dce6b36 535 if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
philware 1:8ea78dce6b36 536 if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
philware 1:8ea78dce6b36 537 return 0xFF;
philware 1:8ea78dce6b36 538 }
philware 1:8ea78dce6b36 539
philware 1:8ea78dce6b36 540 int UbloxATCellularInterfaceN2xx::hex_to_bin(const char* s, char * buff, int length)
philware 1:8ea78dce6b36 541 {
philware 1:8ea78dce6b36 542 int result;
philware 1:8ea78dce6b36 543 if (!s || !buff || length <= 0) return -1;
philware 1:8ea78dce6b36 544
philware 1:8ea78dce6b36 545 for (result = 0; *s; ++result)
philware 1:8ea78dce6b36 546 {
philware 1:8ea78dce6b36 547 unsigned char msn = hex_char(*s++);
philware 1:8ea78dce6b36 548 if (msn == 0xFF) return -1;
philware 1:8ea78dce6b36 549 unsigned char lsn = hex_char(*s++);
philware 1:8ea78dce6b36 550 if (lsn == 0xFF) return -1;
philware 1:8ea78dce6b36 551 unsigned char bin = (msn << 4) + lsn;
philware 1:8ea78dce6b36 552
philware 1:8ea78dce6b36 553 if (length-- <= 0) return -1;
philware 1:8ea78dce6b36 554 *buff++ = bin;
philware 1:8ea78dce6b36 555 }
philware 1:8ea78dce6b36 556 return result;
philware 1:8ea78dce6b36 557 }
philware 1:8ea78dce6b36 558
philware 1:8ea78dce6b36 559 // Attach an event callback to a socket, required for asynchronous
philware 1:8ea78dce6b36 560 // data reception
philware 1:8ea78dce6b36 561 void UbloxATCellularInterfaceN2xx::socket_attach(nsapi_socket_t handle,
philware 1:8ea78dce6b36 562 void (*callback)(void *),
philware 1:8ea78dce6b36 563 void *data)
philware 1:8ea78dce6b36 564 {
philware 1:8ea78dce6b36 565 SockCtrl *socket = (SockCtrl *) handle;
philware 1:8ea78dce6b36 566
philware 1:8ea78dce6b36 567 MBED_ASSERT (check_socket(socket));
philware 1:8ea78dce6b36 568
philware 1:8ea78dce6b36 569 socket->callback = callback;
philware 1:8ea78dce6b36 570 socket->data = data;
philware 1:8ea78dce6b36 571 }
philware 1:8ea78dce6b36 572
philware 1:8ea78dce6b36 573 // Unsupported TCP server functions.
philware 1:8ea78dce6b36 574 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_listen(nsapi_socket_t handle,
philware 1:8ea78dce6b36 575 int backlog)
philware 1:8ea78dce6b36 576 {
philware 1:8ea78dce6b36 577 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 578 }
philware 1:8ea78dce6b36 579 nsapi_error_t UbloxATCellularInterfaceN2xx::socket_accept(nsapi_socket_t server,
philware 1:8ea78dce6b36 580 nsapi_socket_t *handle,
philware 1:8ea78dce6b36 581 SocketAddress *address)
philware 1:8ea78dce6b36 582 {
philware 1:8ea78dce6b36 583 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 584 }
philware 1:8ea78dce6b36 585
philware 1:8ea78dce6b36 586 // Unsupported option functions.
philware 1:8ea78dce6b36 587 nsapi_error_t UbloxATCellularInterfaceN2xx::setsockopt(nsapi_socket_t handle,
philware 1:8ea78dce6b36 588 int level, int optname,
philware 1:8ea78dce6b36 589 const void *optval,
philware 1:8ea78dce6b36 590 unsigned optlen)
philware 1:8ea78dce6b36 591 {
philware 1:8ea78dce6b36 592 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 593 }
philware 1:8ea78dce6b36 594 nsapi_error_t UbloxATCellularInterfaceN2xx::getsockopt(nsapi_socket_t handle,
philware 1:8ea78dce6b36 595 int level, int optname,
philware 1:8ea78dce6b36 596 void *optval,
philware 1:8ea78dce6b36 597 unsigned *optlen)
philware 1:8ea78dce6b36 598 {
philware 1:8ea78dce6b36 599 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 600 }
philware 1:8ea78dce6b36 601
philware 1:8ea78dce6b36 602 /**********************************************************************
philware 1:8ea78dce6b36 603 * PUBLIC METHODS
philware 1:8ea78dce6b36 604 **********************************************************************/
philware 1:8ea78dce6b36 605
philware 1:8ea78dce6b36 606 // Constructor.
philware 1:8ea78dce6b36 607 UbloxATCellularInterfaceN2xx::UbloxATCellularInterfaceN2xx(PinName tx,
philware 1:8ea78dce6b36 608 PinName rx,
philware 1:8ea78dce6b36 609 int baud,
philware 1:8ea78dce6b36 610 bool debug_on)
philware 1:8ea78dce6b36 611 {
philware 1:8ea78dce6b36 612 _sim_pin_check_change_pending = false;
philware 1:8ea78dce6b36 613 _sim_pin_check_change_pending_enabled_value = false;
philware 1:8ea78dce6b36 614 _sim_pin_change_pending = false;
philware 1:8ea78dce6b36 615 _sim_pin_change_pending_new_pin_value = NULL;
philware 1:8ea78dce6b36 616 _apn = NULL;
philware 1:8ea78dce6b36 617 _uname = NULL;
philware 1:8ea78dce6b36 618 _pwd = NULL;
philware 1:8ea78dce6b36 619 _connection_status_cb = NULL;
philware 1:8ea78dce6b36 620
philware 1:8ea78dce6b36 621 _localListenPort = 10000;
philware 1:8ea78dce6b36 622
philware 1:8ea78dce6b36 623 tr_debug("UbloxATCellularInterfaceN2xx Constructor");
philware 1:8ea78dce6b36 624
philware 1:8ea78dce6b36 625 // Initialise sockets storage
philware 1:8ea78dce6b36 626 memset(_sockets, 0, sizeof(_sockets));
philware 1:8ea78dce6b36 627 for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) {
philware 1:8ea78dce6b36 628 _sockets[socket].modem_handle = SOCKET_UNUSED;
philware 1:8ea78dce6b36 629 _sockets[socket].callback = NULL;
philware 1:8ea78dce6b36 630 _sockets[socket].data = NULL;
philware 1:8ea78dce6b36 631 }
philware 1:8ea78dce6b36 632
philware 1:8ea78dce6b36 633 // The authentication to use
philware 1:8ea78dce6b36 634 _auth = NSAPI_SECURITY_UNKNOWN;
philware 1:8ea78dce6b36 635
philware 1:8ea78dce6b36 636 // Nullify the temporary IP address storage
philware 1:8ea78dce6b36 637 _ip = NULL;
philware 1:8ea78dce6b36 638
philware 1:8ea78dce6b36 639 // Initialise the base class, which starts the AT parser
philware 1:8ea78dce6b36 640 baseClassInit(tx, rx, baud, debug_on);
philware 1:8ea78dce6b36 641
philware 1:8ea78dce6b36 642 // Start the event handler thread for Rx data
philware 1:8ea78dce6b36 643 event_thread.start(callback(this, &UbloxATCellularInterfaceN2xx::handle_event));
philware 1:8ea78dce6b36 644
philware 1:8ea78dce6b36 645 // URC handlers for sockets
philware 1:8ea78dce6b36 646 _at->oob("+NSONMI", callback(this, &UbloxATCellularInterfaceN2xx::NSONMI_URC));
philware 1:8ea78dce6b36 647 }
philware 1:8ea78dce6b36 648
philware 1:8ea78dce6b36 649 // Destructor.
philware 1:8ea78dce6b36 650 UbloxATCellularInterfaceN2xx::~UbloxATCellularInterfaceN2xx()
philware 1:8ea78dce6b36 651 {
philware 1:8ea78dce6b36 652 // Free _ip if it was ever allocated
philware 1:8ea78dce6b36 653 free(_ip);
philware 1:8ea78dce6b36 654 }
philware 1:8ea78dce6b36 655
philware 1:8ea78dce6b36 656 // Set the authentication scheme.
philware 1:8ea78dce6b36 657 void UbloxATCellularInterfaceN2xx::set_authentication(nsapi_security_t auth)
philware 1:8ea78dce6b36 658 {
philware 1:8ea78dce6b36 659 _auth = auth;
philware 1:8ea78dce6b36 660 }
philware 1:8ea78dce6b36 661
philware 1:8ea78dce6b36 662 // Set APN, user name and password.
philware 1:8ea78dce6b36 663 void UbloxATCellularInterfaceN2xx::set_credentials(const char *apn,
philware 1:8ea78dce6b36 664 const char *uname,
philware 1:8ea78dce6b36 665 const char *pwd)
philware 1:8ea78dce6b36 666 {
philware 1:8ea78dce6b36 667 _apn = apn;
philware 1:8ea78dce6b36 668 _uname = uname;
philware 1:8ea78dce6b36 669 _pwd = pwd;
philware 1:8ea78dce6b36 670 }
philware 1:8ea78dce6b36 671
philware 1:8ea78dce6b36 672 // Set PIN.
philware 1:8ea78dce6b36 673 void UbloxATCellularInterfaceN2xx::set_sim_pin(const char *pin) {
philware 1:8ea78dce6b36 674 set_pin(pin);
philware 1:8ea78dce6b36 675 }
philware 1:8ea78dce6b36 676
philware 1:8ea78dce6b36 677 // Get the IP address of a host.
philware 1:8ea78dce6b36 678 nsapi_error_t UbloxATCellularInterfaceN2xx::gethostbyname(const char *host,
philware 1:8ea78dce6b36 679 SocketAddress *address,
philware 1:8ea78dce6b36 680 nsapi_version_t version)
philware 1:8ea78dce6b36 681 {
philware 1:8ea78dce6b36 682 nsapi_error_t nsapiError = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 683 tr_debug("GetHostByName: host= %s", host);
philware 1:8ea78dce6b36 684 if (address->set_ip_address(host)) {
philware 1:8ea78dce6b36 685 tr_debug("OK");
philware 1:8ea78dce6b36 686 nsapiError = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 687 } else {
philware 1:8ea78dce6b36 688 tr_debug("Failed");
philware 1:8ea78dce6b36 689 nsapiError = NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 690 }
philware 1:8ea78dce6b36 691
philware 1:8ea78dce6b36 692 return nsapiError;
philware 1:8ea78dce6b36 693 }
philware 1:8ea78dce6b36 694
philware 1:8ea78dce6b36 695 // Make a cellular connection
philware 1:8ea78dce6b36 696 nsapi_error_t UbloxATCellularInterfaceN2xx::connect(const char *sim_pin,
philware 1:8ea78dce6b36 697 const char *apn,
philware 1:8ea78dce6b36 698 const char *uname,
philware 1:8ea78dce6b36 699 const char *pwd)
philware 1:8ea78dce6b36 700 {
philware 1:8ea78dce6b36 701 nsapi_error_t nsapi_error;
philware 1:8ea78dce6b36 702
philware 1:8ea78dce6b36 703 if (sim_pin != NULL) {
philware 1:8ea78dce6b36 704 _pin = sim_pin;
philware 1:8ea78dce6b36 705 }
philware 1:8ea78dce6b36 706
philware 1:8ea78dce6b36 707 if (apn != NULL) {
philware 1:8ea78dce6b36 708 _apn = apn;
philware 1:8ea78dce6b36 709 }
philware 1:8ea78dce6b36 710
philware 1:8ea78dce6b36 711 if ((uname != NULL) && (pwd != NULL)) {
philware 1:8ea78dce6b36 712 _uname = uname;
philware 1:8ea78dce6b36 713 _pwd = pwd;
philware 1:8ea78dce6b36 714 } else {
philware 1:8ea78dce6b36 715 _uname = NULL;
philware 1:8ea78dce6b36 716 _pwd = NULL;
philware 1:8ea78dce6b36 717 }
philware 1:8ea78dce6b36 718
philware 1:8ea78dce6b36 719 tr_debug("SIM, APN, UName & pwd set, now calling connect()");
philware 1:8ea78dce6b36 720 nsapi_error = connect();
philware 1:8ea78dce6b36 721
philware 1:8ea78dce6b36 722 return nsapi_error;
philware 1:8ea78dce6b36 723 }
philware 1:8ea78dce6b36 724
philware 4:2bf3875a13f1 725 bool UbloxATCellularInterfaceN2xx::initialise()
philware 4:2bf3875a13f1 726 {
philware 4:2bf3875a13f1 727 return init();
philware 4:2bf3875a13f1 728 }
philware 4:2bf3875a13f1 729
philware 1:8ea78dce6b36 730 // Make a cellular connection using the IP stack on board the cellular modem
philware 1:8ea78dce6b36 731 nsapi_error_t UbloxATCellularInterfaceN2xx::connect()
philware 1:8ea78dce6b36 732 {
philware 1:8ea78dce6b36 733 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 734 bool registered = false;
philware 1:8ea78dce6b36 735
philware 1:8ea78dce6b36 736 // Set up modem and then register with the network
philware 4:2bf3875a13f1 737 if (initialise()) {
philware 1:8ea78dce6b36 738
philware 1:8ea78dce6b36 739 tr_debug("Trying to register...");
philware 1:8ea78dce6b36 740 nsapi_error = NSAPI_ERROR_NO_CONNECTION;
philware 1:8ea78dce6b36 741 for (int retries = 0; !registered && (retries < 3); retries++) {
philware 1:8ea78dce6b36 742 if (nwk_registration()) {
philware 1:8ea78dce6b36 743 registered = true;
philware 1:8ea78dce6b36 744 }
philware 1:8ea78dce6b36 745 }
philware 1:8ea78dce6b36 746 }
philware 1:8ea78dce6b36 747
philware 1:8ea78dce6b36 748 // Attempt to establish a connection
philware 1:8ea78dce6b36 749 if (registered) {
philware 1:8ea78dce6b36 750 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 751 } else {
philware 1:8ea78dce6b36 752 tr_debug("Failed to register.");
philware 1:8ea78dce6b36 753 }
philware 1:8ea78dce6b36 754
philware 1:8ea78dce6b36 755 return nsapi_error;
philware 1:8ea78dce6b36 756 }
philware 1:8ea78dce6b36 757
philware 1:8ea78dce6b36 758 // User initiated disconnect.
philware 1:8ea78dce6b36 759 nsapi_error_t UbloxATCellularInterfaceN2xx::disconnect()
philware 1:8ea78dce6b36 760 {
philware 1:8ea78dce6b36 761 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
philware 1:8ea78dce6b36 762
philware 1:8ea78dce6b36 763 if (nwk_deregistration()) {
philware 1:8ea78dce6b36 764 nsapi_error = NSAPI_ERROR_OK;
philware 1:8ea78dce6b36 765
philware 1:8ea78dce6b36 766 if (_connection_status_cb) {
philware 1:8ea78dce6b36 767 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
philware 1:8ea78dce6b36 768 }
philware 1:8ea78dce6b36 769 }
philware 1:8ea78dce6b36 770
philware 1:8ea78dce6b36 771 return nsapi_error;
philware 1:8ea78dce6b36 772 }
philware 1:8ea78dce6b36 773
philware 1:8ea78dce6b36 774 // Enable or disable SIM PIN check lock.
philware 1:8ea78dce6b36 775 nsapi_error_t UbloxATCellularInterfaceN2xx::set_sim_pin_check(bool set,
philware 1:8ea78dce6b36 776 bool immediate,
philware 1:8ea78dce6b36 777 const char *sim_pin)
philware 1:8ea78dce6b36 778 {
philware 1:8ea78dce6b36 779 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 780 }
philware 1:8ea78dce6b36 781
philware 1:8ea78dce6b36 782 // Change the PIN code for the SIM card.
philware 1:8ea78dce6b36 783 nsapi_error_t UbloxATCellularInterfaceN2xx::set_new_sim_pin(const char *new_pin,
philware 1:8ea78dce6b36 784 bool immediate,
philware 1:8ea78dce6b36 785 const char *old_pin)
philware 1:8ea78dce6b36 786 {
philware 1:8ea78dce6b36 787 return NSAPI_ERROR_UNSUPPORTED;
philware 1:8ea78dce6b36 788 }
philware 1:8ea78dce6b36 789
philware 1:8ea78dce6b36 790 // Determine if the connection is up.
philware 1:8ea78dce6b36 791 bool UbloxATCellularInterfaceN2xx::is_connected()
philware 1:8ea78dce6b36 792 {
philware 1:8ea78dce6b36 793 return get_ip_address() != NULL;
philware 1:8ea78dce6b36 794 }
philware 1:8ea78dce6b36 795
philware 1:8ea78dce6b36 796 // Get the IP address of the on-board modem IP stack.
philware 1:8ea78dce6b36 797 const char * UbloxATCellularInterfaceN2xx::get_ip_address()
philware 1:8ea78dce6b36 798 {
philware 1:8ea78dce6b36 799 SocketAddress address;
philware 1:8ea78dce6b36 800 int id;
philware 1:8ea78dce6b36 801 LOCK();
philware 1:8ea78dce6b36 802
philware 1:8ea78dce6b36 803 if (_ip == NULL)
philware 1:8ea78dce6b36 804 {
philware 1:8ea78dce6b36 805 // Temporary storage for an IP address string with terminator
philware 1:8ea78dce6b36 806 _ip = (char *) malloc(NSAPI_IP_SIZE);
philware 1:8ea78dce6b36 807 }
philware 1:8ea78dce6b36 808
philware 1:8ea78dce6b36 809 if (_ip != NULL) {
philware 1:8ea78dce6b36 810 memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator
philware 1:8ea78dce6b36 811 // +CGPADDR - returns a list of IP Addresses per context, just pick the first one as SARA-N2xx only allows 1 context.
philware 1:8ea78dce6b36 812 if (!_at->send("AT+CGPADDR") ||
philware 1:8ea78dce6b36 813 !_at->recv("+CGPADDR:%d,%15[^\n]\n", &id, _ip) ||
philware 1:8ea78dce6b36 814 ! _at->recv("OK") ||
philware 1:8ea78dce6b36 815 !address.set_ip_address(_ip) ||
philware 1:8ea78dce6b36 816 !address) {
philware 1:8ea78dce6b36 817 free (_ip);
philware 1:8ea78dce6b36 818 _ip = NULL;
philware 1:8ea78dce6b36 819 }
philware 1:8ea78dce6b36 820 }
philware 1:8ea78dce6b36 821
philware 1:8ea78dce6b36 822 UNLOCK();
philware 1:8ea78dce6b36 823 return _ip;
philware 1:8ea78dce6b36 824 }
philware 1:8ea78dce6b36 825
philware 1:8ea78dce6b36 826 // Get the local network mask.
philware 1:8ea78dce6b36 827 const char *UbloxATCellularInterfaceN2xx::get_netmask()
philware 1:8ea78dce6b36 828 {
philware 1:8ea78dce6b36 829 // Not implemented.
philware 1:8ea78dce6b36 830 return NULL;
philware 1:8ea78dce6b36 831 }
philware 1:8ea78dce6b36 832
philware 1:8ea78dce6b36 833 // Get the local gateways.
philware 1:8ea78dce6b36 834 const char *UbloxATCellularInterfaceN2xx::get_gateway()
philware 1:8ea78dce6b36 835 {
philware 1:8ea78dce6b36 836 return get_ip_address();
philware 1:8ea78dce6b36 837 }
philware 1:8ea78dce6b36 838
philware 1:8ea78dce6b36 839 void UbloxATCellularInterfaceN2xx::set_LocalListenPort(int port) {
philware 1:8ea78dce6b36 840 _localListenPort = port;
philware 1:8ea78dce6b36 841 }
philware 1:8ea78dce6b36 842
philware 1:8ea78dce6b36 843 // Callback in case the connection is lost.
philware 1:8ea78dce6b36 844 void UbloxATCellularInterfaceN2xx::connection_status_cb(Callback<void(nsapi_error_t)> cb)
philware 1:8ea78dce6b36 845 {
philware 1:8ea78dce6b36 846 _connection_status_cb = cb;
philware 1:8ea78dce6b36 847 }
philware 1:8ea78dce6b36 848
philware 1:8ea78dce6b36 849 // End of file
philware 1:8ea78dce6b36 850