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] Parallel pressure tests are not supported by default
00024 #endif
00025 
00026 #include "mbed.h"
00027 #include MBED_CONF_APP_HEADER_FILE
00028 #include "TCPSocket.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_TCP_CLIENT_PACKET_PRESSURE_MIN
00037 #define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64
00038 #endif
00039 
00040 #ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX
00041 #define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000
00042 #endif
00043 
00044 #ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED
00045 #define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
00046 #endif
00047 
00048 #ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS
00049 #define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS 3
00050 #endif
00051 
00052 #ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG
00053 #define MBED_CFG_TCP_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_TCP_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 
00108 // Tries to get the biggest buffer possible on the device. Exponentially
00109 // grows a buffer until heap runs out of space, and uses half to leave
00110 // space for the rest of the program
00111 void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
00112     size_t i = min;
00113     while (i < max) {
00114         void *b = malloc(i);
00115         if (!b) {
00116             i /= 4;
00117             if (i < min) {
00118                 i = min;
00119             }
00120             break;
00121         }
00122         free(b);
00123         i *= 2;
00124     }
00125 
00126     *buffer = (uint8_t *)malloc(i);
00127     *size = i;
00128     TEST_ASSERT(buffer);
00129 }
00130 
00131 
00132 // Global variables shared between pressure tests
00133 NetworkInterface* net;
00134 SocketAddress tcp_addr;
00135 Timer timer;
00136 Mutex iomutex;
00137 
00138 // Single instance of a pressure test
00139 class PressureTest {
00140 private:
00141     uint8_t *buffer;
00142     size_t buffer_size;
00143 
00144     TCPSocket sock;
00145     Thread thread;
00146 
00147 public:
00148     PressureTest(uint8_t *buffer, size_t buffer_size)
00149         : buffer(buffer), buffer_size(buffer_size) {
00150     }
00151 
00152     void start() {
00153         osStatus status = thread.start(callback(this, &PressureTest::run));
00154         TEST_ASSERT_EQUAL(osOK, status);
00155     }
00156 
00157     void join() {
00158         osStatus status = thread.join();
00159         TEST_ASSERT_EQUAL(osOK, status);
00160     }
00161 
00162     void run() {
00163         // Tests exponentially growing sequences
00164         for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN;
00165              size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX;
00166              size *= 2) {
00167             int err = sock.open(net);
00168             TEST_ASSERT_EQUAL(0, err);
00169             err = sock.connect(tcp_addr);
00170             TEST_ASSERT_EQUAL(0, err);
00171             sock.recv(buffer, sizeof(MBED_CONF_APP_TCP_ECHO_PREFIX));
00172 
00173             iomutex.lock();
00174             printf("TCP: %s:%d streaming %d bytes\r\n",
00175                 tcp_addr.get_ip_address(), tcp_addr.get_port(), size);
00176             iomutex.unlock();
00177 
00178             sock.set_blocking(false);
00179 
00180             // Loop to send/recv all data
00181             RandSeq tx_seq;
00182             RandSeq rx_seq;
00183             size_t rx_count = 0;
00184             size_t tx_count = 0;
00185             size_t window = buffer_size;
00186 
00187             while (tx_count < size || rx_count < size) {
00188                 // Send out data
00189                 if (tx_count < size) {
00190                     size_t chunk_size = size - tx_count;
00191                     if (chunk_size > window) {
00192                         chunk_size = window;
00193                     }
00194 
00195                     tx_seq.buffer(buffer, chunk_size);
00196                     int td = sock.send(buffer, chunk_size);
00197 
00198                     if (td > 0) {
00199                         if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
00200                             iomutex.lock();
00201                             printf("TCP: tx -> %d\r\n", td);
00202                             iomutex.unlock();
00203                         }
00204                         tx_seq.skip(td);
00205                         tx_count += td;
00206                     } else if (td != NSAPI_ERROR_WOULD_BLOCK ) {
00207                         // We may fail to send because of buffering issues,
00208                         // cut buffer in half
00209                         if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) {
00210                             window /= 2;
00211                         }
00212 
00213                         if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
00214                             iomutex.lock();
00215                             printf("TCP: Not sent (%d), window = %d\r\n", td, window);
00216                             iomutex.unlock();
00217                         }
00218                     }
00219                 }
00220 
00221                 // Verify recieved data
00222                 while (rx_count < size) {
00223                     int rd = sock.recv(buffer, buffer_size);
00224                     TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK );
00225                     if (rd > 0) {
00226                         if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
00227                             iomutex.lock();
00228                             printf("TCP: rx <- %d\r\n", rd);
00229                             iomutex.unlock();
00230                         }
00231                         int diff = rx_seq.cmp(buffer, rd);
00232                         TEST_ASSERT_EQUAL(0, diff);
00233                         rx_seq.skip(rd);
00234                         rx_count += rd;
00235                     } else if (rd == NSAPI_ERROR_WOULD_BLOCK ) {
00236                         break;
00237                     }
00238                 }
00239             }
00240 
00241             err = sock.close();
00242             TEST_ASSERT_EQUAL(0, err);
00243         }
00244     }
00245 };
00246 
00247 PressureTest *pressure_tests[MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS];
00248 
00249 
00250 void test_tcp_packet_pressure_parallel() {
00251     uint8_t *buffer;
00252     size_t buffer_size;
00253     generate_buffer(&buffer, &buffer_size,
00254         MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN,
00255         MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX);
00256 
00257     size_t buffer_subsize = buffer_size / MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS;
00258     printf("MBED: Generated buffer %d\r\n", buffer_size);
00259     printf("MBED: Split into %d buffers %d\r\n",
00260             MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS,
00261             buffer_subsize);
00262 
00263     net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
00264     int err =  MBED_CONF_APP_CONNECT_STATEMENT;
00265     TEST_ASSERT_EQUAL(0, err);
00266 
00267     printf("MBED: TCPClient IP address is '%s'\n", net->get_ip_address());
00268 
00269     tcp_addr.set_ip_address(MBED_CONF_APP_ECHO_SERVER_ADDR);
00270     tcp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
00271 
00272     timer.start();
00273 
00274     // Startup pressure tests in parallel
00275     for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
00276         pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize);
00277         pressure_tests[i]->start();
00278     }
00279 
00280     for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
00281         pressure_tests[i]->join();
00282         delete pressure_tests[i];
00283     }
00284 
00285     timer.stop();
00286     printf("MBED: Time taken: %fs\r\n", timer.read());
00287     printf("MBED: Speed: %.3fkb/s\r\n",
00288             MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS*
00289             8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX -
00290             MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
00291 
00292     net->disconnect();
00293 }
00294 
00295 
00296 // Test setup
00297 utest::v1::status_t test_setup(const size_t number_of_cases) {
00298     GREENTEA_SETUP(120, "tcp_echo");
00299     return verbose_test_setup_handler(number_of_cases);
00300 }
00301 
00302 Case cases[] = {
00303     Case("TCP packet pressure parallel", test_tcp_packet_pressure_parallel),
00304 };
00305 
00306 Specification specification(test_setup, cases);
00307 
00308 int main() {
00309     return !Harness::run(specification);
00310 }