BA / SerialCom

Fork of OmniWheels by Gustav Atmel

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_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN
00037 #define MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN 64
00038 #endif
00039 
00040 #ifndef MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX
00041 #define MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000
00042 #endif
00043 
00044 #ifndef MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT
00045 #define MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100
00046 #endif
00047 
00048 #ifndef MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_SEED
00049 #define MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
00050 #endif
00051 
00052 #ifndef MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_DEBUG
00053 #define MBED_CONF_APP_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 {
00063 private:
00064     uint32_t x;
00065     uint32_t y;
00066     static const int A = 15;
00067     static const int B = 18;
00068     static const int C = 11;
00069 
00070 public:
00071     RandSeq(uint32_t seed = MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_SEED)
00072         : x(seed), y(seed) {}
00073 
00074     uint32_t next(void)
00075     {
00076         x ^= x << A;
00077         x ^= x >> B;
00078         x ^= y ^ (y >> C);
00079         return x + y;
00080     }
00081 
00082     void skip(size_t size)
00083     {
00084         for (size_t i = 0; i < size; i++) {
00085             next();
00086         }
00087     }
00088 
00089     void buffer(uint8_t *buffer, size_t size)
00090     {
00091         RandSeq lookahead = *this;
00092 
00093         for (size_t i = 0; i < size; i++) {
00094             buffer[i] = lookahead.next() & 0xff;
00095         }
00096     }
00097 
00098     int cmp(uint8_t *buffer, size_t size)
00099     {
00100         RandSeq lookahead = *this;
00101 
00102         for (size_t i = 0; i < size; i++) {
00103             int diff = buffer[i] - (lookahead.next() & 0xff);
00104             if (diff != 0) {
00105                 return diff;
00106             }
00107         }
00108         return 0;
00109     }
00110 };
00111 
00112 // Shared buffer for network transactions
00113 uint8_t *buffer;
00114 size_t buffer_size;
00115 
00116 // Tries to get the biggest buffer possible on the device. Exponentially
00117 // grows a buffer until heap runs out of space, and uses half to leave
00118 // space for the rest of the program
00119 void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max)
00120 {
00121     size_t i = min;
00122     while (i < max) {
00123         void *b = malloc(i);
00124         if (!b) {
00125             i /= 4;
00126             if (i < min) {
00127                 i = min;
00128             }
00129             break;
00130         }
00131         free(b);
00132         i *= 2;
00133     }
00134 
00135     *buffer = (uint8_t *)malloc(i);
00136     *size = i;
00137     TEST_ASSERT(buffer);
00138 }
00139 
00140 void test_udp_packet_pressure()
00141 {
00142     generate_buffer(&buffer, &buffer_size,
00143                     MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN,
00144                     MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX);
00145     printf("MBED: Generated buffer %d\r\n", buffer_size);
00146 
00147     NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
00148     int err =  MBED_CONF_APP_CONNECT_STATEMENT;
00149     TEST_ASSERT_EQUAL(0, err);
00150 
00151     printf("MBED: UDPClient IP address is '%s'\n", net->get_ip_address());
00152 
00153     UDPSocket sock;
00154 #if defined(MBED_CONF_APP_ECHO_SERVER_ADDR) && defined(MBED_CONF_APP_ECHO_SERVER_PORT)
00155     SocketAddress udp_addr(MBED_CONF_APP_ECHO_SERVER_ADDR, MBED_CONF_APP_ECHO_SERVER_PORT);
00156 #else /* MBED_CONF_APP_ECHO_SERVER_ADDR && MBED_CONF_APP_ECHO_SERVER_PORT */
00157     char recv_key[] = "host_port";
00158     char ipbuf[60] = {0};
00159     char portbuf[16] = {0};
00160     unsigned int port = 0;
00161 
00162     greentea_send_kv("target_ip", net->get_ip_address());
00163     greentea_send_kv("host_ip", " ");
00164     greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
00165 
00166     greentea_send_kv("host_port", " ");
00167     greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
00168     sscanf(portbuf, "%u", &port);
00169 
00170     SocketAddress udp_addr(ipbuf, port);
00171 #endif /* MBED_CONF_APP_ECHO_SERVER_ADDR && MBED_CONF_APP_ECHO_SERVER_PORT */
00172 
00173     Timer timer;
00174     timer.start();
00175 
00176     // Tests exponentially growing sequences
00177     for (size_t size = MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN;
00178             size < MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX;
00179             size *= 2) {
00180         err = sock.open(net);
00181         TEST_ASSERT_EQUAL(0, err);
00182         printf("UDP: %s:%d streaming %d bytes\r\n",
00183                udp_addr.get_ip_address(), udp_addr.get_port(), size);
00184 
00185         sock.set_blocking(false);
00186 
00187         // Loop to send/recv all data
00188         RandSeq tx_seq;
00189         RandSeq rx_seq;
00190         size_t rx_count = 0;
00191         size_t tx_count = 0;
00192         int known_time = timer.read_ms();
00193         size_t window = buffer_size;
00194 
00195         while (tx_count < size || rx_count < size) {
00196             // Send out packets
00197             if (tx_count < size) {
00198                 size_t chunk_size = size - tx_count;
00199                 if (chunk_size > window) {
00200                     chunk_size = window;
00201                 }
00202 
00203                 tx_seq.buffer(buffer, chunk_size);
00204                 int td = sock.sendto(udp_addr, buffer, chunk_size);
00205 
00206                 if (td > 0) {
00207                     if (MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00208                         printf("UDP: tx -> %d\r\n", td);
00209                     }
00210                     tx_seq.skip(td);
00211                     tx_count += td;
00212                 } else if (td != NSAPI_ERROR_WOULD_BLOCK ) {
00213                     // We may fail to send because of buffering issues, revert to
00214                     // last good sequence and cut buffer in half
00215                     if (window > MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN) {
00216                         window /= 2;
00217                     }
00218 
00219                     if (MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00220                         printf("UDP: Not sent (%d), window = %d\r\n", td, window);
00221                     }
00222                 }
00223             }
00224 
00225             // Prioritize receiving over sending packets to avoid flooding
00226             // the network while handling erronous packets
00227             while (rx_count < size) {
00228                 int rd = sock.recvfrom(NULL, buffer, buffer_size);
00229                 TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK );
00230 
00231                 if (rd > 0) {
00232                     if (MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00233                         printf("UDP: rx <- %d\r\n", rd);
00234                     }
00235 
00236                     if (rx_seq.cmp(buffer, rd) == 0) {
00237                         rx_seq.skip(rd);
00238                         rx_count += rd;
00239                         known_time = timer.read_ms();
00240                         if (window < MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX) {
00241                             window += MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN;
00242                         }
00243                     }
00244                 } else if (timer.read_ms() - known_time >
00245                            MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) {
00246                     // Dropped packet or out of order, revert to last good sequence
00247                     // and cut buffer in half
00248                     tx_seq = rx_seq;
00249                     tx_count = rx_count;
00250                     known_time = timer.read_ms();
00251                     if (window > MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN) {
00252                         window /= 2;
00253                     }
00254 
00255                     if (MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
00256                         printf("UDP: Dropped, window = %d\r\n", window);
00257                     }
00258                 } else if (rd == NSAPI_ERROR_WOULD_BLOCK ) {
00259                     break;
00260                 }
00261             }
00262         }
00263 
00264         err = sock.close();
00265         TEST_ASSERT_EQUAL(0, err);
00266     }
00267 
00268     timer.stop();
00269     printf("MBED: Time taken: %fs\r\n", timer.read());
00270     printf("MBED: Speed: %.3fkb/s\r\n",
00271            8 * (2 * MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MAX -
00272                 MBED_CONF_APP_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000 * timer.read()));
00273 
00274     net->disconnect();
00275 }
00276 
00277 
00278 // Test setup
00279 utest::v1::status_t test_setup(const size_t number_of_cases)
00280 {
00281     GREENTEA_SETUP(120, "udp_echo");
00282     return verbose_test_setup_handler(number_of_cases);
00283 }
00284 
00285 Case cases[] = {
00286     Case("UDP packet pressure", test_udp_packet_pressure),
00287 };
00288 
00289 Specification specification(test_setup, cases);
00290 
00291 int main()
00292 {
00293     return !Harness::run(specification);
00294 }