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:
Mon Jun 26 13:49:08 2017 +0100
Revision:
1:8ea78dce6b36
Child:
4:2bf3875a13f1
UDP Sockets over AT for SARA-N2xx modules

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