Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 "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_THREADS 00053 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 3 00054 #endif 00055 00056 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG 00057 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false 00058 #endif 00059 00060 #define STRINGIZE(x) STRINGIZE2(x) 00061 #define STRINGIZE2(x) #x 00062 00063 00064 // Simple xorshift pseudorandom number generator 00065 class RandSeq { 00066 private: 00067 uint32_t x; 00068 uint32_t y; 00069 static const int A = 15; 00070 static const int B = 18; 00071 static const int C = 11; 00072 00073 public: 00074 RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) 00075 : x(seed), y(seed) {} 00076 00077 uint32_t next(void) { 00078 x ^= x << A; 00079 x ^= x >> B; 00080 x ^= y ^ (y >> C); 00081 return x + y; 00082 } 00083 00084 void skip(size_t size) { 00085 for (size_t i = 0; i < size; i++) { 00086 next(); 00087 } 00088 } 00089 00090 void buffer(uint8_t *buffer, size_t size) { 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 RandSeq lookahead = *this; 00100 00101 for (size_t i = 0; i < size; i++) { 00102 int diff = buffer[i] - (lookahead.next() & 0xff); 00103 if (diff != 0) { 00104 return diff; 00105 } 00106 } 00107 return 0; 00108 } 00109 }; 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 /= 8; 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 00135 // Global variables shared between pressure tests 00136 NetworkInterface* net; 00137 SocketAddress udp_addr; 00138 Timer timer; 00139 Mutex iomutex; 00140 00141 // Single instance of a pressure test 00142 class PressureTest { 00143 private: 00144 uint8_t *buffer; 00145 size_t buffer_size; 00146 00147 UDPSocket sock; 00148 Thread thread; 00149 00150 public: 00151 PressureTest(uint8_t *buffer, size_t buffer_size) 00152 : buffer(buffer), buffer_size(buffer_size) { 00153 } 00154 00155 void start() { 00156 osStatus status = thread.start(callback(this, &PressureTest::run)); 00157 TEST_ASSERT_EQUAL(osOK, status); 00158 } 00159 00160 void join() { 00161 osStatus status = thread.join(); 00162 TEST_ASSERT_EQUAL(osOK, status); 00163 } 00164 00165 void run() { 00166 // Tests exponentially growing sequences 00167 for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; 00168 size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; 00169 size *= 2) { 00170 int err = sock.open(net); 00171 TEST_ASSERT_EQUAL(0, err); 00172 iomutex.lock(); 00173 printf("UDP: %s:%d streaming %d bytes\r\n", 00174 udp_addr.get_ip_address(), udp_addr.get_port(), size); 00175 iomutex.unlock(); 00176 00177 sock.set_blocking(false); 00178 00179 // Loop to send/recv all data 00180 RandSeq tx_seq; 00181 RandSeq rx_seq; 00182 size_t rx_count = 0; 00183 size_t tx_count = 0; 00184 int known_time = timer.read_ms(); 00185 size_t window = buffer_size; 00186 00187 while (tx_count < size || rx_count < size) { 00188 // Send out packets 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.sendto(udp_addr, buffer, chunk_size); 00197 00198 if (td > 0) { 00199 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00200 iomutex.lock(); 00201 printf("UDP: 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, revert to 00208 // last good sequence and cut buffer in half 00209 if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { 00210 window /= 2; 00211 } 00212 00213 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00214 iomutex.lock(); 00215 printf("UDP: Not sent (%d), window = %d\r\n", td, window); 00216 iomutex.unlock(); 00217 } 00218 } 00219 } 00220 00221 // Prioritize recieving over sending packets to avoid flooding 00222 // the network while handling erronous packets 00223 while (rx_count < size) { 00224 int rd = sock.recvfrom(NULL, buffer, buffer_size); 00225 TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK ); 00226 00227 if (rd > 0) { 00228 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00229 iomutex.lock(); 00230 printf("UDP: rx <- %d\r\n", rd); 00231 iomutex.unlock(); 00232 } 00233 00234 if (rx_seq.cmp(buffer, rd) == 0) { 00235 rx_seq.skip(rd); 00236 rx_count += rd; 00237 known_time = timer.read_ms(); 00238 if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { 00239 window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; 00240 } 00241 } 00242 } else if (timer.read_ms() - known_time > 00243 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { 00244 // Dropped packet or out of order, revert to last good sequence 00245 // and cut buffer in half 00246 tx_seq = rx_seq; 00247 tx_count = rx_count; 00248 known_time = timer.read_ms(); 00249 if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { 00250 window /= 2; 00251 } 00252 00253 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00254 iomutex.lock(); 00255 printf("UDP: Dropped, window = %d\r\n", window); 00256 iomutex.unlock(); 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 }; 00269 00270 PressureTest *pressure_tests[MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS]; 00271 00272 00273 void test_udp_packet_pressure_parallel() { 00274 uint8_t *buffer; 00275 size_t buffer_size; 00276 generate_buffer(&buffer, &buffer_size, 00277 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, 00278 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); 00279 00280 size_t buffer_subsize = buffer_size / MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; 00281 printf("MBED: Generated buffer %d\r\n", buffer_size); 00282 printf("MBED: Split into %d buffers %d\r\n", 00283 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS, 00284 buffer_subsize); 00285 00286 net = MBED_CONF_APP_OBJECT_CONSTRUCTION; 00287 int err = MBED_CONF_APP_CONNECT_STATEMENT; 00288 TEST_ASSERT_EQUAL(0, err); 00289 00290 printf("MBED: UDPClient IP address is '%s'\n", net->get_ip_address()); 00291 00292 udp_addr.set_ip_address(MBED_CONF_APP_ECHO_SERVER_ADDR); 00293 udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT); 00294 00295 timer.start(); 00296 00297 // Startup pressure tests in parallel 00298 for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { 00299 pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); 00300 pressure_tests[i]->start(); 00301 } 00302 00303 for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { 00304 pressure_tests[i]->join(); 00305 delete pressure_tests[i]; 00306 } 00307 00308 timer.stop(); 00309 printf("MBED: Time taken: %fs\r\n", timer.read()); 00310 printf("MBED: Speed: %.3fkb/s\r\n", 00311 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS* 00312 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - 00313 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); 00314 00315 net->disconnect(); 00316 } 00317 00318 00319 // Test setup 00320 utest::v1::status_t test_setup(const size_t number_of_cases) { 00321 GREENTEA_SETUP(120, "udp_echo"); 00322 return verbose_test_setup_handler(number_of_cases); 00323 } 00324 00325 Case cases[] = { 00326 Case("UDP packet pressure parallel", test_udp_packet_pressure_parallel), 00327 }; 00328 00329 Specification specification(test_setup, cases); 00330 00331 int main() { 00332 return !Harness::run(specification); 00333 }
Generated on Sun Jul 17 2022 08:25:27 by
1.7.2