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.
Fork of OmniWheels by
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 Fri Jul 22 2022 04:53:47 by
 1.7.2
 1.7.2 
    