Retry

Fork of ublox-at-cellular-interface by u-blox

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "UbloxATCellularInterface.h"
00002 #include "greentea-client/test_env.h"
00003 #include "unity.h"
00004 #include "utest.h"
00005 #include "UDPSocket.h"
00006 #ifdef FEATURE_COMMON_PAL
00007 #include "mbed_trace.h"
00008 #define TRACE_GROUP "TEST"
00009 #else
00010 #define tr_debug(format, ...) debug(format "\n", ## __VA_ARGS__)
00011 #define tr_info(format, ...)  debug(format "\n", ## __VA_ARGS__)
00012 #define tr_warn(format, ...)  debug(format "\n", ## __VA_ARGS__)
00013 #define tr_error(format, ...) debug(format "\n", ## __VA_ARGS__)
00014 #endif
00015 
00016 using namespace utest::v1;
00017 
00018 // IMPORTANT!!! if you make a change to the tests here you should
00019 // check whether the same change should be made to the tests under
00020 // the PPP interface.
00021 
00022 // NOTE: these test are only as reliable as UDP across the internet
00023 // over a radio link.  The tests expect an NTP server to respond
00024 // to UDP packets and, if configured, an echo server to respond
00025 // to UDP packets.  This simply may not happen.  Please be patient.
00026 
00027 // ----------------------------------------------------------------
00028 // COMPILE-TIME MACROS
00029 // ----------------------------------------------------------------
00030 
00031 // These macros can be overridden with an mbed_app.json file and
00032 // contents of the following form:
00033 //
00034 //{
00035 //    "config": {
00036 //        "default-pin": {
00037 //            "value": "\"1234\""
00038 //        }
00039 //}
00040 //
00041 // See the template_mbed_app.txt in this directory for a fuller example.
00042 
00043 // Whether debug trace is on
00044 #ifndef MBED_CONF_APP_DEBUG_ON
00045 # define MBED_CONF_APP_DEBUG_ON false
00046 #endif
00047 
00048 // Run the SIM change tests, which require the DEFAULT_PIN
00049 // above to be correct for the board on which the test
00050 // is being run (and the SIM PIN to be disabled before tests run).
00051 #ifndef MBED_CONF_APP_RUN_SIM_PIN_CHANGE_TESTS
00052 # define MBED_CONF_APP_RUN_SIM_PIN_CHANGE_TESTS 0
00053 #endif
00054 
00055 #if MBED_CONF_APP_RUN_SIM_PIN_CHANGE_TESTS
00056 # ifndef MBED_CONF_APP_DEFAULT_PIN
00057 #   error "MBED_CONF_APP_DEFAULT_PIN must be defined to run the SIM tests"
00058 # endif
00059 # ifndef MBED_CONF_APP_ALT_PIN
00060 #   error "MBED_CONF_APP_ALT_PIN must be defined to run the SIM tests"
00061 # endif
00062 # ifndef MBED_CONF_APP_INCORRECT_PIN
00063 #   error "MBED_CONF_APP_INCORRECT_PIN must be defined to run the SIM tests"
00064 # endif
00065 #endif
00066 
00067 // The credentials of the SIM in the board.
00068 #ifndef MBED_CONF_APP_DEFAULT_PIN
00069 // Note: if PIN is enabled on your SIM, or you wish to run the SIM PIN change
00070 // tests, you must define the PIN for your SIM (see note above on using
00071 // mbed_app.json to do so).
00072 # define MBED_CONF_APP_DEFAULT_PIN "0000"
00073 #endif
00074 #ifndef MBED_CONF_APP_APN
00075 # define MBED_CONF_APP_APN         NULL
00076 #endif
00077 #ifndef MBED_CONF_APP_USERNAME
00078 # define MBED_CONF_APP_USERNAME    NULL
00079 #endif
00080 #ifndef MBED_CONF_APP_PASSWORD
00081 # define MBED_CONF_APP_PASSWORD    NULL
00082 #endif
00083 
00084 // Alternate PIN to use during pin change testing
00085 #ifndef MBED_CONF_APP_ALT_PIN
00086 # define MBED_CONF_APP_ALT_PIN    "9876"
00087 #endif
00088 
00089 // A PIN that is definitely incorrect
00090 #ifndef MBED_CONF_APP_INCORRECT_PIN
00091 # define MBED_CONF_APP_INCORRECT_PIN "1530"
00092 #endif
00093 
00094 // Servers and ports
00095 #ifdef MBED_CONF_APP_ECHO_SERVER
00096 # ifndef MBED_CONF_APP_ECHO_UDP_PORT
00097 #  error "MBED_CONF_APP_ECHO_UDP_PORT (the port on which your echo server echoes UDP packets) must be defined"
00098 # endif
00099 # ifndef MBED_CONF_APP_ECHO_TCP_PORT
00100 #  error "MBED_CONF_APP_ECHO_TCP_PORT (the port on which your echo server echoes TCP packets) must be defined"
00101 # endif
00102 #endif
00103 
00104 #ifndef MBED_CONF_APP_NTP_SERVER
00105 # define MBED_CONF_APP_NTP_SERVER "2.pool.ntp.org"
00106 #else
00107 # ifndef MBED_CONF_APP_NTP_PORT
00108 #  error "MBED_CONF_APP_NTP_PORT must be defined if MBED_CONF_APP_NTP_SERVER is defined"
00109 # endif
00110 #endif
00111 #ifndef MBED_CONF_APP_NTP_PORT
00112 # define MBED_CONF_APP_NTP_PORT 123
00113 #endif
00114 
00115 #ifndef MBED_CONF_APP_LOCAL_PORT
00116 # define MBED_CONF_APP_LOCAL_PORT 15
00117 #endif
00118 
00119 // UDP packet size limit for testing
00120 #ifndef MBED_CONF_APP_UDP_MAX_PACKET_SIZE
00121 #  define MBED_CONF_APP_UDP_MAX_PACKET_SIZE 1024
00122 #endif
00123 
00124 // The maximum size of UDP data fragmented across
00125 // multiple packets
00126 #ifndef MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE
00127 # define MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE 1500
00128 #endif
00129 
00130 // TCP packet size limit for testing
00131 #ifndef MBED_CONF_APP_MBED_CONF_APP_TCP_MAX_PACKET_SIZE
00132 # define MBED_CONF_APP_TCP_MAX_PACKET_SIZE 1500
00133 #endif
00134 
00135 // The number of retries for UDP exchanges
00136 #define NUM_UDP_RETRIES 5
00137 
00138 // How long to wait for stuff to travel in the async echo tests
00139 #define ASYNC_TEST_WAIT_TIME 10000
00140 
00141 // The maximum number of sockets that can be open at one time
00142 #define MAX_NUM_SOCKETS 7
00143 
00144 // ----------------------------------------------------------------
00145 // PRIVATE VARIABLES
00146 // ----------------------------------------------------------------
00147 
00148 #ifdef FEATURE_COMMON_PAL
00149 // Lock for debug prints
00150 static Mutex mtx;
00151 #endif
00152 
00153 // An instance of the cellular interface
00154 static UbloxATCellularInterface *interface =
00155        new UbloxATCellularInterface(MDMTXD, MDMRXD,
00156                                     MBED_CONF_UBLOX_CELL_BAUD_RATE,
00157                                     MBED_CONF_APP_DEBUG_ON);
00158 
00159 // Connection flag
00160 static bool connection_has_gone_down = false;
00161 
00162 // Data to exchange
00163 static const char send_data[] =  "_____0000:0123456789012345678901234567890123456789"
00164                                  "01234567890123456789012345678901234567890123456789"
00165                                  "_____0100:0123456789012345678901234567890123456789"
00166                                  "01234567890123456789012345678901234567890123456789"
00167                                  "_____0200:0123456789012345678901234567890123456789"
00168                                  "01234567890123456789012345678901234567890123456789"
00169                                  "_____0300:0123456789012345678901234567890123456789"
00170                                  "01234567890123456789012345678901234567890123456789"
00171                                  "_____0400:0123456789012345678901234567890123456789"
00172                                  "01234567890123456789012345678901234567890123456789"
00173                                  "_____0500:0123456789012345678901234567890123456789"
00174                                  "01234567890123456789012345678901234567890123456789"
00175                                  "_____0600:0123456789012345678901234567890123456789"
00176                                  "01234567890123456789012345678901234567890123456789"
00177                                  "_____0700:0123456789012345678901234567890123456789"
00178                                  "01234567890123456789012345678901234567890123456789"
00179                                  "_____0800:0123456789012345678901234567890123456789"
00180                                  "01234567890123456789012345678901234567890123456789"
00181                                  "_____0900:0123456789012345678901234567890123456789"
00182                                  "01234567890123456789012345678901234567890123456789"
00183                                  "_____1000:0123456789012345678901234567890123456789"
00184                                  "01234567890123456789012345678901234567890123456789"
00185                                  "_____1100:0123456789012345678901234567890123456789"
00186                                  "01234567890123456789012345678901234567890123456789"
00187                                  "_____1200:0123456789012345678901234567890123456789"
00188                                  "01234567890123456789012345678901234567890123456789"
00189                                  "_____1300:0123456789012345678901234567890123456789"
00190                                  "01234567890123456789012345678901234567890123456789"
00191                                  "_____1400:0123456789012345678901234567890123456789"
00192                                  "01234567890123456789012345678901234567890123456789"
00193                                  "_____1500:0123456789012345678901234567890123456789"
00194                                  "01234567890123456789012345678901234567890123456789"
00195                                  "_____1600:0123456789012345678901234567890123456789"
00196                                  "01234567890123456789012345678901234567890123456789"
00197                                  "_____1700:0123456789012345678901234567890123456789"
00198                                  "01234567890123456789012345678901234567890123456789"
00199                                  "_____1800:0123456789012345678901234567890123456789"
00200                                  "01234567890123456789012345678901234567890123456789"
00201                                  "_____1900:0123456789012345678901234567890123456789"
00202                                  "01234567890123456789012345678901234567890123456789"
00203                                  "_____2000:0123456789012345678901234567890123456789"
00204                                  "01234567890123456789012345678901234567890123456789";
00205 
00206 // ----------------------------------------------------------------
00207 // PRIVATE FUNCTIONS
00208 // ----------------------------------------------------------------
00209 
00210 #ifdef FEATURE_COMMON_PAL
00211 // Locks for debug prints
00212 static void lock()
00213 {
00214     mtx.lock();
00215 }
00216 
00217 static void unlock()
00218 {
00219     mtx.unlock();
00220 }
00221 #endif
00222 
00223 // Callback in case the connection goes down
00224 static void connection_down_cb(nsapi_error_t err)
00225 {
00226     connection_has_gone_down = true;
00227 }
00228 
00229 #ifdef MBED_CONF_APP_ECHO_SERVER
00230 // Make sure that size is greater than 0 and no more than limit,
00231 // useful since, when moduloing a very large number number,
00232 // compilers sometimes screw up and produce a small *negative*
00233 // number.  Who knew?  For example, GCC decided that
00234 // 492318453 (0x1d582ef5) modulo 508 was -47 (0xffffffd1).
00235 static int fix (int size, int limit)
00236 {
00237     if (size <= 0) {
00238         size = limit / 2; // better than 1
00239     } else if (size > limit) {
00240         size = limit;
00241     }
00242 
00243     return size;
00244 }
00245 
00246 // Do a UDP socket echo test to a given host of a given packet size
00247 static void do_udp_echo(UDPSocket *sock, SocketAddress *host_address, int size)
00248 {
00249     bool success = false;
00250     void * recv_data = malloc (size);
00251     SocketAddress sender_address;
00252     TEST_ASSERT(recv_data != NULL);
00253 
00254     // Retry this a few times, don't want to fail due to a flaky link
00255     for (int x = 0; !success && (x < NUM_UDP_RETRIES); x++) {
00256         tr_debug("Echo testing UDP packet size %d byte(s), try %d.", size, x + 1);
00257         if ((sock->sendto(*host_address, (void*) send_data, size) == size) &&
00258             (sock->recvfrom(&sender_address, recv_data, size) == size)) {
00259             TEST_ASSERT (memcmp(send_data, recv_data, size) == 0);
00260             TEST_ASSERT (strcmp(sender_address.get_ip_address(), host_address->get_ip_address()) == 0);
00261             TEST_ASSERT (sender_address.get_port() == host_address->get_port());
00262             success = true;
00263         }
00264     }
00265     TEST_ASSERT (success);
00266     TEST_ASSERT(!connection_has_gone_down);
00267 
00268     free (recv_data);
00269 }
00270 
00271 // The asynchronous callback
00272 static void async_cb(bool *callback_triggered)
00273 {
00274 
00275     TEST_ASSERT (callback_triggered != NULL);
00276     *callback_triggered = true;
00277 }
00278 
00279 // Do a UDP echo but using the asynchronous interface; we can exchange
00280 // packets longer in size than one UDP packet this way
00281 static void do_udp_echo_async(UDPSocket *sock, SocketAddress *host_address,
00282                               int size, bool *callback_triggered)
00283 {
00284     void * recv_data = malloc (size);
00285     int recv_size = 0;
00286     SocketAddress sender_address;
00287     Timer timer;
00288     int x, y, z;
00289     TEST_ASSERT(recv_data != NULL);
00290 
00291     *callback_triggered = false;
00292     for (y = 0; (recv_size < size) && (y < NUM_UDP_RETRIES); y++) {
00293         tr_debug("Echo testing UDP packet size %d byte(s) async, try %d.", size, y + 1);
00294         recv_size = 0;
00295         // Retry this a few times, don't want to fail due to a flaky link
00296         if (sock->sendto(*host_address, (void *) send_data, size) == size) {
00297             // Wait for all the echoed data to arrive
00298             timer.start();
00299             while ((recv_size < size) && (timer.read_ms() < ASYNC_TEST_WAIT_TIME)) {
00300                 if (*callback_triggered) {
00301                     *callback_triggered = false;
00302                     x = sock->recvfrom(&sender_address, (char *) recv_data + recv_size, size);
00303                     if (x > 0) {
00304                         recv_size += x;
00305                     }
00306                     tr_debug("%d byte(s) echoed back so far, %d to go.", recv_size, size - recv_size);
00307                     TEST_ASSERT(strcmp(sender_address.get_ip_address(), host_address->get_ip_address()) == 0);
00308                     TEST_ASSERT(sender_address.get_port() == host_address->get_port());
00309                 }
00310                 wait_ms(10);
00311             }
00312             timer.stop();
00313             timer.reset();
00314 
00315             // If everything arrived back, check it's the same as we sent
00316             if (recv_size == size) {
00317                 z = memcmp(send_data, recv_data, size);
00318                 if (z != 0) {
00319                     tr_debug("WARNING: mismatch, retrying");
00320                     tr_debug("Sent %d, |%*.*s|", size, size, size, send_data);
00321                     tr_debug("Rcvd %d, |%*.*s|", size, size, size, (char *) recv_data);
00322                     // If things don't match, it could be due to data loss (this is UDP
00323                     // you know...), so set recv_size to 0 to cause another try
00324                     recv_size = 0;
00325                 }
00326             }
00327         }
00328     }
00329 
00330     TEST_ASSERT(recv_size == size);
00331     TEST_ASSERT(!connection_has_gone_down);
00332 
00333     free (recv_data);
00334 }
00335 
00336 // Send an entire TCP data buffer until done
00337 static int sendAll(TCPSocket *sock,  const char *data, int size)
00338 {
00339     int x;
00340     int count = 0;
00341     Timer timer;
00342 
00343     timer.start();
00344     while ((count < size) && (timer.read_ms() < 10000)) {
00345         x = sock->send(data + count, size - count);
00346         if (x > 0) {
00347             count += x;
00348             tr_debug("%d byte(s) sent, %d left to send.", count, size - count);
00349         }
00350         wait_ms(10);
00351     }
00352     timer.stop();
00353 
00354     return count;
00355 }
00356 
00357 // Do a TCP echo but using the asynchronous interface
00358 static void do_tcp_echo_async(TCPSocket *sock, int size, bool *callback_triggered)
00359 {
00360     void * recv_data = malloc (size);
00361     int recv_size = 0;
00362     int x, y;
00363     Timer timer;
00364     TEST_ASSERT(recv_data != NULL);
00365 
00366     *callback_triggered = false;
00367     tr_debug("Echo testing TCP packet size %d byte(s) async.", size);
00368     TEST_ASSERT (sendAll(sock, send_data, size) == size);
00369 
00370     // Wait for all the echoed data to arrive
00371     timer.start();
00372     while ((recv_size < size) && (timer.read_ms() < ASYNC_TEST_WAIT_TIME)) {
00373         if (*callback_triggered) {
00374             *callback_triggered = false;
00375             x = sock->recv((char *) recv_data + recv_size, size);
00376             TEST_ASSERT(x > 0);
00377             recv_size += x;
00378             tr_debug("%d byte(s) echoed back so far, %d to go.", recv_size, size - recv_size);
00379         }
00380         wait_ms(10);
00381     }
00382     TEST_ASSERT(recv_size == size);
00383     y = memcmp(send_data, recv_data, size);
00384     if (y != 0) {
00385         tr_debug("Sent %d, |%*.*s|", size, size, size, send_data);
00386         tr_debug("Rcvd %d, |%*.*s|", size, size, size, (char *) recv_data);
00387         TEST_ASSERT(false);
00388     }
00389     timer.stop();
00390 
00391     TEST_ASSERT(!connection_has_gone_down);
00392 
00393     free (recv_data);
00394 }
00395 #endif
00396 
00397 // Get NTP time from a socket
00398 static void do_ntp_sock (UDPSocket *sock, SocketAddress ntp_address)
00399 {
00400     char ntp_values[48] = { 0 };
00401     time_t timestamp = 0;
00402     struct tm *localTime;
00403     char timeString[25];
00404     time_t TIME1970 = 2208988800U;
00405     int len;
00406     bool comms_done = false;
00407 
00408     ntp_values[0] = '\x1b';
00409 
00410     // Retry this a few times, don't want to fail due to a flaky link
00411     for (unsigned int x = 0; !comms_done && (x < NUM_UDP_RETRIES); x++) {
00412         sock->sendto(ntp_address, (void*) ntp_values, sizeof(ntp_values));
00413         len = sock->recvfrom(&ntp_address, (void*) ntp_values, sizeof(ntp_values));
00414         if (len > 0) {
00415             comms_done = true;
00416         }
00417     }
00418     TEST_ASSERT (comms_done);
00419 
00420     tr_debug("UDP: %d byte(s) returned by NTP server.", len);
00421     if (len >= 43) {
00422         timestamp |= ((int) *(ntp_values + 40)) << 24;
00423         timestamp |= ((int) *(ntp_values + 41)) << 16;
00424         timestamp |= ((int) *(ntp_values + 42)) << 8;
00425         timestamp |= ((int) *(ntp_values + 43));
00426         timestamp -= TIME1970;
00427         srand (timestamp);
00428         tr_debug("srand() called");
00429         localTime = localtime(&timestamp);
00430         if (localTime) {
00431             if (strftime(timeString, sizeof(timeString), "%a %b %d %H:%M:%S %Y", localTime) > 0) {
00432                 printf("NTP timestamp is %s.\n", timeString);
00433             }
00434         }
00435     }
00436 }
00437 
00438 // Get NTP time
00439 static void do_ntp(UbloxATCellularInterface *interface)
00440 {
00441     UDPSocket sock;
00442     SocketAddress host_address;
00443 
00444     TEST_ASSERT(sock.open(interface) == 0)
00445 
00446     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_NTP_SERVER, &host_address) == 0);
00447     host_address.set_port(MBED_CONF_APP_NTP_PORT);
00448 
00449     tr_debug("UDP: NIST server %s address: %s on port %d.", MBED_CONF_APP_NTP_SERVER,
00450              host_address.get_ip_address(), host_address.get_port());
00451 
00452     sock.set_timeout(10000);
00453 
00454     do_ntp_sock(&sock, host_address);
00455 
00456     sock.close();
00457 }
00458 
00459 // Use a connection, checking that it is good
00460 static void use_connection(UbloxATCellularInterface *interface)
00461 {
00462     const char * ip_address = interface->get_ip_address();
00463     const char * net_mask = interface->get_netmask();
00464     const char * gateway = interface->get_gateway();
00465 
00466     TEST_ASSERT(interface->is_connected());
00467 
00468     TEST_ASSERT(ip_address != NULL);
00469     tr_debug ("IP address %s.", ip_address);
00470     TEST_ASSERT(net_mask == NULL);
00471     tr_debug ("Net mask %s.", net_mask);
00472     TEST_ASSERT(gateway != NULL);
00473     tr_debug ("Gateway %s.", gateway);
00474 
00475     do_ntp(interface);
00476     TEST_ASSERT(!connection_has_gone_down);
00477 }
00478 
00479 // Drop a connection and check that it has dropped
00480 static void drop_connection(UbloxATCellularInterface *interface)
00481 {
00482     TEST_ASSERT(interface->disconnect() == 0);
00483     TEST_ASSERT(connection_has_gone_down);
00484     connection_has_gone_down = false;
00485     TEST_ASSERT(!interface->is_connected());
00486 }
00487 
00488 // ----------------------------------------------------------------
00489 // TESTS
00490 // ----------------------------------------------------------------
00491 
00492 // Call srand() using the NTP server
00493 void test_set_randomise() {
00494     UDPSocket sock;
00495     SocketAddress host_address;
00496 
00497     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00498                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00499     do_ntp(interface);
00500     TEST_ASSERT(!connection_has_gone_down);
00501     drop_connection(interface);
00502 }
00503 
00504 #ifdef MBED_CONF_APP_ECHO_SERVER
00505 
00506 // Test UDP data exchange
00507 void test_udp_echo() {
00508     UDPSocket sock;
00509     SocketAddress host_address;
00510     SocketAddress local_address;
00511     int x;
00512     int size;
00513 
00514     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00515                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00516 
00517     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00518     host_address.set_port(MBED_CONF_APP_ECHO_UDP_PORT);
00519 
00520     tr_debug("UDP: Server %s address: %s on port %d.", MBED_CONF_APP_ECHO_SERVER,
00521              host_address.get_ip_address(), host_address.get_port());
00522 
00523     TEST_ASSERT(sock.open(interface) == 0)
00524 
00525     // Do a bind, just for the helluvit
00526     local_address.set_port(MBED_CONF_APP_LOCAL_PORT);
00527     TEST_ASSERT(sock.bind(local_address) == 0);
00528 
00529     sock.set_timeout(10000);
00530 
00531     // Test min, max, and some random sizes in-between
00532     do_udp_echo(&sock, &host_address, 1);
00533     do_udp_echo(&sock, &host_address, MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00534     for (x = 0; x < 10; x++) {
00535         size = (rand() % MBED_CONF_APP_UDP_MAX_PACKET_SIZE) + 1;
00536         size = fix(size, MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00537         do_udp_echo(&sock, &host_address, size);
00538     }
00539 
00540     sock.close();
00541     drop_connection(interface);
00542     tr_debug("%d UDP packets of size up to %d byte(s) echoed successfully.",
00543              x, MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00544 }
00545 
00546 // Test many different sizes of UDP data arriving at once
00547 void  test_udp_echo_recv_sizes() {
00548     UDPSocket sock;
00549     SocketAddress host_address;
00550     int x, y, z;
00551     int size;
00552     int tries = 0;
00553     unsigned int offset;
00554     char * recv_data;
00555     bool packetLoss;
00556     bool sendSuccess;
00557     Timer timer;
00558 
00559     interface->deinit();
00560     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00561                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00562 
00563     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00564     host_address.set_port(MBED_CONF_APP_ECHO_UDP_PORT);
00565 
00566     tr_debug("UDP: Server %s address: %s on port %d.", MBED_CONF_APP_ECHO_SERVER,
00567              host_address.get_ip_address(), host_address.get_port());
00568 
00569     TEST_ASSERT(sock.open(interface) == 0)
00570 
00571     do {
00572         tr_debug("--- UDP packet size test, test try %d, flushing input buffers", tries + 1);
00573         // First of all, clear any junk from the socket
00574         sock.set_timeout(1000);
00575         recv_data = (char *) malloc (MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00576         TEST_ASSERT(recv_data != NULL);
00577         while (sock.recvfrom(&host_address, (void *) recv_data, MBED_CONF_APP_UDP_MAX_PACKET_SIZE) > 0) {
00578             // Throw it away
00579         }
00580         free (recv_data);
00581 
00582         sock.set_timeout(10000);
00583 
00584         // Throw random sized UDP packets up...
00585         x = 0;
00586         offset = 0;
00587         while (offset < sizeof (send_data)) {
00588             size = (rand() % (MBED_CONF_APP_UDP_MAX_PACKET_SIZE / 2)) + 1;
00589             size = fix(size, MBED_CONF_APP_UDP_MAX_PACKET_SIZE / 2);
00590             if (offset + size > sizeof (send_data)) {
00591                 size = sizeof (send_data) - offset;
00592             }
00593             sendSuccess = false;
00594             for (y = 0; !sendSuccess && (y < NUM_UDP_RETRIES); y++) {
00595                 tr_debug("Sending UDP packet number %d, size %d byte(s), send try %d.", x + 1, size, y + 1);
00596                 if (sock.sendto(host_address, (void *) (send_data + offset), size) == size) {
00597                     sendSuccess = true;
00598                     offset += size;
00599                 }
00600             }
00601             TEST_ASSERT(sendSuccess);
00602             x++;
00603         }
00604         tr_debug("--- All UDP packets sent");
00605 
00606         // ...and capture them all again afterwards
00607         recv_data = (char *) malloc (sizeof (send_data));
00608         TEST_ASSERT(recv_data != NULL);
00609         memset (recv_data, 0, sizeof (send_data));
00610         size = 0;
00611         y = 0;
00612         packetLoss = false;
00613         timer.start();
00614         while ((size < (int) sizeof (send_data)) && (timer.read_ms() < 10000)) {
00615             y = sock.recvfrom(&host_address, (void *) (recv_data + size), sizeof (send_data) - size);
00616             if (y > 0) {
00617                 size += y;
00618             }
00619         }
00620         timer.stop();
00621         timer.reset();
00622         tr_debug(   "--- Either received everything back or timed out waiting");
00623 
00624         // Check that we reassembled everything correctly
00625         if (size == sizeof (send_data)) {
00626             for (x = 0; ((*(recv_data + x) == *(send_data + x))) && (x < (int) sizeof (send_data)); x++) {
00627             }
00628             if (x != sizeof (send_data)) {
00629                 y = x - 5;
00630                 if (y < 0) {
00631                     y = 0;
00632                 }
00633                 z = 10;
00634                 if (y + z > (int) sizeof (send_data)) {
00635                     z = sizeof(send_data) - y;
00636                 }
00637                 tr_debug("   --- Difference at character %d (send \"%*.*s\", recv \"%*.*s\")",
00638                          x + 1, z, z, send_data + y, z, z, recv_data + y);
00639                 packetLoss = true;
00640             }
00641         } else {
00642             tr_debug("   --- %d bytes missing (%d bytes received when %d were expected))",
00643                       sizeof (send_data) - size, size, sizeof (send_data));
00644             packetLoss = true;
00645         }
00646         free (recv_data);
00647         tries++;
00648     } while (packetLoss && (tries < NUM_UDP_RETRIES));
00649 
00650     TEST_ASSERT(!packetLoss);
00651     TEST_ASSERT(!connection_has_gone_down);
00652     sock.close();
00653     drop_connection(interface);
00654 }
00655 
00656 // Test UDP data exchange via the asynchronous sigio() mechanism
00657 void test_udp_echo_async() {
00658     UDPSocket sock;
00659     SocketAddress host_address;
00660     SocketAddress local_address;
00661     bool callback_triggered = false;
00662     int x;
00663     int size;
00664 
00665     interface->deinit();
00666     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00667                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00668 
00669     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00670     host_address.set_port(MBED_CONF_APP_ECHO_UDP_PORT);
00671 
00672     tr_debug("UDP: Server %s address: %s on port %d.", MBED_CONF_APP_ECHO_SERVER,
00673              host_address.get_ip_address(), host_address.get_port());
00674 
00675     TEST_ASSERT(sock.open(interface) == 0)
00676 
00677     // Set up the async callback and set the timeout to zero
00678     sock.sigio(callback(async_cb, &callback_triggered));
00679     sock.set_timeout(0);
00680 
00681     // Test min, max, and some random sizes in-between
00682     // and this time allow the UDP packets to be fragmented
00683     do_udp_echo_async(&sock, &host_address, 1, &callback_triggered);
00684     do_udp_echo_async(&sock, &host_address, MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE,
00685                       &callback_triggered);
00686     for (x = 0; x < 10; x++) {
00687         size = (rand() % MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE) + 1;
00688         size = fix(size, MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE);
00689         do_udp_echo_async(&sock, &host_address, size, &callback_triggered);
00690     }
00691 
00692     sock.close();
00693 
00694     drop_connection(interface);
00695 
00696     tr_debug("%d UDP packets of size up to %d byte(s) echoed asynchronously and successfully.",
00697              x, MBED_CONF_APP_UDP_MAX_FRAG_PACKET_SIZE);
00698 }
00699 
00700 // Test many different sizes of TCP data arriving at once
00701 void  test_tcp_echo_recv_sizes() {
00702     TCPSocket sock;
00703     SocketAddress host_address;
00704     int x, y, z;
00705     int size;
00706     unsigned int offset;
00707     char * recv_data;
00708     Timer timer;
00709 
00710     interface->deinit();
00711     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00712                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00713 
00714     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00715     host_address.set_port(MBED_CONF_APP_ECHO_TCP_PORT);
00716 
00717     tr_debug("TCP: Server %s address: %s on port %d.", MBED_CONF_APP_ECHO_SERVER,
00718              host_address.get_ip_address(), host_address.get_port());
00719 
00720     TEST_ASSERT(sock.open(interface) == 0)
00721 
00722     TEST_ASSERT(sock.connect(host_address) == 0);
00723 
00724     sock.set_timeout(10000);
00725 
00726     // Throw random sized TCP packets up...
00727     x = 0;
00728     offset = 0;
00729     while (offset < sizeof (send_data)) {
00730         size = (rand() % (MBED_CONF_APP_UDP_MAX_PACKET_SIZE / 2)) + 1;
00731         size = fix(size, MBED_CONF_APP_UDP_MAX_PACKET_SIZE / 2);
00732         if (offset + size > sizeof (send_data)) {
00733             size = sizeof (send_data) - offset;
00734         }
00735         tr_debug("Sending TCP packet number %d, size %d byte(s).", x + 1, size);
00736         TEST_ASSERT(sendAll(&sock, (send_data + offset), size) == size);
00737         offset += size;
00738         x++;
00739     }
00740 
00741     // ...and capture them all again afterwards
00742     recv_data = (char *) malloc (sizeof (send_data));
00743     TEST_ASSERT(recv_data != NULL);
00744     memset (recv_data, 0, sizeof (send_data));
00745     size = 0;
00746     x = 0;
00747     timer.start();
00748     while ((size < (int) sizeof (send_data)) && (timer.read_ms() < 30000)) {
00749         y = sock.recv((void *) (recv_data + size), sizeof (send_data) - size);
00750         tr_debug("Received TCP packet number %d, size %d byte(s).", x, y);
00751         size += y;
00752         x++;
00753     }
00754     timer.stop();
00755     timer.reset();
00756 
00757     // Check that we reassembled everything correctly
00758     for (x = 0; ((*(recv_data + x) == *(send_data + x))) && (x < (int) sizeof (send_data)); x++) {
00759     }
00760     if (x != sizeof (send_data)) {
00761         y = x - 5;
00762         if (y < 0) {
00763             y = 0;
00764         }
00765         z = 10;
00766         if (y + z > (int) sizeof (send_data)) {
00767             z = sizeof(send_data) - y;
00768         }
00769         tr_debug("Difference at character %d (send \"%*.*s\", recv \"%*.*s\")",
00770                  x + 1, z, z, send_data + y, z, z, recv_data + y);
00771         TEST_ASSERT(false);
00772     }
00773     free (recv_data);
00774 
00775     TEST_ASSERT(!connection_has_gone_down);
00776     sock.close();
00777     drop_connection(interface);
00778 }
00779 
00780 // Test TCP data exchange via the asynchronous sigio() mechanism
00781 void test_tcp_echo_async() {
00782     TCPSocket sock;
00783     SocketAddress host_address;
00784     bool callback_triggered = false;
00785     int x;
00786     int size;
00787 
00788     interface->deinit();
00789     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00790                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00791 
00792     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00793     host_address.set_port(MBED_CONF_APP_ECHO_TCP_PORT);
00794 
00795     tr_debug("TCP: Server %s address: %s on port %d.", MBED_CONF_APP_ECHO_SERVER,
00796              host_address.get_ip_address(), host_address.get_port());
00797 
00798     TEST_ASSERT(sock.open(interface) == 0)
00799 
00800     // Set up the async callback and set the timeout to zero
00801     sock.sigio(callback(async_cb, &callback_triggered));
00802     sock.set_timeout(0);
00803 
00804     TEST_ASSERT(sock.connect(host_address) == 0);
00805     // Test min, max, and some random sizes in-between
00806     do_tcp_echo_async(&sock, 1, &callback_triggered);
00807     do_tcp_echo_async(&sock, MBED_CONF_APP_TCP_MAX_PACKET_SIZE, &callback_triggered);
00808     for (x = 0; x < 10; x++) {
00809         size = (rand() % MBED_CONF_APP_TCP_MAX_PACKET_SIZE) + 1;
00810         size = fix(size, MBED_CONF_APP_TCP_MAX_PACKET_SIZE);
00811         do_tcp_echo_async(&sock, size, &callback_triggered);
00812     }
00813 
00814     sock.close();
00815 
00816     drop_connection(interface);
00817 
00818     tr_debug("%d TCP packets of size up to %d byte(s) echoed asynchronously and successfully.",
00819              x, MBED_CONF_APP_TCP_MAX_PACKET_SIZE);
00820 }
00821 #endif
00822 
00823 // Allocate max sockets
00824 void test_max_sockets() {
00825     UDPSocket sock[MAX_NUM_SOCKETS];
00826     UDPSocket sockNone;
00827     SocketAddress host_address;
00828 
00829     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00830                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00831 
00832     TEST_ASSERT(interface->gethostbyname(MBED_CONF_APP_NTP_SERVER, &host_address) == 0);
00833     host_address.set_port(MBED_CONF_APP_NTP_PORT);
00834 
00835     // Open the first socket and use it
00836     TEST_ASSERT(sock[0].open(interface) == 0)
00837     sock[0].set_timeout(10000);
00838     do_ntp_sock(&sock[0], host_address);
00839 
00840     // Check that we stop being able to get sockets at the max number
00841     for (int x = 1; x < (int) (sizeof (sock) / sizeof (sock[0])); x++) {
00842         TEST_ASSERT(sock[x].open(interface) == 0)
00843     }
00844     TEST_ASSERT(sockNone.open(interface) < 0);
00845 
00846     // Now use the last one
00847     sock[sizeof (sock) / sizeof (sock[0]) - 1].set_timeout(10000);
00848     do_ntp_sock(&sock[sizeof (sock) / sizeof (sock[0]) - 1], host_address);
00849 
00850     // Close all of the sockets
00851     for (int x = 0; x < (int) (sizeof (sock) / sizeof (sock[0])); x++) {
00852         TEST_ASSERT(sock[x].close() == 0);
00853     }
00854 
00855     drop_connection(interface);
00856 }
00857 
00858 // Connect with credentials included in the connect request
00859 void test_connect_credentials() {
00860 
00861     interface->deinit();
00862     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00863                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00864     use_connection(interface);
00865     drop_connection(interface);
00866 }
00867 
00868 // Test with credentials preset
00869 void test_connect_preset_credentials() {
00870 
00871     interface->deinit();
00872     TEST_ASSERT(interface->init(MBED_CONF_APP_DEFAULT_PIN));
00873     interface->set_credentials(MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME,
00874                                MBED_CONF_APP_PASSWORD);
00875     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN) == 0);
00876     use_connection(interface);
00877     drop_connection(interface);
00878 }
00879 
00880 // Test adding and using a SIM pin, then removing it, using the pending
00881 // mechanism where the change doesn't occur until connect() is called
00882 void test_check_sim_pin_pending() {
00883 
00884     interface->deinit();
00885 
00886     // Enable PIN checking (which will use the current PIN)
00887     // and also flag that the PIN should be changed to MBED_CONF_APP_ALT_PIN,
00888     // then try connecting
00889     interface->set_sim_pin_check(true);
00890     interface->set_new_sim_pin(MBED_CONF_APP_ALT_PIN);
00891     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00892                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00893     use_connection(interface);
00894     drop_connection(interface);
00895     interface->deinit();
00896 
00897     // Now change the PIN back to what it was before
00898     interface->set_new_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00899     TEST_ASSERT(interface->connect(MBED_CONF_APP_ALT_PIN, MBED_CONF_APP_APN,
00900                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00901     use_connection(interface);
00902     drop_connection(interface);
00903     interface->deinit();
00904 
00905     // Check that it was changed back, and this time
00906     // use the other way of entering the PIN
00907     interface->set_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00908     TEST_ASSERT(interface->connect(NULL, MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME,
00909                                    MBED_CONF_APP_PASSWORD) == 0);
00910     use_connection(interface);
00911     drop_connection(interface);
00912     interface->deinit();
00913 
00914     // Remove PIN checking again and check that it no
00915     // longer matters what the PIN is
00916     interface->set_sim_pin_check(false);
00917     TEST_ASSERT(interface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00918                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00919     use_connection(interface);
00920     drop_connection(interface);
00921     interface->deinit();
00922     TEST_ASSERT(interface->init(NULL));
00923     TEST_ASSERT(interface->connect(MBED_CONF_APP_INCORRECT_PIN, MBED_CONF_APP_APN,
00924                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00925     use_connection(interface);
00926     drop_connection(interface);
00927 
00928     // Put the SIM pin back to the correct value for any subsequent tests
00929     interface->set_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00930 }
00931 
00932 // Test adding and using a SIM pin, then removing it, using the immediate
00933 // mechanism
00934 void test_check_sim_pin_immediate() {
00935 
00936     interface->deinit();
00937     interface->connection_status_cb(connection_down_cb);
00938 
00939     // Enable PIN checking (which will use the current PIN), change
00940     // the PIN to MBED_CONF_APP_ALT_PIN, then try connecting after powering on and
00941     // off the modem
00942     interface->set_sim_pin_check(true, true, MBED_CONF_APP_DEFAULT_PIN);
00943     interface->set_new_sim_pin(MBED_CONF_APP_ALT_PIN, true);
00944     interface->deinit();
00945     TEST_ASSERT(interface->init(NULL));
00946     TEST_ASSERT(interface->connect(MBED_CONF_APP_ALT_PIN, MBED_CONF_APP_APN,
00947                                    MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00948     use_connection(interface);
00949     drop_connection(interface);
00950 
00951     interface->connection_status_cb(connection_down_cb);
00952 
00953     // Now change the PIN back to what it was before
00954     interface->set_new_sim_pin(MBED_CONF_APP_DEFAULT_PIN, true);
00955     interface->deinit();
00956     interface->set_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00957     TEST_ASSERT(interface->init(NULL));
00958     TEST_ASSERT(interface->connect(NULL, MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME,
00959                                    MBED_CONF_APP_PASSWORD) == 0);
00960     use_connection(interface);
00961     drop_connection(interface);
00962 
00963     interface->connection_status_cb(connection_down_cb);
00964 
00965     // Remove PIN checking again and check that it no
00966     // longer matters what the PIN is
00967     interface->set_sim_pin_check(false, true);
00968     interface->deinit();
00969     TEST_ASSERT(interface->init(MBED_CONF_APP_INCORRECT_PIN));
00970     TEST_ASSERT(interface->connect(NULL, MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME,
00971                                    MBED_CONF_APP_PASSWORD) == 0);
00972     use_connection(interface);
00973     drop_connection(interface);
00974 
00975     // Put the SIM pin back to the correct value for any subsequent tests
00976     interface->set_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00977 }
00978 
00979 // Test being able to connect with a local instance of the interface
00980 // NOTE: since this local instance will fiddle with bits of HW that the
00981 // static instance thought it owned, the static instance will no longer
00982 // work afterwards, hence this must be run as the last test in the list
00983 void test_connect_local_instance_last_test() {
00984 
00985     UbloxATCellularInterface *pLocalInterface = NULL;
00986 
00987     pLocalInterface = new UbloxATCellularInterface(MDMTXD, MDMRXD,
00988                                                    MBED_CONF_UBLOX_CELL_BAUD_RATE,
00989                                                    MBED_CONF_APP_DEBUG_ON);
00990     pLocalInterface->connection_status_cb(connection_down_cb);
00991 
00992     TEST_ASSERT(pLocalInterface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00993                                          MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
00994     use_connection(pLocalInterface);
00995     drop_connection(pLocalInterface);
00996     delete pLocalInterface;
00997 
00998     pLocalInterface = new UbloxATCellularInterface(MDMTXD, MDMRXD,
00999                                                    MBED_CONF_UBLOX_CELL_BAUD_RATE,
01000                                                    MBED_CONF_APP_DEBUG_ON);
01001     pLocalInterface->connection_status_cb(connection_down_cb);
01002 
01003     TEST_ASSERT(pLocalInterface->connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
01004                                          MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == 0);
01005     use_connection(pLocalInterface);
01006     drop_connection(pLocalInterface);
01007     delete pLocalInterface;
01008 }
01009 
01010 // ----------------------------------------------------------------
01011 // TEST ENVIRONMENT
01012 // ----------------------------------------------------------------
01013 
01014 // Setup the test environment
01015 utest::v1::status_t test_setup(const size_t number_of_cases) {
01016     // Setup Greentea with a timeout
01017     GREENTEA_SETUP(960, "default_auto");
01018     return verbose_test_setup_handler(number_of_cases);
01019 }
01020 
01021 // IMPORTANT!!! if you make a change to the tests here you should
01022 // check whether the same change should be made to the tests under
01023 // the PPP interface.
01024 
01025 // Test cases
01026 Case cases[] = {
01027     Case("Set randomise", test_set_randomise),
01028 #ifdef MBED_CONF_APP_ECHO_SERVER
01029     Case("UDP echo test", test_udp_echo),
01030 # ifndef TARGET_UBLOX_C027 // Not enough RAM on little 'ole C027 to run this test
01031     Case("UDP recv sizes", test_udp_echo_recv_sizes),
01032 # endif
01033     Case("UDP async echo test", test_udp_echo_async),
01034 # ifndef TARGET_UBLOX_C027 // Not enough RAM on little 'ole C027 to run this test
01035     Case("TCP recv sizes", test_tcp_echo_recv_sizes),
01036 # endif
01037     Case("TCP async echo test", test_tcp_echo_async),
01038 #endif
01039 #ifndef TARGET_UBLOX_C027 // Not enough RAM on little 'ole C027 to run this test
01040     Case("Alloc max sockets", test_max_sockets),
01041 #endif
01042     Case("Connect with credentials", test_connect_credentials),
01043     Case("Connect with preset credentials", test_connect_preset_credentials),
01044 #if MBED_CONF_APP_RUN_SIM_PIN_CHANGE_TESTS
01045     Case("Check SIM pin, pending", test_check_sim_pin_pending),
01046     Case("Check SIM pin, immediate", test_check_sim_pin_immediate),
01047 #endif
01048 #ifndef TARGET_UBLOX_C027 // Not enough RAM on little 'ole C027 for this
01049     Case("Connect using local instance, must be last test", test_connect_local_instance_last_test)
01050 #endif
01051 };
01052 
01053 Specification specification(test_setup, cases);
01054 
01055 // ----------------------------------------------------------------
01056 // MAIN
01057 // ----------------------------------------------------------------
01058 
01059 int main() {
01060 
01061 #ifdef FEATURE_COMMON_PAL
01062     mbed_trace_init();
01063 
01064     mbed_trace_mutex_wait_function_set(lock);
01065     mbed_trace_mutex_release_function_set(unlock);
01066 #endif
01067 
01068     interface->connection_status_cb(connection_down_cb);
01069 
01070     // Run tests
01071     return !Harness::run(specification);
01072 }
01073 
01074 // End Of File
01075