Version of easy-connect with the u-blox cellular platforms C027 and C030 added.
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 #ifndef MBED_EXTENDED_TESTS 00002 #error [NOT_SUPPORTED] Parallel pressure tests are not supported by default 00003 #endif 00004 00005 #include "mbed.h" 00006 #include "ESP8266Interface.h" 00007 #include "UDPSocket.h" 00008 #include "greentea-client/test_env.h" 00009 #include "unity/unity.h" 00010 #include "utest.h" 00011 00012 using namespace utest::v1; 00013 00014 00015 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 00016 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64 00017 #endif 00018 00019 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 00020 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000 00021 #endif 00022 00023 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 00024 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100 00025 #endif 00026 00027 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 00028 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 00029 #endif 00030 00031 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 00032 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 3 00033 #endif 00034 00035 #ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG 00036 #define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false 00037 #endif 00038 00039 #ifndef MBED_CFG_ESP8266_TX 00040 #define MBED_CFG_ESP8266_TX D1 00041 #endif 00042 00043 #ifndef MBED_CFG_ESP8266_RX 00044 #define MBED_CFG_ESP8266_RX D0 00045 #endif 00046 00047 #ifndef MBED_CFG_ESP8266_DEBUG 00048 #define MBED_CFG_ESP8266_DEBUG false 00049 #endif 00050 00051 #define STRINGIZE(x) STRINGIZE2(x) 00052 #define STRINGIZE2(x) #x 00053 00054 00055 // Simple xorshift pseudorandom number generator 00056 class RandSeq { 00057 private: 00058 uint32_t x; 00059 uint32_t y; 00060 static const int A = 15; 00061 static const int B = 18; 00062 static const int C = 11; 00063 00064 public: 00065 RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) 00066 : x(seed), y(seed) {} 00067 00068 uint32_t next(void) { 00069 x ^= x << A; 00070 x ^= x >> B; 00071 x ^= y ^ (y >> C); 00072 return x + y; 00073 } 00074 00075 void skip(size_t size) { 00076 for (size_t i = 0; i < size; i++) { 00077 next(); 00078 } 00079 } 00080 00081 void buffer(uint8_t *buffer, size_t size) { 00082 RandSeq lookahead = *this; 00083 00084 for (size_t i = 0; i < size; i++) { 00085 buffer[i] = lookahead.next() & 0xff; 00086 } 00087 } 00088 00089 int cmp(uint8_t *buffer, size_t size) { 00090 RandSeq lookahead = *this; 00091 00092 for (size_t i = 0; i < size; i++) { 00093 int diff = buffer[i] - (lookahead.next() & 0xff); 00094 if (diff != 0) { 00095 return diff; 00096 } 00097 } 00098 return 0; 00099 } 00100 }; 00101 00102 // Tries to get the biggest buffer possible on the device. Exponentially 00103 // grows a buffer until heap runs out of space, and uses half to leave 00104 // space for the rest of the program 00105 void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { 00106 size_t i = min; 00107 while (i < max) { 00108 void *b = malloc(i); 00109 if (!b) { 00110 i /= 8; 00111 if (i < min) { 00112 i = min; 00113 } 00114 break; 00115 } 00116 free(b); 00117 i *= 2; 00118 } 00119 00120 *buffer = (uint8_t *)malloc(i); 00121 *size = i; 00122 TEST_ASSERT(buffer); 00123 } 00124 00125 00126 // Global variables shared between pressure tests 00127 ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); 00128 SocketAddress udp_addr; 00129 Timer timer; 00130 Mutex iomutex; 00131 00132 // Single instance of a pressure test 00133 class PressureTest { 00134 private: 00135 uint8_t *buffer; 00136 size_t buffer_size; 00137 00138 UDPSocket sock; 00139 Thread thread; 00140 00141 public: 00142 PressureTest(uint8_t *buffer, size_t buffer_size) 00143 : buffer(buffer), buffer_size(buffer_size) { 00144 } 00145 00146 void start() { 00147 osStatus status = thread.start(callback(this, &PressureTest::run)); 00148 TEST_ASSERT_EQUAL(osOK, status); 00149 } 00150 00151 void join() { 00152 osStatus status = thread.join(); 00153 TEST_ASSERT_EQUAL(osOK, status); 00154 } 00155 00156 void run() { 00157 // Tests exponentially growing sequences 00158 for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; 00159 size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; 00160 size *= 2) { 00161 int err = sock.open(&net); 00162 TEST_ASSERT_EQUAL(0, err); 00163 iomutex.lock(); 00164 printf("UDP: %s:%d streaming %d bytes\r\n", 00165 udp_addr.get_ip_address(), udp_addr.get_port(), size); 00166 iomutex.unlock(); 00167 00168 sock.set_blocking(false); 00169 00170 // Loop to send/recv all data 00171 RandSeq tx_seq; 00172 RandSeq rx_seq; 00173 size_t rx_count = 0; 00174 size_t tx_count = 0; 00175 int known_time = timer.read_ms(); 00176 size_t window = buffer_size; 00177 00178 while (tx_count < size || rx_count < size) { 00179 // Send out packets 00180 if (tx_count < size) { 00181 size_t chunk_size = size - tx_count; 00182 if (chunk_size > window) { 00183 chunk_size = window; 00184 } 00185 00186 tx_seq.buffer(buffer, chunk_size); 00187 int td = sock.sendto(udp_addr, buffer, chunk_size); 00188 00189 if (td > 0) { 00190 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00191 iomutex.lock(); 00192 printf("UDP: tx -> %d\r\n", td); 00193 iomutex.unlock(); 00194 } 00195 tx_seq.skip(td); 00196 tx_count += td; 00197 } else if (td != NSAPI_ERROR_WOULD_BLOCK) { 00198 // We may fail to send because of buffering issues, revert to 00199 // last good sequence and cut buffer in half 00200 if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { 00201 window /= 2; 00202 } 00203 00204 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00205 iomutex.lock(); 00206 printf("UDP: Not sent (%d), window = %d\r\n", td, window); 00207 iomutex.unlock(); 00208 } 00209 } 00210 } 00211 00212 // Prioritize recieving over sending packets to avoid flooding 00213 // the network while handling erronous packets 00214 while (rx_count < size) { 00215 int rd = sock.recvfrom(NULL, buffer, buffer_size); 00216 TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); 00217 00218 if (rd > 0) { 00219 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00220 iomutex.lock(); 00221 printf("UDP: rx <- %d\r\n", rd); 00222 iomutex.unlock(); 00223 } 00224 00225 if (rx_seq.cmp(buffer, rd) == 0) { 00226 rx_seq.skip(rd); 00227 rx_count += rd; 00228 known_time = timer.read_ms(); 00229 if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { 00230 window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; 00231 } 00232 } 00233 } else if (timer.read_ms() - known_time > 00234 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { 00235 // Dropped packet or out of order, revert to last good sequence 00236 // and cut buffer in half 00237 tx_seq = rx_seq; 00238 tx_count = rx_count; 00239 known_time = timer.read_ms(); 00240 if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { 00241 window /= 2; 00242 } 00243 00244 if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { 00245 iomutex.lock(); 00246 printf("UDP: Dropped, window = %d\r\n", window); 00247 iomutex.unlock(); 00248 } 00249 } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { 00250 break; 00251 } 00252 } 00253 } 00254 00255 err = sock.close(); 00256 TEST_ASSERT_EQUAL(0, err); 00257 } 00258 } 00259 }; 00260 00261 PressureTest *pressure_tests[MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS]; 00262 00263 00264 void test_udp_packet_pressure_parallel() { 00265 uint8_t *buffer; 00266 size_t buffer_size; 00267 generate_buffer(&buffer, &buffer_size, 00268 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, 00269 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); 00270 00271 size_t buffer_subsize = buffer_size / MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; 00272 printf("MBED: Generated buffer %d\r\n", buffer_size); 00273 printf("MBED: Split into %d buffers %d\r\n", 00274 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS, 00275 buffer_subsize); 00276 00277 int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); 00278 TEST_ASSERT_EQUAL(0, err); 00279 00280 printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); 00281 printf("MBED: UDPClient waiting for server IP and port...\n"); 00282 00283 greentea_send_kv("target_ip", net.get_ip_address()); 00284 00285 char recv_key[] = "host_port"; 00286 char ipbuf[60] = {0}; 00287 char portbuf[16] = {0}; 00288 unsigned int port = 0; 00289 00290 greentea_send_kv("host_ip", " "); 00291 greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); 00292 00293 greentea_send_kv("host_port", " "); 00294 greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); 00295 sscanf(portbuf, "%u", &port); 00296 00297 printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); 00298 udp_addr.set_ip_address(ipbuf); 00299 udp_addr.set_port(port); 00300 00301 timer.start(); 00302 00303 // Startup pressure tests in parallel 00304 for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { 00305 pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); 00306 pressure_tests[i]->start(); 00307 } 00308 00309 for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { 00310 pressure_tests[i]->join(); 00311 delete pressure_tests[i]; 00312 } 00313 00314 timer.stop(); 00315 printf("MBED: Time taken: %fs\r\n", timer.read()); 00316 printf("MBED: Speed: %.3fkb/s\r\n", 00317 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS* 00318 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - 00319 MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); 00320 00321 net.disconnect(); 00322 } 00323 00324 00325 // Test setup 00326 utest::v1::status_t test_setup(const size_t number_of_cases) { 00327 GREENTEA_SETUP(120, "udp_echo"); 00328 return verbose_test_setup_handler(number_of_cases); 00329 } 00330 00331 Case cases[] = { 00332 Case("UDP packet pressure parallel", test_udp_packet_pressure_parallel), 00333 }; 00334 00335 Specification specification(test_setup, cases); 00336 00337 int main() { 00338 return !Harness::run(specification); 00339 } 00340 00341
Generated on Tue Jul 12 2022 15:14:29 by 1.7.2