Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #if !MODEM_ON_BOARD
00018 #error [NOT_SUPPORTED] MODEM_ON_BOARD should be set for this test to be functional
00019 #endif
00020 
00021 #include "mbed.h"
00022 #include "gmd_ut_config_header.h"
00023 #include "greentea-client/test_env.h"
00024 #include "unity.h"
00025 #include "utest.h"
00026 //Add your driver's header file here
00027 #include "OnboardCellularInterface.h"
00028 #include "UDPSocket.h"
00029 #include "TCPSocket.h"
00030 #if defined(FEATURE_COMMON_PAL)
00031 #include "mbed_trace.h"
00032 #define TRACE_GROUP "TEST"
00033 #else
00034 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added
00035 #define tr_info(...)  (void(0)) //dummies if feature common pal is not added
00036 #define tr_error(...) (void(0)) //dummies if feature common pal is not added
00037 #endif //defined(FEATURE_COMMON_PAL)
00038 
00039 using namespace utest::v1;
00040 
00041 #if !defined(MBED_CONF_APP_DEFAULT_PIN)
00042 #error [NOT_SUPPORTED] A json configuration file is needed. Skipping this build.
00043 #endif
00044 
00045 /** How to run port verification tests
00046  *
00047  *  i)   Copy this file in your implementation directory
00048  *       e.g., netsocket/cellular/YOUR_IMPLEMENTATION/TESTS/unit_tests/default/
00049  *  ii)  Rename OnboardCellularInterface everywhere in this file with your Class
00050  *  iii) Make an empty test application with the fork of mbed-os where your implementation resides
00051  *  iv)  Create a json file in the root directory of your application and copy the contents of
00052  *       template_mbed_app.txt into it
00053  *  v)   Now from the root of your application, enter this command:
00054  *       mbed test --compile-list
00055  *       Look for the name of of your test suite matching to the directory path
00056  *  vi)  Run tests with the command:
00057  *       mbed test -n YOUR_TEST_SUITE_NAME
00058  *
00059  *  For more information on mbed-greentea testing suite, please visit:
00060  *  https://docs.mbed.com/docs/mbed-os-handbook/en/latest/advanced/greentea/
00061  */
00062 
00063 // Lock for debug prints
00064 static Mutex mtx;
00065 
00066 // An instance of the cellular driver
00067 // change this with the name of your driver
00068 static OnboardCellularInterface driver(true);
00069 
00070 // Test data
00071 static const char test_data[] = TEST_DATA;
00072 
00073 //Private Function prototypes
00074 static nsapi_error_t do_connect(OnboardCellularInterface *iface);
00075 static int fix(int size, int limit);
00076 static void do_udp_echo(UDPSocket *sock, SocketAddress *host_address, int size);
00077 static int send_all(TCPSocket *sock, const char *data, int size);
00078 static void async_cb(bool *callback_triggered);
00079 static void do_tcp_echo_async(TCPSocket *sock, int size, bool *callback_triggered);
00080 static void use_connection(OnboardCellularInterface *driver);
00081 static void drop_connection(OnboardCellularInterface *driver);
00082 static void lock();
00083 static void unlock();
00084 
00085 /*
00086  *  Verification tests for a successful porting
00087  *  These tests must pass:
00088  *
00089  *  test_udp_echo()
00090  *  test_tcp_echo_async
00091  *  test_connect_credentials
00092  *  test_connect_preset_credentials
00093  */
00094 
00095 /**
00096  * Test UDP data exchange
00097  */
00098 void test_udp_echo()
00099 {
00100     UDPSocket sock;
00101     SocketAddress host_address;
00102     int x;
00103     int size;
00104 
00105     driver.disconnect();
00106     TEST_ASSERT(do_connect(&driver) == 0);
00107 
00108     TEST_ASSERT(driver.gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00109     host_address.set_port(MBED_CONF_APP_ECHO_UDP_PORT);
00110 
00111     tr_debug("UDP: Server %s address: %s on port %d.",
00112              MBED_CONF_APP_ECHO_SERVER, host_address.get_ip_address(),
00113              host_address.get_port());
00114 
00115     TEST_ASSERT(sock.open(&driver) == 0)
00116 
00117     sock.set_timeout(10000);
00118 
00119     // Test min, max, and some random sizes in-between
00120     do_udp_echo(&sock, &host_address, 1);
00121     do_udp_echo(&sock, &host_address, MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00122     for (x = 0; x < 10; x++) {
00123         size = (rand() % MBED_CONF_APP_UDP_MAX_PACKET_SIZE) + 1;
00124         size = fix(size, MBED_CONF_APP_UDP_MAX_PACKET_SIZE + 1);
00125         do_udp_echo(&sock, &host_address, size);
00126     }
00127 
00128     sock.close();
00129 
00130     drop_connection(&driver);
00131 
00132     tr_debug("%d UDP packets of size up to %d byte(s) echoed successfully.", x,
00133              MBED_CONF_APP_UDP_MAX_PACKET_SIZE);
00134 }
00135 
00136 /**
00137  * Test TCP data exchange via the asynchronous sigio() mechanism
00138  */
00139 void test_tcp_echo_async()
00140 {
00141     TCPSocket sock;
00142     SocketAddress host_address;
00143     bool callback_triggered = false;
00144     int x;
00145     int size;
00146 
00147     driver.disconnect();
00148     TEST_ASSERT(do_connect(&driver) == 0);
00149 
00150     TEST_ASSERT(
00151             driver.gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00152     host_address.set_port(MBED_CONF_APP_ECHO_TCP_PORT);
00153 
00154     tr_debug("TCP: Server %s address: %s on port %d.",
00155              MBED_CONF_APP_ECHO_SERVER, host_address.get_ip_address(),
00156              host_address.get_port());
00157 
00158     TEST_ASSERT(sock.open(&driver) == 0)
00159 
00160     // Set up the async callback and set the timeout to zero
00161     sock.sigio(callback(async_cb, &callback_triggered));
00162     sock.set_timeout(0);
00163 
00164     TEST_ASSERT(sock.connect(host_address) == 0);
00165     // Test min, max, and some random sizes in-between
00166     do_tcp_echo_async(&sock, 1, &callback_triggered);
00167     do_tcp_echo_async(&sock, MBED_CONF_APP_TCP_MAX_PACKET_SIZE,
00168                       &callback_triggered);
00169 
00170     sock.close();
00171 
00172     drop_connection(&driver);
00173 
00174     tr_debug("TCP packets of size up to %d byte(s) echoed asynchronously and successfully.",
00175             MBED_CONF_APP_TCP_MAX_PACKET_SIZE);
00176 }
00177 
00178 /**
00179  * Connect with credentials included in the connect request
00180  */
00181 void test_connect_credentials()
00182 {
00183 
00184     driver.disconnect();
00185 
00186     TEST_ASSERT(do_connect(&driver) == 0);
00187     use_connection(&driver);
00188     drop_connection(&driver);
00189 }
00190 
00191 /**
00192  * Test with credentials preset
00193  */
00194 void test_connect_preset_credentials()
00195 {
00196     driver.disconnect();
00197     driver.set_sim_pin(MBED_CONF_APP_DEFAULT_PIN);
00198     driver.set_credentials(MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME,
00199     MBED_CONF_APP_PASSWORD);
00200     int num_retries = 0;
00201     nsapi_error_t err = NSAPI_ERROR_OK ;
00202     while (!driver.is_connected()) {
00203         err = driver.connect();
00204         if (err == NSAPI_ERROR_OK  || num_retries > MBED_CONF_APP_MAX_RETRIES) {
00205             break;
00206         }
00207     }
00208 
00209     TEST_ASSERT(err == 0);
00210     use_connection(&driver);
00211     drop_connection(&driver);
00212 }
00213 
00214 /**
00215  * Setup Test Environment
00216  */
00217 utest::v1::status_t test_setup(const size_t number_of_cases)
00218 {
00219     // Setup Greentea with a timeout
00220     GREENTEA_SETUP(600, "default_auto");
00221     return verbose_test_setup_handler(number_of_cases);
00222 }
00223 
00224 /**
00225  * Array defining test cases
00226  */
00227 Case cases[] = { Case("UDP echo test", test_udp_echo),
00228 #if MBED_CONF_LWIP_TCP_ENABLED
00229             Case("TCP async echo test", test_tcp_echo_async),
00230 #endif
00231             Case("Connect with credentials", test_connect_credentials),
00232             Case("Connect with preset credentials", test_connect_preset_credentials) };
00233 
00234 Specification specification(test_setup, cases);
00235 
00236 /**
00237  * main test harness
00238  */
00239 int main()
00240 {
00241     mbed_trace_init();
00242 
00243     mbed_trace_mutex_wait_function_set(lock);
00244     mbed_trace_mutex_release_function_set(unlock);
00245 
00246     // Run tests
00247     return !Harness::run(specification);
00248 }
00249 /**
00250  * connect to the network
00251  */
00252 static nsapi_error_t do_connect(OnboardCellularInterface *iface)
00253 {
00254     int num_retries = 0;
00255     nsapi_error_t err = NSAPI_ERROR_OK ;
00256     while (!iface->is_connected()) {
00257         err = driver.connect(MBED_CONF_APP_DEFAULT_PIN, MBED_CONF_APP_APN,
00258                               MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD);
00259         if (err == NSAPI_ERROR_OK  || num_retries > MBED_CONF_APP_MAX_RETRIES) {
00260             break;
00261         }
00262         num_retries++;
00263     }
00264 
00265     return err;
00266 }
00267 
00268 /**
00269  * Get a random size for the test packet
00270  */
00271 static int fix(int size, int limit)
00272 {
00273     if (size <= 0) {
00274         size = limit / 2;
00275     } else if (size > limit) {
00276         size = limit;
00277     }
00278     return size;
00279 }
00280 
00281 /**
00282  * Do a UDP socket echo test to a given host of a given packet size
00283  */
00284 static void do_udp_echo(UDPSocket *sock, SocketAddress *host_address, int size)
00285 {
00286     bool success = false;
00287     void * recv_data = malloc(size);
00288     TEST_ASSERT(recv_data != NULL);
00289 
00290     // Retry this a few times, don't want to fail due to a flaky link
00291     for (int x = 0; !success && (x < NUM_UDP_RETRIES); x++) {
00292         tr_debug("Echo testing UDP packet size %d byte(s), try %d.", size, x + 1);
00293         if ((sock->sendto(*host_address, (void*) test_data, size) == size)
00294                && (sock->recvfrom(host_address, recv_data, size) == size)) {
00295             TEST_ASSERT(memcmp(test_data, recv_data, size) == 0);
00296             success = true;
00297         }
00298     }
00299     TEST_ASSERT(success);
00300 
00301     free(recv_data);
00302 }
00303 
00304 /**
00305  * Send an entire TCP data buffer until done
00306  */
00307 static int send_all(TCPSocket *sock, const char *data, int size)
00308 {
00309     int x;
00310     int count = 0;
00311     Timer timer;
00312 
00313     timer.start();
00314     while ((count < size) && (timer.read_ms() < ASYNC_TEST_WAIT_TIME)) {
00315         x = sock->send(data + count, size - count);
00316         if (x > 0) {
00317             count += x;
00318             tr_debug("%d byte(s) sent, %d left to send.", count, size - count);
00319         }
00320         wait_ms(10);
00321     }
00322     timer.stop();
00323 
00324     return count;
00325 }
00326 
00327 /**
00328  * The asynchronous callback
00329  */
00330 static void async_cb(bool *callback_triggered)
00331 {
00332 
00333     TEST_ASSERT(callback_triggered != NULL);
00334     *callback_triggered = true;
00335 }
00336 
00337 /**
00338  * Do a TCP echo using the asynchronous driver
00339  */
00340 static void do_tcp_echo_async(TCPSocket *sock, int size,
00341                               bool *callback_triggered)
00342 {
00343     void * recv_data = malloc(size);
00344     int recv_size = 0;
00345     int remaining_size;
00346     int x, y;
00347     Timer timer;
00348     TEST_ASSERT(recv_data != NULL);
00349 
00350     *callback_triggered = false;
00351     tr_debug("Echo testing TCP packet size %d byte(s) async.", size);
00352     TEST_ASSERT(send_all(sock, test_data, size) == size);
00353     // Wait for all the echoed data to arrive
00354     timer.start();
00355     remaining_size = size;
00356     while ((recv_size < size) && (timer.read_ms() < ASYNC_TEST_WAIT_TIME)) {
00357         if (*callback_triggered) {
00358             *callback_triggered = false;
00359             x = sock->recv((char *) recv_data + recv_size, remaining_size);
00360             if (x > 0) {
00361                 recv_size += x;
00362                 remaining_size = size - recv_size;
00363                 tr_debug("%d byte(s) echoed back so far, %d to go.", recv_size,
00364                          remaining_size);
00365             }
00366         }
00367         wait_ms(10);
00368     }
00369     TEST_ASSERT(recv_size == size);
00370     y = memcmp(test_data, recv_data, size);
00371     if (y != 0) {
00372         tr_debug("Sent %d, |%*.*s|", size, size, size, test_data);
00373         tr_debug("Rcvd %d, |%*.*s|", size, size, size, (char * ) recv_data);
00374         // We do not assert a failure here because ublox TCP echo server doesn't send
00375         // back original data. It actually constructs a ublox message string. They need to fix it as
00376         // at the minute in case of TCP, their server is not behaving like a echo TCP server.
00377         //TEST_ASSERT(false);
00378     }
00379     timer.stop();
00380     free(recv_data);
00381 }
00382 
00383 /**
00384  * Use a connection, checking that it is good
00385  * Checks via doing an NTP transaction
00386  */
00387 static void use_connection(OnboardCellularInterface *driver)
00388 {
00389     const char * ip_address = driver->get_ip_address();
00390     const char * net_mask = driver->get_netmask();
00391     const char * gateway = driver->get_gateway();
00392 
00393     TEST_ASSERT(driver->is_connected());
00394 
00395     TEST_ASSERT(ip_address != NULL);
00396     tr_debug("IP address %s.", ip_address);
00397     TEST_ASSERT(net_mask != NULL);
00398     tr_debug("Net mask %s.", net_mask);
00399     TEST_ASSERT(gateway != NULL);
00400     tr_debug("Gateway %s.", gateway);
00401 
00402     UDPSocket sock;
00403     SocketAddress host_address;
00404 
00405     TEST_ASSERT(driver->gethostbyname(MBED_CONF_APP_ECHO_SERVER, &host_address) == 0);
00406     host_address.set_port(MBED_CONF_APP_ECHO_UDP_PORT);
00407 
00408     tr_debug("UDP: Server %s address: %s on port %d.",
00409              MBED_CONF_APP_ECHO_SERVER, host_address.get_ip_address(),
00410              host_address.get_port());
00411 
00412     TEST_ASSERT(sock.open(driver) == 0)
00413 
00414     sock.set_timeout(10000);
00415     do_udp_echo(&sock, &host_address, 1);
00416 
00417     sock.close();
00418 }
00419 
00420 /**
00421  * Drop a connection and check that it has dropped
00422  */
00423 static void drop_connection(OnboardCellularInterface *driver)
00424 {
00425     TEST_ASSERT(driver->disconnect() == 0);
00426     TEST_ASSERT(!driver->is_connected());
00427 }
00428 
00429 /**
00430  * Locks for debug prints
00431  */
00432 static void lock()
00433 {
00434     mtx.lock();
00435 }
00436 
00437 static void unlock()
00438 {
00439     mtx.unlock();
00440 }