Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers emac_util.cpp Source File

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(&eth_mac_echo_server_addr[i][0], addr, ETH_MAC_ADDR_LEN) == 0) {
00234             return;
00235         }
00236     }
00237 
00238     memcpy(&eth_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 &eth_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(&eth_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