Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
emac_util.cpp
00001 /* 00002 * Copyright (c) 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 #include "mbed.h" 00019 #include "greentea-client/test_env.h" 00020 #include "unity.h" 00021 #include "utest.h" 00022 00023 #if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET 00024 00025 #include "mbed.h" 00026 00027 #include "EMAC.h" 00028 #include "EMACMemoryManager.h" 00029 #include "emac_TestMemoryManager.h" 00030 00031 #include "emac_tests.h" 00032 #include "emac_initialize.h" 00033 #include "emac_util.h" 00034 #include "emac_membuf.h" 00035 #include "emac_ctp.h" 00036 00037 using namespace utest::v1; 00038 00039 /* For LPC boards define the memory bank ourselves to give us section placement 00040 control */ 00041 #ifndef ETHMEM_SECTION 00042 #if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) 00043 # if defined (__ICCARM__) 00044 # define ETHMEM_SECTION 00045 # elif defined(TOOLCHAIN_GCC_CR) 00046 # define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"))) 00047 # else 00048 # define ETHMEM_SECTION __attribute__((section("AHBSRAM0"),aligned)) 00049 # endif 00050 #elif defined(TARGET_LPC1768) || defined(TARGET_LPC1769) 00051 # if defined (__ICCARM__) 00052 # define ETHMEM_SECTION 00053 # elif defined(TOOLCHAIN_GCC_CR) 00054 # define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32"))) 00055 # else 00056 # define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned)) 00057 # endif 00058 #endif 00059 #endif 00060 00061 #ifndef ETHMEM_SECTION 00062 #define ETHMEM_SECTION 00063 #endif 00064 00065 typedef struct { 00066 int length; 00067 int receipt_number; 00068 unsigned short flags; 00069 unsigned short lifetime; 00070 } outgoing_msg_t; 00071 00072 #define ECHO_SERVER_COUNT 5 00073 00074 #define OUTGOING_MSG_COUNT 100 00075 00076 // Event flags 00077 #define LINK_UP 0x01 00078 #define LINK_DOWN 0x02 00079 00080 // Hook to lwip input function 00081 extern struct netif *netif_list; 00082 00083 // Broadcast address 00084 const unsigned char eth_mac_broadcast_addr[ETH_MAC_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; 00085 00086 // MTU size 00087 static int eth_mtu_size = 0; 00088 00089 // Event queue 00090 static rtos::Semaphore worker_loop_semaphore; 00091 static rtos::Semaphore link_status_semaphore; 00092 00093 #if defined (__ICCARM__) 00094 #pragma location = ".ethusbram" 00095 #endif 00096 ETHMEM_SECTION static EventQueue worker_loop_event_queue(20 * EVENTS_EVENT_SIZE); 00097 00098 static void worker_loop_event_cb(int event); 00099 static Event<void(int)> worker_loop_event(&worker_loop_event_queue, worker_loop_event_cb); 00100 static void link_input_event_cb(void *buf); 00101 static Event<void(void *)> link_input_event(&worker_loop_event_queue, link_input_event_cb); 00102 00103 // Found echo server addresses 00104 static unsigned char eth_mac_echo_server_addr[ECHO_SERVER_COUNT][ETH_MAC_ADDR_LEN]; 00105 static int etc_mac_echo_server_free_index = 0; 00106 00107 static bool output_memory = true; 00108 static bool input_memory = true; 00109 00110 static void (*current_test_step_cb_fnc)(int opt); 00111 00112 // Outgoing messages 00113 static outgoing_msg_t outgoing_msgs[OUTGOING_MSG_COUNT]; 00114 00115 static unsigned int trace_level = 0; 00116 static unsigned int error_flags = 0; 00117 static unsigned int no_response_cnt = 0; 00118 static bool link_up = false; 00119 00120 int emac_if_find_outgoing_msg(int receipt_number) 00121 { 00122 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00123 if (outgoing_msgs[i].length && outgoing_msgs[i].receipt_number == receipt_number) { 00124 return i; 00125 } 00126 } 00127 return -1; 00128 } 00129 00130 void emac_if_free_outgoing_msg(int index) 00131 { 00132 outgoing_msgs[index].length = 0; 00133 } 00134 00135 int emac_if_count_outgoing_msg(void) 00136 { 00137 int count = 0; 00138 00139 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00140 if (outgoing_msgs[i].length) { 00141 00142 if (!(outgoing_msgs[i].flags & RESPONSE_RECEIVED)) { 00143 count++; 00144 } 00145 } 00146 } 00147 00148 return count; 00149 } 00150 00151 void emac_if_reset_outgoing_msg(void) 00152 { 00153 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00154 if (outgoing_msgs[i].length) { 00155 outgoing_msgs[i].length = 0; 00156 } 00157 } 00158 } 00159 00160 int emac_if_add_outgoing_msg(int length) 00161 { 00162 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00163 if (!outgoing_msgs[i].length) { 00164 outgoing_msgs[i].receipt_number = 0; 00165 outgoing_msgs[i].length = length; 00166 outgoing_msgs[i].flags = 0; 00167 outgoing_msgs[i].lifetime = 10; 00168 return i; 00169 } 00170 } 00171 return -1; 00172 } 00173 00174 void emac_if_set_outgoing_msg_receipt_num(int index, int receipt_number) 00175 { 00176 outgoing_msgs[index].receipt_number = receipt_number; 00177 } 00178 00179 void emac_if_set_outgoing_msg_flags(int index, int flags) 00180 { 00181 outgoing_msgs[index].flags |= flags; 00182 } 00183 00184 void emac_if_timeout_outgoing_msg(void) 00185 { 00186 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00187 if (outgoing_msgs[i].length) { 00188 if (outgoing_msgs[i].lifetime) { 00189 outgoing_msgs[i].lifetime--; 00190 if (outgoing_msgs[i].lifetime == 0) { 00191 SET_ERROR_FLAGS(NO_RESPONSE); 00192 } 00193 } 00194 } 00195 } 00196 } 00197 00198 void emac_if_validate_outgoing_msg(void) 00199 { 00200 static char broadcast_resp_count = 0; 00201 00202 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00203 if (outgoing_msgs[i].length) { 00204 00205 if (outgoing_msgs[i].flags & RESPONSE_RECEIVED) { 00206 00207 int failure = outgoing_msgs[i].flags & (INVALID_LENGHT | INVALID_DATA); 00208 00209 if (failure) { 00210 SET_ERROR_FLAGS(MSG_VALID_ERROR); 00211 } 00212 00213 if (!(outgoing_msgs[i].flags & PRINTED)) { 00214 if ((trace_level & TRACE_SUCCESS) || ((trace_level & TRACE_FAILURE) && failure)) { 00215 printf("response: receipt number %i %s %s %s\r\n\r\n", outgoing_msgs[i].receipt_number, 00216 outgoing_msgs[i].flags & INVALID_LENGHT ? "LENGTH INVALID" : "LENGTH OK", 00217 outgoing_msgs[i].flags & INVALID_DATA ? "DATA INVALID" : "DATA OK", 00218 outgoing_msgs[i].flags & BROADCAST ? "BROADCAST" : "UNICAST"); 00219 outgoing_msgs[i].flags |= PRINTED; 00220 } 00221 } 00222 00223 if (outgoing_msgs[i].flags & BROADCAST) { 00224 outgoing_msgs[i].lifetime = 2; 00225 broadcast_resp_count++; 00226 if (broadcast_resp_count > 5) { 00227 emac_if_free_outgoing_msg(i); 00228 } 00229 } else { 00230 emac_if_free_outgoing_msg(i); 00231 } 00232 } 00233 00234 if (!outgoing_msgs[i].lifetime) { 00235 if (!(outgoing_msgs[i].flags & RESPONSE_RECEIVED) && (trace_level & TRACE_FAILURE)) { 00236 printf("NO RESPONSE: receipt number %i\r\n\r\n", outgoing_msgs[i].receipt_number); 00237 } 00238 emac_if_free_outgoing_msg(i); 00239 } 00240 } 00241 } 00242 } 00243 00244 bool emac_if_update_reply_to_outgoing_msg(int receipt_number, int length, int invalid_data_index) 00245 { 00246 int32_t outgoing_msg_index = emac_if_find_outgoing_msg(receipt_number); 00247 00248 if (outgoing_msg_index >= 0) { 00249 outgoing_msgs[outgoing_msg_index].flags |= RESPONSE_RECEIVED; 00250 00251 if (outgoing_msgs[outgoing_msg_index].length < ETH_FRAME_MIN_LEN) { 00252 /* If length of the sent message is smaller than Ethernet minimum frame length, validates against 00253 minimum frame length or sent length (in case frame has been converted to be longer than minimum 00254 length does not validate length) */ 00255 if (length != ETH_FRAME_MIN_LEN && length != ETH_FRAME_PADD_LEN && outgoing_msgs[outgoing_msg_index].length != length && length < ETH_FRAME_MIN_LEN) { 00256 outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT; 00257 } 00258 } else { 00259 if (outgoing_msgs[outgoing_msg_index].length != length) { 00260 outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT; 00261 } 00262 } 00263 if (invalid_data_index && invalid_data_index < outgoing_msgs[outgoing_msg_index].length) { 00264 outgoing_msgs[outgoing_msg_index].flags |= INVALID_DATA; 00265 } 00266 return true; 00267 } else { 00268 return false; 00269 } 00270 } 00271 00272 void emac_if_add_echo_server_addr(unsigned char *addr) 00273 { 00274 if (etc_mac_echo_server_free_index == ECHO_SERVER_COUNT) { 00275 return; 00276 } 00277 00278 for (int i = 0; i < etc_mac_echo_server_free_index; i++) { 00279 if (memcmp(ð_mac_echo_server_addr[i][0], addr, ETH_MAC_ADDR_LEN) == 0) { 00280 return; 00281 } 00282 } 00283 00284 memcpy(ð_mac_echo_server_addr[etc_mac_echo_server_free_index][0], addr, ETH_MAC_ADDR_LEN); 00285 etc_mac_echo_server_free_index++; 00286 } 00287 00288 int emac_if_count_echo_server_addr(void) 00289 { 00290 return etc_mac_echo_server_free_index; 00291 } 00292 00293 unsigned char *emac_if_get_echo_server_addr(int index) 00294 { 00295 if (index < etc_mac_echo_server_free_index) { 00296 return ð_mac_echo_server_addr[index][0]; 00297 } 00298 00299 return 0; 00300 } 00301 00302 void emac_if_set_error_flags(unsigned int error_flags_value) 00303 { 00304 error_flags |= error_flags_value; 00305 00306 if (error_flags_value & NO_RESPONSE) { 00307 no_response_cnt++; 00308 } 00309 } 00310 00311 unsigned int emac_if_get_error_flags(void) 00312 { 00313 int error_flags_value = error_flags; 00314 00315 // Indicate no response error only if more than three messages are lost 00316 if (error_flags_value & NO_RESPONSE) { 00317 if (no_response_cnt < 3) { 00318 error_flags_value &= ~NO_RESPONSE; 00319 } 00320 } 00321 00322 return error_flags_value; 00323 } 00324 00325 void emac_if_reset_error_flags(unsigned int error_flags_value) 00326 { 00327 error_flags &= ~error_flags_value; 00328 if (error_flags_value & NO_RESPONSE) { 00329 no_response_cnt = 0; 00330 } 00331 } 00332 00333 void emac_if_reset_all_error_flags(void) 00334 { 00335 error_flags = 0; 00336 no_response_cnt = 0; 00337 } 00338 00339 void emac_if_print_error_flags(void) 00340 { 00341 int error_flags_value = emac_if_get_error_flags(); 00342 00343 char no_resp_message[50]; 00344 if (error_flags_value & NO_RESPONSE) { 00345 snprintf(no_resp_message, 50, "no response from echo server, counter: %i", no_response_cnt); 00346 } else if (no_response_cnt > 0) { 00347 printf("no response from echo server, counter: %i\r\n\r\n", no_response_cnt); 00348 } 00349 00350 printf("test result: %s%s%s%s%s%s\r\n\r\n", 00351 error_flags_value ? "Test FAILED, reason: ": "PASS", 00352 error_flags_value & TEST_FAILED ? "test failed ": "", 00353 error_flags_value & MSG_VALID_ERROR ? "message content validation error ": "", 00354 error_flags_value & OUT_OF_MSG_DATA ? "out of message validation data storage ": "", 00355 error_flags_value & NO_FREE_MEM_BUF ? "no free memory buffers ": "", 00356 error_flags_value & NO_RESPONSE ? no_resp_message: ""); 00357 } 00358 00359 void emac_if_set_trace_level(char trace_level_value) 00360 { 00361 trace_level = trace_level_value; 00362 } 00363 00364 char emac_if_get_trace_level(void) 00365 { 00366 return trace_level; 00367 } 00368 00369 void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, unsigned char *data) 00370 { 00371 int line_len = 0; 00372 00373 for (int i = 0; i < len; i++) { 00374 if ((line_len % 14) == 0) { 00375 if (line_len != 0) { 00376 printf("\r\n"); 00377 } 00378 printf("%s %06x", prefix, line_len); 00379 } 00380 line_len++; 00381 printf(" %02x", data[i]); 00382 } 00383 printf("\r\n\r\n"); 00384 } 00385 00386 void emac_if_set_all_multicast(bool all) 00387 { 00388 emac_if_get()->set_all_multicast(all); 00389 } 00390 00391 void emac_if_add_multicast_group(uint8_t *address) 00392 { 00393 emac_if_get()->add_multicast_group(address); 00394 } 00395 00396 void emac_if_set_output_memory(bool memory) 00397 { 00398 output_memory = memory; 00399 } 00400 00401 void emac_if_set_input_memory(bool memory) 00402 { 00403 input_memory = memory; 00404 00405 emac_if_set_memory(memory); 00406 } 00407 00408 void emac_if_check_memory(bool output) 00409 { 00410 if (output) { 00411 emac_if_set_memory(output_memory); 00412 } else { 00413 emac_if_set_memory(input_memory); 00414 } 00415 } 00416 00417 void emac_if_set_memory(bool memory) 00418 { 00419 static bool memory_value = true; 00420 if (memory_value != memory ) { 00421 memory_value = memory; 00422 EmacTestMemoryManager *mem_mngr = emac_m_mngr_get(); 00423 mem_mngr->set_memory_available(memory); 00424 } 00425 } 00426 00427 void emac_if_link_state_change_cb(bool up) 00428 { 00429 if (up) { 00430 worker_loop_event.post(LINK_UP); 00431 } else { 00432 worker_loop_event.post(LINK_DOWN); 00433 } 00434 } 00435 00436 void emac_if_link_input_cb(void *buf) 00437 { 00438 link_input_event.post(buf); 00439 } 00440 00441 static void link_input_event_cb(void *buf) 00442 { 00443 int length = emac_m_mngr_get()->get_total_len(buf); 00444 00445 if (length >= ETH_FRAME_HEADER_LEN) { 00446 // Ethernet input frame 00447 unsigned char eth_input_frame_data[ETH_FRAME_HEADER_LEN]; 00448 memset(eth_input_frame_data, 0, ETH_FRAME_HEADER_LEN); 00449 00450 int invalid_data_index = emac_if_memory_buffer_read(buf, eth_input_frame_data); 00451 00452 if (eth_input_frame_data[12] == 0x90 && eth_input_frame_data[13] == 0x00) { 00453 unsigned char eth_output_frame_data[ETH_FRAME_HEADER_LEN]; 00454 int receipt_number; 00455 00456 ctp_function function = emac_if_ctp_header_handle(eth_input_frame_data, eth_output_frame_data, emac_if_get_hw_addr(), &receipt_number); 00457 00458 if (function == CTP_REPLY) { 00459 // If reply has valid receipt number 00460 if (emac_if_update_reply_to_outgoing_msg(receipt_number, length, invalid_data_index)) { 00461 // Checks received messages for errors 00462 emac_if_validate_outgoing_msg(); 00463 // Removes not replied retry entries if any 00464 emac_if_reset_outgoing_msg(); 00465 // Removes retry entries no response flags 00466 emac_if_reset_error_flags(NO_RESPONSE); 00467 // Calls test loop 00468 worker_loop_event_queue.call(current_test_step_cb_fnc, INPUT); 00469 } 00470 #if MBED_CONF_APP_ECHO_SERVER 00471 // Echoes only if configured as echo server 00472 } else if (function == CTP_FORWARD) { 00473 emac_if_memory_buffer_write(buf, eth_output_frame_data, false); 00474 emac_if_get()->link_out(buf); 00475 buf = 0; 00476 #endif 00477 } 00478 00479 emac_if_add_echo_server_addr(ð_input_frame_data[6]); 00480 00481 if (trace_level & TRACE_ETH_FRAMES) { 00482 printf("INP> LEN %i\r\n\r\n", length); 00483 const char trace_type[] = "INP>"; 00484 emac_if_trace_to_ascii_hex_dump(trace_type, ETH_FRAME_HEADER_LEN, eth_input_frame_data); 00485 } 00486 } 00487 } 00488 00489 if (buf) { 00490 emac_m_mngr_get()->free(buf); 00491 } 00492 } 00493 00494 00495 #if defined (__ICCARM__) 00496 #pragma location = ".ethusbram" 00497 #endif 00498 ETHMEM_SECTION static unsigned char thread_stack[2048]; 00499 00500 void worker_loop(void); 00501 00502 void worker_loop_init(void) 00503 { 00504 static rtos::Thread worker_loop_thread(osPriorityNormal, 2048, thread_stack); 00505 00506 static bool init_done = false; 00507 00508 if (!init_done) { 00509 if (worker_loop_thread.get_state() == Thread::Deleted) { 00510 worker_loop_thread.start(mbed::callback(&worker_loop)); 00511 } 00512 init_done = true; 00513 } 00514 } 00515 00516 void worker_loop_start(void (*test_step_cb_fnc)(int opt), int timeout) 00517 { 00518 current_test_step_cb_fnc = test_step_cb_fnc; 00519 00520 int test_step_cb_timer = worker_loop_event_queue.call_every(timeout, test_step_cb_fnc, TIMEOUT); 00521 int timeout_outgoing_msg_timer = worker_loop_event_queue.call_every(1000, emac_if_timeout_outgoing_msg); 00522 00523 int validate_outgoing_msg_timer = 0; 00524 if (timeout > 500) { 00525 // For long test step callback timeouts validates messages also between callback timeouts 00526 validate_outgoing_msg_timer = worker_loop_event_queue.call_every(200, emac_if_validate_outgoing_msg); 00527 } 00528 00529 #if MBED_CONF_APP_ECHO_SERVER 00530 worker_loop_semaphore.wait(); 00531 #else 00532 worker_loop_semaphore.wait(600 * SECOND_TO_MS); 00533 #endif 00534 00535 worker_loop_event_queue.cancel(test_step_cb_timer); 00536 worker_loop_event_queue.cancel(timeout_outgoing_msg_timer); 00537 if (validate_outgoing_msg_timer) { 00538 worker_loop_event_queue.cancel(validate_outgoing_msg_timer); 00539 } 00540 00541 osDelay(1000); 00542 } 00543 00544 static void worker_loop_event_cb(int event) 00545 { 00546 if (event == LINK_UP) { 00547 link_up = true; 00548 link_status_semaphore.release(); 00549 } 00550 00551 if (event == LINK_DOWN) { 00552 link_up = false; 00553 } 00554 } 00555 00556 void worker_loop_link_up_wait(void) 00557 { 00558 if (!link_up) { 00559 link_status_semaphore.wait(); 00560 } 00561 } 00562 00563 void worker_loop_end(void) 00564 { 00565 worker_loop_semaphore.release(); 00566 } 00567 00568 void worker_loop(void) 00569 { 00570 worker_loop_event_queue.dispatch_forever(); 00571 } 00572 00573 unsigned char *emac_if_get_own_addr(void) 00574 { 00575 return (emac_if_get_hw_addr()); 00576 } 00577 00578 int emac_if_get_mtu_size() 00579 { 00580 return eth_mtu_size; 00581 } 00582 00583 void emac_if_set_mtu_size(int mtu_size) 00584 { 00585 eth_mtu_size = mtu_size; 00586 } 00587 00588 #endif
Generated on Tue Jul 12 2022 12:43:54 by
1.7.2