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 extern "C" { // netif input 00026 #include "tcpip.h" 00027 } 00028 00029 #include "emac_api.h" 00030 #include "emac_stack_mem.h" 00031 00032 #include "emac_tests.h" 00033 #include "emac_initialize.h" 00034 #include "emac_util.h" 00035 #include "emac_membuf.h" 00036 #include "emac_ctp.h" 00037 00038 using namespace utest::v1; 00039 00040 typedef struct { 00041 int length; 00042 int receipt_number; 00043 unsigned short flags; 00044 unsigned short lifetime; 00045 } outgoing_msg_t; 00046 00047 #define ECHO_SERVER_COUNT 5 00048 00049 #define OUTGOING_MSG_COUNT 100 00050 00051 // Event flags 00052 #define LINK_UP 0x01 00053 #define LINK_DOWN 0x02 00054 00055 // Hook to lwip input function 00056 extern struct netif *netif_list; 00057 00058 // Broadcast address 00059 const unsigned char eth_mac_broadcast_addr[ETH_MAC_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; 00060 00061 // Event queue 00062 static EventQueue worker_loop_event_queue; 00063 static void worker_loop_event_cb(int event); 00064 static Event<void(int)> worker_loop_event(&worker_loop_event_queue, worker_loop_event_cb); 00065 static void link_input_event_cb(emac_stack_mem_chain_t *mem_chain_p); 00066 static Event<void(emac_stack_mem_chain_t *)> link_input_event(&worker_loop_event_queue, link_input_event_cb); 00067 00068 // Found echo server addresses 00069 static unsigned char eth_mac_echo_server_addr[ECHO_SERVER_COUNT][ETH_MAC_ADDR_LEN]; 00070 static int etc_mac_echo_server_free_index = 0; 00071 00072 // Outgoing messages 00073 static outgoing_msg_t outgoing_msgs[OUTGOING_MSG_COUNT]; 00074 00075 static unsigned int trace_level = 0; 00076 static unsigned int error_flags = 0; 00077 static unsigned int no_response_cnt = 0; 00078 00079 int emac_if_find_outgoing_msg(int receipt_number) 00080 { 00081 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00082 if (outgoing_msgs[i].length && outgoing_msgs[i].receipt_number == receipt_number) { 00083 return i; 00084 } 00085 } 00086 return -1; 00087 } 00088 00089 void emac_if_free_outgoing_msg(int index) 00090 { 00091 outgoing_msgs[index].length = 0; 00092 } 00093 00094 int emac_if_count_outgoing_msg(void) 00095 { 00096 int count = 0; 00097 00098 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00099 if (outgoing_msgs[i].length) { 00100 count++; 00101 } 00102 } 00103 00104 return count; 00105 } 00106 00107 void emac_if_reset_outgoing_msg(void) 00108 { 00109 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00110 if (outgoing_msgs[i].length) { 00111 outgoing_msgs[i].length = 0; 00112 } 00113 } 00114 } 00115 00116 int emac_if_add_outgoing_msg(int length) 00117 { 00118 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00119 if (!outgoing_msgs[i].length) { 00120 outgoing_msgs[i].receipt_number = 0; 00121 outgoing_msgs[i].length = length; 00122 outgoing_msgs[i].flags = 0; 00123 outgoing_msgs[i].lifetime = 10; 00124 return i; 00125 } 00126 } 00127 return -1; 00128 } 00129 00130 void emac_if_set_outgoing_msg_receipt_num(int index, int receipt_number) 00131 { 00132 outgoing_msgs[index].receipt_number = receipt_number; 00133 } 00134 00135 void emac_if_set_outgoing_msg_flags(int index, int flags) 00136 { 00137 outgoing_msgs[index].flags |= flags; 00138 } 00139 00140 void emac_if_timeout_outgoing_msg(void) 00141 { 00142 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00143 if (outgoing_msgs[i].length) { 00144 if (outgoing_msgs[i].lifetime) { 00145 outgoing_msgs[i].lifetime--; 00146 if (outgoing_msgs[i].lifetime == 0) { 00147 SET_ERROR_FLAGS(NO_RESPONSE); 00148 } 00149 } 00150 } 00151 } 00152 } 00153 00154 void emac_if_validate_outgoing_msg(void) 00155 { 00156 static char broadcast_resp_count = 0; 00157 00158 for (int i = 0; i < OUTGOING_MSG_COUNT; i++) { 00159 if (outgoing_msgs[i].length) { 00160 00161 if (outgoing_msgs[i].flags & RESPONSE_RECEIVED) { 00162 00163 int failure = outgoing_msgs[i].flags & (INVALID_LENGHT | INVALID_DATA); 00164 00165 if (failure) { 00166 SET_ERROR_FLAGS(MSG_VALID_ERROR); 00167 } 00168 00169 if (!(outgoing_msgs[i].flags & PRINTED)) { 00170 if ((trace_level & TRACE_SUCCESS) || ((trace_level & TRACE_FAILURE) && failure)) { 00171 printf("response: receipt number %i %s %s %s\r\n\r\n", outgoing_msgs[i].receipt_number, 00172 outgoing_msgs[i].flags & INVALID_LENGHT ? "LENGTH INVALID" : "LENGTH OK", 00173 outgoing_msgs[i].flags & INVALID_DATA ? "DATA INVALID" : "DATA OK", 00174 outgoing_msgs[i].flags & BROADCAST ? "BROADCAST" : "UNICAST"); 00175 outgoing_msgs[i].flags |= PRINTED; 00176 } 00177 } 00178 00179 if (outgoing_msgs[i].flags & BROADCAST) { 00180 outgoing_msgs[i].lifetime = 2; 00181 broadcast_resp_count++; 00182 if (broadcast_resp_count > 5) { 00183 emac_if_free_outgoing_msg(i); 00184 } 00185 } else { 00186 emac_if_free_outgoing_msg(i); 00187 } 00188 } 00189 00190 if (!outgoing_msgs[i].lifetime) { 00191 if (!(outgoing_msgs[i].flags & RESPONSE_RECEIVED) && (trace_level & TRACE_FAILURE)) { 00192 printf("NO RESPONSE: receipt number %i\r\n\r\n", outgoing_msgs[i].receipt_number); 00193 } 00194 emac_if_free_outgoing_msg(i); 00195 } 00196 } 00197 } 00198 } 00199 00200 void emac_if_update_reply_to_outgoing_msg(int receipt_number, int lenght, int invalid_data_index) 00201 { 00202 int32_t outgoing_msg_index = emac_if_find_outgoing_msg(receipt_number); 00203 00204 if (outgoing_msg_index >= 0) { 00205 outgoing_msgs[outgoing_msg_index].flags |= RESPONSE_RECEIVED; 00206 00207 #if MBED_CONF_APP_TEST_ETHERNET 00208 if (outgoing_msgs[outgoing_msg_index].length < ETH_FRAME_MIN_LEN) { 00209 if (lenght != ETH_FRAME_MIN_LEN) { 00210 outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT; 00211 } 00212 } else { 00213 #endif 00214 if (outgoing_msgs[outgoing_msg_index].length != lenght) { 00215 outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT; 00216 } 00217 #if MBED_CONF_APP_TEST_ETHERNET 00218 } 00219 #endif 00220 if (invalid_data_index && invalid_data_index < outgoing_msgs[outgoing_msg_index].length) { 00221 outgoing_msgs[outgoing_msg_index].flags |= INVALID_DATA; 00222 } 00223 } 00224 } 00225 00226 void emac_if_add_echo_server_addr(unsigned char *addr) 00227 { 00228 if (etc_mac_echo_server_free_index == ECHO_SERVER_COUNT) { 00229 return; 00230 } 00231 00232 for (int i = 0; i < etc_mac_echo_server_free_index; i++) { 00233 if (memcmp(ð_mac_echo_server_addr[i][0], addr, ETH_MAC_ADDR_LEN) == 0) { 00234 return; 00235 } 00236 } 00237 00238 memcpy(ð_mac_echo_server_addr[etc_mac_echo_server_free_index][0], addr, ETH_MAC_ADDR_LEN); 00239 etc_mac_echo_server_free_index++; 00240 } 00241 00242 int emac_if_count_echo_server_addr(void) 00243 { 00244 return etc_mac_echo_server_free_index; 00245 } 00246 00247 unsigned char *emac_if_get_echo_server_addr(int index) 00248 { 00249 if (index < etc_mac_echo_server_free_index) { 00250 return ð_mac_echo_server_addr[index][0]; 00251 } 00252 00253 return 0; 00254 } 00255 00256 void emac_if_set_error_flags(unsigned int error_flags_value) 00257 { 00258 error_flags |= error_flags_value; 00259 00260 if (error_flags_value & NO_RESPONSE) { 00261 no_response_cnt++; 00262 } 00263 } 00264 00265 unsigned int emac_if_get_error_flags(void) 00266 { 00267 int error_flags_value = error_flags; 00268 00269 // Indicate no response error only if more than three messages are lost 00270 if (error_flags_value & NO_RESPONSE) { 00271 if (no_response_cnt < 3) { 00272 error_flags_value &= ~NO_RESPONSE; 00273 } 00274 } 00275 00276 return error_flags_value; 00277 } 00278 00279 void emac_if_reset_error_flags(void) 00280 { 00281 error_flags = 0; 00282 no_response_cnt = 0; 00283 } 00284 00285 void emac_if_print_error_flags(void) 00286 { 00287 int error_flags_value = emac_if_get_error_flags(); 00288 00289 char no_resp_message[50]; 00290 if (error_flags_value & NO_RESPONSE) { 00291 snprintf(no_resp_message, 50, "no response from echo server, counter: %i", no_response_cnt); 00292 } else if (no_response_cnt > 0) { 00293 printf("no response from echo server, counter: %i\r\n\r\n", no_response_cnt); 00294 } 00295 00296 printf("test result: %s%s%s%s%s%s\r\n\r\n", 00297 error_flags_value ? "Test FAILED, reason: ": "PASS", 00298 error_flags_value & TEST_FAILED ? "test failed ": "", 00299 error_flags_value & MSG_VALID_ERROR ? "message content validation error ": "", 00300 error_flags_value & OUT_OF_MSG_DATA ? "out of message validation data storage ": "", 00301 error_flags_value & NO_FREE_MEM_BUF ? "no free memory buffers ": "", 00302 error_flags_value & NO_RESPONSE ? no_resp_message: ""); 00303 } 00304 00305 void emac_if_set_trace_level(char trace_level_value) 00306 { 00307 trace_level = trace_level_value; 00308 } 00309 00310 void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, unsigned char *data) 00311 { 00312 int line_len = 0; 00313 00314 for (int i = 0; i < len; i++) { 00315 if ((line_len % 14) == 0) { 00316 if (line_len != 0) { 00317 printf("\r\n"); 00318 } 00319 printf("%s %06x", prefix, line_len); 00320 } 00321 line_len++; 00322 printf(" %02x", data[i]); 00323 } 00324 printf("\r\n\r\n"); 00325 } 00326 00327 void emac_if_link_state_change_cb(void *data, bool up) 00328 { 00329 if (up) { 00330 worker_loop_event.post(LINK_UP); 00331 } else { 00332 worker_loop_event.post(LINK_DOWN); 00333 } 00334 } 00335 00336 void emac_if_link_input_cb(void *data, emac_stack_mem_chain_t *mem_chain_p) 00337 { 00338 link_input_event.post(mem_chain_p); 00339 } 00340 00341 static void link_input_event_cb(emac_stack_mem_chain_t *mem_chain_p) 00342 { 00343 int lenght = emac_stack_mem_len(0, mem_chain_p); 00344 00345 if (lenght >= ETH_FRAME_HEADER_LEN) { 00346 // Ethernet input frame 00347 unsigned char eth_input_frame_data[ETH_FRAME_HEADER_LEN]; 00348 memset(eth_input_frame_data, 0, ETH_FRAME_HEADER_LEN); 00349 00350 int invalid_data_index = emac_if_memory_buffer_read(mem_chain_p, eth_input_frame_data); 00351 00352 if (eth_input_frame_data[12] == 0x90 && eth_input_frame_data[13] == 0x00) { 00353 unsigned char eth_output_frame_data[ETH_FRAME_HEADER_LEN]; 00354 int receipt_number; 00355 00356 ctp_function function = emac_if_ctp_header_handle(eth_input_frame_data, eth_output_frame_data, emac_if_get_hw_addr(), &receipt_number); 00357 00358 if (function == CTP_REPLY) { 00359 emac_if_update_reply_to_outgoing_msg(receipt_number, lenght, invalid_data_index); 00360 #if MBED_CONF_APP_ECHO_SERVER 00361 // Echoes only if configured as echo server 00362 } else if (function == CTP_FORWARD) { 00363 emac_if_memory_buffer_write(mem_chain_p, eth_output_frame_data, false); 00364 emac_if_get()->ops.link_out(emac_if_get(), mem_chain_p); 00365 #endif 00366 } 00367 00368 emac_if_add_echo_server_addr(ð_input_frame_data[6]); 00369 00370 emac_stack_mem_free(0, mem_chain_p); 00371 00372 if (trace_level & TRACE_ETH_FRAMES) { 00373 printf("LEN %i\r\n\r\n", lenght); 00374 const char trace_type[] = "INP>"; 00375 emac_if_trace_to_ascii_hex_dump(trace_type, ETH_FRAME_HEADER_LEN, eth_input_frame_data); 00376 } 00377 return; 00378 } 00379 } 00380 00381 // Forward other than CTP frames to lwip 00382 struct netif *netif; 00383 00384 /* loop through netif's */ 00385 netif = netif_list; 00386 if (netif != NULL) { 00387 struct pbuf *p = (struct pbuf *)mem_chain_p; 00388 00389 /* pass all packets to ethernet_input, which decides what packets it supports */ 00390 if (netif->input(p, netif) != ERR_OK) { 00391 emac_stack_mem_free(0, mem_chain_p); 00392 } 00393 } else { 00394 emac_stack_mem_free(0, mem_chain_p); 00395 } 00396 } 00397 00398 void worker_loop_start(void (*test_step_cb_fnc)(void), int timeout) 00399 { 00400 int test_step_cb_timer = worker_loop_event_queue.call_every(timeout, test_step_cb_fnc); 00401 int timeout_outgoing_msg_timer = worker_loop_event_queue.call_every(1000, emac_if_timeout_outgoing_msg); 00402 00403 #if MBED_CONF_APP_ECHO_SERVER 00404 worker_loop_event_queue.dispatch_forever(); 00405 #else 00406 worker_loop_event_queue.dispatch(600 * SECOND_TO_MS); 00407 #endif 00408 00409 worker_loop_event_queue.cancel(test_step_cb_timer); 00410 worker_loop_event_queue.cancel(timeout_outgoing_msg_timer); 00411 00412 worker_loop_event_queue.dispatch(5); 00413 } 00414 00415 static void worker_loop_event_cb(int event) 00416 { 00417 if (event == LINK_UP) { 00418 printf("cable connected\r\n\r\n"); 00419 } 00420 00421 if (event == LINK_DOWN) { 00422 printf("cable disconnected\r\n\r\n"); 00423 } 00424 } 00425 00426 void worker_loop_end(void) 00427 { 00428 worker_loop_event_queue.break_dispatch(); 00429 } 00430 00431 unsigned char *emac_if_get_own_addr(void) 00432 { 00433 return (emac_if_get_hw_addr()); 00434 } 00435 00436 #endif
Generated on Tue Jul 12 2022 14:23:36 by
