Example program that uses the mbed UbloxATCellularInterface or OnboardCellularInterface classes to perform simple sockets operations. This program can be used on the C027 and C030 boards, including the C030 N2xx version with a little editing.

Dependencies:   ublox-at-cellular-interface ublox-cellular-base ublox-cellular-base-n2xx ublox-at-cellular-interface-n2xx

Committer:
fahim.alavi@u-blox.com
Date:
Wed Feb 13 10:55:51 2019 +0500
Revision:
36:f24c264ad2cd
Parent:
35:8e65f2bee044
Child:
37:98338956aaba
Update cellular library N2XX

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rob.meades@u-blox.com 1:581335dbdd60 1 /* mbed Microcontroller Library
rob.meades@u-blox.com 1:581335dbdd60 2 * Copyright (c) 2017 u-blox
rob.meades@u-blox.com 1:581335dbdd60 3 *
rob.meades@u-blox.com 1:581335dbdd60 4 * Licensed under the Apache License, Version 2.0 (the "License");
rob.meades@u-blox.com 1:581335dbdd60 5 * you may not use this file except in compliance with the License.
rob.meades@u-blox.com 1:581335dbdd60 6 * You may obtain a copy of the License at
rob.meades@u-blox.com 1:581335dbdd60 7 *
rob.meades@u-blox.com 1:581335dbdd60 8 * http://www.apache.org/licenses/LICENSE-2.0
rob.meades@u-blox.com 1:581335dbdd60 9 *
rob.meades@u-blox.com 1:581335dbdd60 10 * Unless required by applicable law or agreed to in writing, software
rob.meades@u-blox.com 1:581335dbdd60 11 * distributed under the License is distributed on an "AS IS" BASIS,
rob.meades@u-blox.com 1:581335dbdd60 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rob.meades@u-blox.com 1:581335dbdd60 13 * See the License for the specific language governing permissions and
rob.meades@u-blox.com 1:581335dbdd60 14 * limitations under the License.
rob.meades@u-blox.com 1:581335dbdd60 15 */
rob.meades@u-blox.com 1:581335dbdd60 16 #include "mbed.h"
rob.meades@u-blox.com 1:581335dbdd60 17 #include "UbloxATCellularInterface.h"
RobMeades 33:48101a4c3f14 18 #include "OnboardCellularInterface.h"
rob.meades@u-blox.com 28:e33af9f1ce3e 19 #include "UbloxATCellularInterfaceN2xx.h"
RobMeades 8:3e170c40a284 20
rob.meades@u-blox.com 31:4a36566b5385 21 // You must select the correct interface library for your board, by
rob.meades@u-blox.com 31:4a36566b5385 22 // uncommenting the correct line below. Supported combinations are
rob.meades@u-blox.com 31:4a36566b5385 23 // indicated with a "Y" in the table below.
rob.meades@u-blox.com 28:e33af9f1ce3e 24 //
rob.meades@u-blox.com 28:e33af9f1ce3e 25 // C030_U201 C030_N211 C027
rob.meades@u-blox.com 28:e33af9f1ce3e 26 // UbloxATCellularInterface Y - Y
RobMeades 33:48101a4c3f14 27 // OnboardCellularInterface Y - Y
rob.meades@u-blox.com 28:e33af9f1ce3e 28 // UbloxATCellularInterfaceN2xx - Y -
rob.meades@u-blox.com 28:e33af9f1ce3e 29 // Note: the N211 module supports only UDP, not TCP
rob.meades@u-blox.com 28:e33af9f1ce3e 30
RobMeades 33:48101a4c3f14 31 // OnboardCellularInterface uses LWIP and the PPP cellular interface
rob.meades@u-blox.com 28:e33af9f1ce3e 32 // on the mbed MCU, while using UbloxATCellularInterface and
rob.meades@u-blox.com 28:e33af9f1ce3e 33 // UbloxATCellularInterfaceN2xx uses an IP stack on the cellular
rob.meades@u-blox.com 28:e33af9f1ce3e 34 // module and hence uses less RAM (significant on C027). This also
RobMeades 8:3e170c40a284 35 // allows other AT command operations (e.g. sending an SMS) to happen
rob.meades@u-blox.com 28:e33af9f1ce3e 36 // during a data transfer (for which you should replace the
rob.meades@u-blox.com 28:e33af9f1ce3e 37 // UbloxATCellularInterface library with the UbloxATCellularInterfaceExt
rob.meades@u-blox.com 28:e33af9f1ce3e 38 // library). However, it is slower than using the LWIP/PPP on the mbed
rob.meades@u-blox.com 28:e33af9f1ce3e 39 // MCU interface since more string parsing is required.
RobMeades 8:3e170c40a284 40 #define INTERFACE_CLASS UbloxATCellularInterface
RobMeades 33:48101a4c3f14 41 //#define INTERFACE_CLASS OnboardCellularInterface
rob.meades@u-blox.com 28:e33af9f1ce3e 42 //#define INTERFACE_CLASS UbloxATCellularInterfaceN2xx
rob.meades@u-blox.com 1:581335dbdd60 43
rob.meades@u-blox.com 1:581335dbdd60 44 // The credentials of the SIM in the board. If PIN checking is enabled
rob.meades@u-blox.com 1:581335dbdd60 45 // for your SIM card you must set this to the required PIN.
rob.meades@u-blox.com 1:581335dbdd60 46 #define PIN "0000"
rob.meades@u-blox.com 1:581335dbdd60 47
rob.meades@u-blox.com 1:581335dbdd60 48 // Network credentials. You should set this according to your
rob.meades@u-blox.com 30:4e55e975dd0b 49 // network/SIM card. For C030 non-N2xx boards, leave the parameters as NULL
rob.meades@u-blox.com 1:581335dbdd60 50 // otherwise, if you do not know the APN for your network, you may
rob.meades@u-blox.com 1:581335dbdd60 51 // either try the fairly common "internet" for the APN (and leave the
rob.meades@u-blox.com 1:581335dbdd60 52 // username and password NULL), or you may leave all three as NULL and then
rob.meades@u-blox.com 1:581335dbdd60 53 // a lookup will be attempted for a small number of known networks
rob.meades@u-blox.com 1:581335dbdd60 54 // (see APN_db.h in mbed-os/features/netsocket/cellular/utils).
rob.meades@u-blox.com 1:581335dbdd60 55 #define APN NULL
rob.meades@u-blox.com 1:581335dbdd60 56 #define USERNAME NULL
rob.meades@u-blox.com 1:581335dbdd60 57 #define PASSWORD NULL
fahim.alavi@u-blox.com 35:8e65f2bee044 58 #define TCP_SERVER "os.mbed.com"
rob.meades@u-blox.com 1:581335dbdd60 59
rob.meades@u-blox.com 1:581335dbdd60 60 // LEDs
rob.meades@u-blox.com 1:581335dbdd60 61 DigitalOut ledRed(LED1, 1);
rob.meades@u-blox.com 1:581335dbdd60 62 DigitalOut ledGreen(LED2, 1);
rob.meades@u-blox.com 1:581335dbdd60 63 DigitalOut ledBlue(LED3, 1);
rob.meades@u-blox.com 1:581335dbdd60 64
rob.meades@u-blox.com 1:581335dbdd60 65 // The user button
rob.meades@u-blox.com 1:581335dbdd60 66 volatile bool buttonPressed = false;
rob.meades@u-blox.com 1:581335dbdd60 67
rob.meades@u-blox.com 1:581335dbdd60 68 static void good() {
rob.meades@u-blox.com 1:581335dbdd60 69 ledGreen = 0;
rob.meades@u-blox.com 1:581335dbdd60 70 ledBlue = 1;
rob.meades@u-blox.com 1:581335dbdd60 71 ledRed = 1;
rob.meades@u-blox.com 1:581335dbdd60 72 }
rob.meades@u-blox.com 1:581335dbdd60 73
rob.meades@u-blox.com 1:581335dbdd60 74 static void bad() {
rob.meades@u-blox.com 1:581335dbdd60 75 ledRed = 0;
rob.meades@u-blox.com 1:581335dbdd60 76 ledGreen = 1;
rob.meades@u-blox.com 1:581335dbdd60 77 ledBlue = 1;
rob.meades@u-blox.com 1:581335dbdd60 78 }
rob.meades@u-blox.com 1:581335dbdd60 79
rob.meades@u-blox.com 1:581335dbdd60 80 static void event() {
rob.meades@u-blox.com 1:581335dbdd60 81 ledBlue = 0;
rob.meades@u-blox.com 1:581335dbdd60 82 ledRed = 1;
rob.meades@u-blox.com 1:581335dbdd60 83 ledGreen = 1;
rob.meades@u-blox.com 1:581335dbdd60 84 }
rob.meades@u-blox.com 1:581335dbdd60 85
rob.meades@u-blox.com 1:581335dbdd60 86 static void pulseEvent() {
rob.meades@u-blox.com 1:581335dbdd60 87 event();
rob.meades@u-blox.com 1:581335dbdd60 88 wait_ms(500);
rob.meades@u-blox.com 1:581335dbdd60 89 good();
rob.meades@u-blox.com 1:581335dbdd60 90 }
rob.meades@u-blox.com 1:581335dbdd60 91
rob.meades@u-blox.com 1:581335dbdd60 92 static void ledOff() {
rob.meades@u-blox.com 1:581335dbdd60 93 ledBlue = 1;
rob.meades@u-blox.com 1:581335dbdd60 94 ledRed = 1;
rob.meades@u-blox.com 1:581335dbdd60 95 ledGreen = 1;
rob.meades@u-blox.com 1:581335dbdd60 96 }
rob.meades@u-blox.com 1:581335dbdd60 97
rob.meades@u-blox.com 1:581335dbdd60 98 static void printNtpTime(char * buf, int len)
rob.meades@u-blox.com 1:581335dbdd60 99 {
rob.meades@u-blox.com 1:581335dbdd60 100 time_t timestamp = 0;
rob.meades@u-blox.com 1:581335dbdd60 101 struct tm *localTime;
rob.meades@u-blox.com 1:581335dbdd60 102 char timeString[25];
rob.meades@u-blox.com 1:581335dbdd60 103 time_t TIME1970 = 2208988800U;
rob.meades@u-blox.com 1:581335dbdd60 104
rob.meades@u-blox.com 1:581335dbdd60 105 if (len >= 43) {
rob.meades@u-blox.com 1:581335dbdd60 106 timestamp |= ((int) *(buf + 40)) << 24;
rob.meades@u-blox.com 1:581335dbdd60 107 timestamp |= ((int) *(buf + 41)) << 16;
rob.meades@u-blox.com 1:581335dbdd60 108 timestamp |= ((int) *(buf + 42)) << 8;
rob.meades@u-blox.com 1:581335dbdd60 109 timestamp |= ((int) *(buf + 43));
rob.meades@u-blox.com 1:581335dbdd60 110 timestamp -= TIME1970;
rob.meades@u-blox.com 1:581335dbdd60 111 localTime = localtime(&timestamp);
rob.meades@u-blox.com 1:581335dbdd60 112 if (localTime) {
rob.meades@u-blox.com 1:581335dbdd60 113 if (strftime(timeString, sizeof(timeString), "%a %b %d %H:%M:%S %Y", localTime) > 0) {
rob.meades@u-blox.com 1:581335dbdd60 114 printf("NTP timestamp is %s.\n", timeString);
rob.meades@u-blox.com 1:581335dbdd60 115 }
rob.meades@u-blox.com 1:581335dbdd60 116 }
rob.meades@u-blox.com 1:581335dbdd60 117 }
rob.meades@u-blox.com 1:581335dbdd60 118 }
rob.meades@u-blox.com 1:581335dbdd60 119
rob.meades@u-blox.com 1:581335dbdd60 120 static void cbButton()
rob.meades@u-blox.com 1:581335dbdd60 121 {
rob.meades@u-blox.com 1:581335dbdd60 122 buttonPressed = true;
rob.meades@u-blox.com 1:581335dbdd60 123 pulseEvent();
rob.meades@u-blox.com 1:581335dbdd60 124 }
rob.meades@u-blox.com 1:581335dbdd60 125
rob.meades@u-blox.com 1:581335dbdd60 126 /* This example program for the u-blox C030 and C027 boards instantiates
RobMeades 33:48101a4c3f14 127 * the UbloxATCellularInterface or OnboardCellularInterface and uses it
rob.meades@u-blox.com 30:4e55e975dd0b 128 * to make a simple sockets connection to a server, using 2.pool.ntp.org
rob.meades@u-blox.com 13:d31b8735cca8 129 * for UDP and developer.mbed.org for TCP. For a more comprehensive example,
rob.meades@u-blox.com 13:d31b8735cca8 130 * where higher layer protocols make use of the same sockets interface,
rob.meades@u-blox.com 13:d31b8735cca8 131 * see example-ublox-mbed-client.
rob.meades@u-blox.com 1:581335dbdd60 132 * Progress may be monitored with a serial terminal running at 9600 baud.
rob.meades@u-blox.com 1:581335dbdd60 133 * The LED on the C030 board will turn green when this program is
rob.meades@u-blox.com 1:581335dbdd60 134 * operating correctly, pulse blue when a sockets operation is completed
rob.meades@u-blox.com 1:581335dbdd60 135 * and turn red if there is a failure.
rob.meades@u-blox.com 1:581335dbdd60 136 */
rob.meades@u-blox.com 1:581335dbdd60 137
rob.meades@u-blox.com 1:581335dbdd60 138 int main()
rob.meades@u-blox.com 1:581335dbdd60 139 {
RobMeades 10:1f35371d572d 140 INTERFACE_CLASS *interface = new INTERFACE_CLASS();
RobMeades 5:bf352de1d3e5 141 // If you need to debug the cellular interface, comment out the
RobMeades 5:bf352de1d3e5 142 // instantiation above and uncomment the one below.
rob.meades@u-blox.com 31:4a36566b5385 143 // For the N2xx interface, change xxx to MBED_CONF_UBLOX_CELL_BAUD_RATE,
rob.meades@u-blox.com 31:4a36566b5385 144 // while for the non-N2xx interface change it to MBED_CONF_UBLOX_CELL_N2XX_BAUD_RATE.
RobMeades 8:3e170c40a284 145 // INTERFACE_CLASS *interface = new INTERFACE_CLASS(MDMTXD, MDMRXD,
rob.meades@u-blox.com 31:4a36566b5385 146 // xxx,
RobMeades 8:3e170c40a284 147 // true);
rob.meades@u-blox.com 28:e33af9f1ce3e 148 #ifndef TARGET_UBLOX_C030_N211
rob.meades@u-blox.com 1:581335dbdd60 149 TCPSocket sockTcp;
rob.meades@u-blox.com 28:e33af9f1ce3e 150 #endif
rob.meades@u-blox.com 1:581335dbdd60 151 UDPSocket sockUdp;
rob.meades@u-blox.com 1:581335dbdd60 152 SocketAddress udpServer;
rob.meades@u-blox.com 1:581335dbdd60 153 SocketAddress udpSenderAddress;
rob.meades@u-blox.com 1:581335dbdd60 154 SocketAddress tcpServer;
rob.meades@u-blox.com 1:581335dbdd60 155 char buf[1024];
rob.meades@u-blox.com 1:581335dbdd60 156 int x;
RobMeades 4:3e2b789c3adc 157 #ifdef TARGET_UBLOX_C027
RobMeades 4:3e2b789c3adc 158 // No user button on C027
RobMeades 4:3e2b789c3adc 159 InterruptIn userButton(NC);
RobMeades 4:3e2b789c3adc 160 #else
rob.meades@u-blox.com 1:581335dbdd60 161 InterruptIn userButton(SW0);
RobMeades 4:3e2b789c3adc 162 #endif
rob.meades@u-blox.com 1:581335dbdd60 163
rob.meades@u-blox.com 1:581335dbdd60 164 // Attach a function to the user button
rob.meades@u-blox.com 1:581335dbdd60 165 userButton.rise(&cbButton);
rob.meades@u-blox.com 1:581335dbdd60 166
rob.meades@u-blox.com 1:581335dbdd60 167 good();
rob.meades@u-blox.com 1:581335dbdd60 168 printf("Starting up, please wait up to 180 seconds for network registration to complete...\n");
RobMeades 33:48101a4c3f14 169 interface->set_credentials(APN, USERNAME, PASSWORD);
RobMeades 33:48101a4c3f14 170 for (x = 0; interface->connect(PIN) != 0; x++) {
RobMeades 33:48101a4c3f14 171 if (x > 0) {
RobMeades 33:48101a4c3f14 172 bad();
RobMeades 33:48101a4c3f14 173 printf("Retrying (have you checked that an antenna is plugged in and your APN is correct?)...\n");
RobMeades 33:48101a4c3f14 174 }
RobMeades 33:48101a4c3f14 175 }
RobMeades 33:48101a4c3f14 176 pulseEvent();
RobMeades 33:48101a4c3f14 177
RobMeades 33:48101a4c3f14 178 printf("Getting the IP address of \"developer.mbed.org\" and \"2.pool.ntp.org\"...\n");
RobMeades 33:48101a4c3f14 179 if ((interface->gethostbyname("2.pool.ntp.org", &udpServer) == 0) &&
fahim.alavi@u-blox.com 35:8e65f2bee044 180 (interface->gethostbyname(TCP_SERVER, &tcpServer) == 0)) {
rob.meades@u-blox.com 1:581335dbdd60 181 pulseEvent();
RobMeades 33:48101a4c3f14 182
RobMeades 33:48101a4c3f14 183 udpServer.set_port(123);
fahim.alavi@u-blox.com 35:8e65f2bee044 184 tcpServer.set_port(80);
RobMeades 33:48101a4c3f14 185 printf("\"2.pool.ntp.org\" address: %s on port %d.\n", udpServer.get_ip_address(), udpServer.get_port());
fahim.alavi@u-blox.com 35:8e65f2bee044 186 printf("\"os.mbed.com\" address: %s on port %d.\n", tcpServer.get_ip_address(), tcpServer.get_port());
rob.meades@u-blox.com 28:e33af9f1ce3e 187
RobMeades 33:48101a4c3f14 188 printf("Performing socket operations in a loop (until the user button is pressed on C030 or forever on C027)...\n");
RobMeades 33:48101a4c3f14 189 while (!buttonPressed) {
RobMeades 33:48101a4c3f14 190 // UDP Sockets
RobMeades 33:48101a4c3f14 191 printf("=== UDP ===\n");
RobMeades 33:48101a4c3f14 192 printf("Opening a UDP socket...\n");
RobMeades 33:48101a4c3f14 193 if (sockUdp.open(interface) == 0) {
RobMeades 33:48101a4c3f14 194 pulseEvent();
RobMeades 33:48101a4c3f14 195 printf("UDP socket open.\n");
RobMeades 33:48101a4c3f14 196 sockUdp.set_timeout(10000);
RobMeades 33:48101a4c3f14 197 printf("Sending time request to \"2.pool.ntp.org\" over UDP socket...\n");
RobMeades 33:48101a4c3f14 198 memset (buf, 0, sizeof(buf));
RobMeades 33:48101a4c3f14 199 *buf = '\x1b';
RobMeades 33:48101a4c3f14 200 if (sockUdp.sendto(udpServer, (void *) buf, 48) == 48) {
rob.meades@u-blox.com 1:581335dbdd60 201 pulseEvent();
RobMeades 33:48101a4c3f14 202 printf("Socket send completed, waiting for UDP response...\n");
RobMeades 33:48101a4c3f14 203 x = sockUdp.recvfrom(&udpSenderAddress, buf, sizeof (buf));
RobMeades 33:48101a4c3f14 204 if (x > 0) {
rob.meades@u-blox.com 1:581335dbdd60 205 pulseEvent();
RobMeades 33:48101a4c3f14 206 printf("Received %d byte response from server %s on UDP socket:\n"
RobMeades 33:48101a4c3f14 207 "-------------------------------------------------------\n",
RobMeades 33:48101a4c3f14 208 x, udpSenderAddress.get_ip_address());
RobMeades 33:48101a4c3f14 209 printNtpTime(buf, x);
RobMeades 33:48101a4c3f14 210 printf("-------------------------------------------------------\n");
RobMeades 33:48101a4c3f14 211 }
RobMeades 33:48101a4c3f14 212 }
RobMeades 33:48101a4c3f14 213 printf("Closing socket...\n");
RobMeades 33:48101a4c3f14 214 sockUdp.close();
RobMeades 33:48101a4c3f14 215 pulseEvent();
RobMeades 33:48101a4c3f14 216 printf("Socket closed.\n");
RobMeades 33:48101a4c3f14 217 }
RobMeades 33:48101a4c3f14 218
RobMeades 33:48101a4c3f14 219 #ifndef TARGET_UBLOX_C030_N211
RobMeades 33:48101a4c3f14 220 // TCP Sockets
RobMeades 33:48101a4c3f14 221 printf("=== TCP ===\n");
RobMeades 33:48101a4c3f14 222 printf("Opening a TCP socket...\n");
RobMeades 33:48101a4c3f14 223 if (sockTcp.open(interface) == 0) {
RobMeades 33:48101a4c3f14 224 pulseEvent();
RobMeades 33:48101a4c3f14 225 printf("TCP socket open.\n");
RobMeades 33:48101a4c3f14 226 sockTcp.set_timeout(10000);
RobMeades 33:48101a4c3f14 227 printf("Connecting socket to %s on port %d...\n", tcpServer.get_ip_address(), tcpServer.get_port());
RobMeades 33:48101a4c3f14 228 if (sockTcp.connect(tcpServer) == 0) {
RobMeades 33:48101a4c3f14 229 pulseEvent();
fahim.alavi@u-blox.com 35:8e65f2bee044 230 printf("Connected, sending HTTP GET request to %s over socket...\n", TCP_SERVER);
RobMeades 33:48101a4c3f14 231 strcpy (buf, "GET /media/uploads/mbed_official/hello.txt HTTP/1.0\r\n\r\n");
RobMeades 33:48101a4c3f14 232 // Note: since this is a short string we can send it in one go as it will
RobMeades 33:48101a4c3f14 233 // fit within the default buffer sizes. Normally you should call sock.send()
RobMeades 33:48101a4c3f14 234 // in a loop until your entire buffer has been sent.
RobMeades 33:48101a4c3f14 235 if (sockTcp.send((void *) buf, strlen(buf)) == (int) strlen(buf)) {
RobMeades 33:48101a4c3f14 236 pulseEvent();
RobMeades 33:48101a4c3f14 237 printf("Socket send completed, waiting for response...\n");
RobMeades 33:48101a4c3f14 238 x = sockTcp.recv(buf, sizeof (buf));
rob.meades@u-blox.com 1:581335dbdd60 239 if (x > 0) {
rob.meades@u-blox.com 1:581335dbdd60 240 pulseEvent();
RobMeades 33:48101a4c3f14 241 printf("Received %d byte response from server on TCP socket:\n"
RobMeades 33:48101a4c3f14 242 "----------------------------------------------------\n%.*s"
RobMeades 33:48101a4c3f14 243 "----------------------------------------------------\n",
RobMeades 33:48101a4c3f14 244 x, x, buf);
rob.meades@u-blox.com 1:581335dbdd60 245 }
rob.meades@u-blox.com 1:581335dbdd60 246 }
rob.meades@u-blox.com 1:581335dbdd60 247 }
RobMeades 33:48101a4c3f14 248 printf("Closing socket...\n");
RobMeades 33:48101a4c3f14 249 sockTcp.close();
RobMeades 33:48101a4c3f14 250 pulseEvent();
RobMeades 33:48101a4c3f14 251 printf("Socket closed.\n");
rob.meades@u-blox.com 1:581335dbdd60 252 }
RobMeades 33:48101a4c3f14 253 #endif
RobMeades 33:48101a4c3f14 254 wait_ms(5000);
RobMeades 33:48101a4c3f14 255 #ifndef TARGET_UBLOX_C027
RobMeades 33:48101a4c3f14 256 printf("[Checking if user button has been pressed]\n");
RobMeades 33:48101a4c3f14 257 #endif
rob.meades@u-blox.com 1:581335dbdd60 258 }
RobMeades 33:48101a4c3f14 259
RobMeades 33:48101a4c3f14 260 pulseEvent();
RobMeades 33:48101a4c3f14 261 printf("User button was pressed, stopping...\n");
RobMeades 33:48101a4c3f14 262 interface->disconnect();
RobMeades 33:48101a4c3f14 263 ledOff();
RobMeades 33:48101a4c3f14 264 printf("Stopped.\n");
rob.meades@u-blox.com 1:581335dbdd60 265 } else {
rob.meades@u-blox.com 1:581335dbdd60 266 bad();
RobMeades 33:48101a4c3f14 267 printf("Unable to get IP address of \"developer.mbed.org\" or \"2.pool.ntp.org\".\n");
rob.meades@u-blox.com 1:581335dbdd60 268 }
rob.meades@u-blox.com 1:581335dbdd60 269 }
RobMeades 32:bdc45c7052cc 270 // End Of File