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