Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Copyright (c) 2013-2017, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018  #ifndef MBED_CONF_APP_CONNECT_STATEMENT
00019      #error [NOT_SUPPORTED] No network configuration found for this target.
00020  #endif
00021 
00022 #ifndef MBED_EXTENDED_TESTS
00023     #error [NOT_SUPPORTED] Pressure tests are not supported by default
00024 #endif
00025 
00026 #include "mbed.h"
00027 #include MBED_CONF_APP_HEADER_FILE
00028 #include "UDPSocket.h"
00029 #include "greentea-client/test_env.h"
00030 #include "unity/unity.h"
00031 #include "utest.h"
00032 
00033 using namespace utest::v1;
00034 
00035 
00036 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN
00037 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64
00038 #endif
00039 
00040 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX
00041 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000
00042 #endif
00043 
00044 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT
00045 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100
00046 #endif
00047 
00048 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED
00049 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
00050 #endif
00051 
00052 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG
00053 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false
00054 #endif
00055 
00056 #define STRINGIZE(x) STRINGIZE2(x)
00057 #define STRINGIZE2(x) #x
00058 
00059 
00060 // Simple xorshift pseudorandom number generator
00061 class RandSeq {
00062 private:
00063     uint32_t x;
00064     uint32_t y;
00065     static const int A = 15;
00066     static const int B = 18;
00067     static const int C = 11;
00068 
00069 public:
00070     RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED)
00071         : x(seed), y(seed) {}
00072 
00073     uint32_t next(void) {
00074         x ^= x << A;
00075         x ^= x >> B;
00076         x ^= y ^ (y >> C);
00077         return x + y;
00078     }
00079 
00080     void skip(size_t size) {
00081         for (size_t i = 0; i < size; i++) {
00082             next();
00083         }
00084     }
00085 
00086     void buffer(uint8_t *buffer, size_t size) {
00087         RandSeq lookahead = *this;
00088 
00089         for (size_t i = 0; i < size; i++) {
00090             buffer[i] = lookahead.next() & 0xff;
00091         }
00092     }
00093 
00094     int cmp(uint8_t *buffer, size_t size) {
00095         RandSeq lookahead = *this;
00096 
00097         for (size_t i = 0; i < size; i++) {
00098             int diff = buffer[i] - (lookahead.next() & 0xff);
00099             if (diff != 0) {
00100                 return diff;
00101             }
00102         }
00103         return 0;
00104     }
00105 };
00106 
00107 // Shared buffer for network transactions
00108 uint8_t *buffer;
00109 size_t buffer_size;
00110 
00111 // Tries to get the biggest buffer possible on the device. Exponentially
00112 // grows a buffer until heap runs out of space, and uses half to leave
00113 // space for the rest of the program
00114 void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
00115     size_t i = min;
00116     while (i < max) {
00117         void *b = malloc(i);
00118         if (!b) {
00119             i /= 4;
00120             if (i < min) {
00121                 i = min;
00122             }
00123             break;
00124         }
00125         free(b);
00126         i *= 2;
00127     }
00128 
00129     *buffer = (uint8_t *)malloc(i);
00130     *size = i;
00131     TEST_ASSERT(buffer);
00132 }
00133 
00134 void test_udp_packet_pressure() {
00135     generate_buffer(&buffer, &buffer_size,
00136         MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN,
00137         MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX);
00138     printf("MBED: Generated buffer %d\r\n", buffer_size);
00139 
00140     NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
00141     int err =  MBED_CONF_APP_CONNECT_STATEMENT;
00142     TEST_ASSERT_EQUAL(0, err);
00143 
00144     printf("MBED: UDPClient IP address is '%s'\n", net->get_ip_address());
00145 
00146     UDPSocket sock;
00147     SocketAddress udp_addr(MBED_CONF_APP_ECHO_SERVER_ADDR, MBED_CONF_APP_ECHO_SERVER_PORT);
00148 
00149     Timer timer;
00150     timer.start();
00151 
00152     // Tests exponentially growing sequences
00153     for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
00154          size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX;
00155          size *= 2) {
00156         err = sock.open(net);
00157         TEST_ASSERT_EQUAL(0, err);
00158         printf("UDP: %s:%d streaming %d bytes\r\n",
00159             udp_addr.get_ip_address(), udp_addr.get_port(), size);
00160 
00161         sock.set_blocking(false);
00162 
00163         // Loop to send/recv all data
00164         RandSeq tx_seq;
00165         RandSeq rx_seq;
00166         size_t rx_count = 0;
00167         size_t tx_count = 0;
00168         int known_time = timer.read_ms();
00169         size_t window = buffer_size;
00170 
00171         while (tx_count < size || rx_count < size) {
00172             // Send out packets
00173             if (tx_count < size) {
00174                 size_t chunk_size = size - tx_count;
00175                 if (chunk_size > window) {
00176                     chunk_size = window;
00177                 }
00178 
00179                 tx_seq.buffer(buffer, chunk_size);
00180                 int td = sock.sendto(udp_addr, buffer, chunk_size);
00181 
00182                 if (td > 0) {
00183                     if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00184                         printf("UDP: tx -> %d\r\n", td);
00185                     }
00186                     tx_seq.skip(td);
00187                     tx_count += td;
00188                 } else if (td != NSAPI_ERROR_WOULD_BLOCK ) {
00189                     // We may fail to send because of buffering issues, revert to
00190                     // last good sequence and cut buffer in half
00191                     if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
00192                         window /= 2;
00193                     }
00194 
00195                     if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00196                         printf("UDP: Not sent (%d), window = %d\r\n", td, window);
00197                     }
00198                 }
00199             }
00200 
00201             // Prioritize recieving over sending packets to avoid flooding
00202             // the network while handling erronous packets
00203             while (rx_count < size) {
00204                 int rd = sock.recvfrom(NULL, buffer, buffer_size);
00205                 TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK );
00206 
00207                 if (rd > 0) {
00208                     if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00209                         printf("UDP: rx <- %d\r\n", rd);
00210                     }
00211 
00212                     if (rx_seq.cmp(buffer, rd) == 0) {
00213                         rx_seq.skip(rd);
00214                         rx_count += rd;
00215                         known_time = timer.read_ms();
00216                         if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) {
00217                             window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
00218                         }
00219                     }
00220                 } else if (timer.read_ms() - known_time >
00221                         MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) {
00222                     // Dropped packet or out of order, revert to last good sequence
00223                     // and cut buffer in half
00224                     tx_seq = rx_seq;
00225                     tx_count = rx_count;
00226                     known_time = timer.read_ms();
00227                     if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
00228                         window /= 2;
00229                     }
00230 
00231                     if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00232                         printf("UDP: Dropped, window = %d\r\n", window);
00233                     }
00234                 } else if (rd == NSAPI_ERROR_WOULD_BLOCK ) {
00235                     break;
00236                 }
00237             }
00238         }
00239 
00240         err = sock.close();
00241         TEST_ASSERT_EQUAL(0, err);
00242     }
00243 
00244     timer.stop();
00245     printf("MBED: Time taken: %fs\r\n", timer.read());
00246     printf("MBED: Speed: %.3fkb/s\r\n",
00247             8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX -
00248             MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
00249 
00250     net->disconnect();
00251 }
00252 
00253 
00254 // Test setup
00255 utest::v1::status_t test_setup(const size_t number_of_cases) {
00256     GREENTEA_SETUP(120, "udp_echo");
00257     return verbose_test_setup_handler(number_of_cases);
00258 }
00259 
00260 Case cases[] = {
00261     Case("UDP packet pressure", test_udp_packet_pressure),
00262 };
00263 
00264 Specification specification(test_setup, cases);
00265 
00266 int main() {
00267     return !Harness::run(specification);
00268 }