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:
rob.meades@u-blox.com
Date:
Thu Sep 14 11:00:41 2017 +0100
Revision:
8:0162c103346a
Parent:
7:69e676f4af84
Child:
10:08c5a69437ac
uint becomes uint32_t (ARM tools do not have uint).

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