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