diff --git a/api/icsneoc2/icsneoc2.cpp b/api/icsneoc2/icsneoc2.cpp index c2fdc41..dcf2f52 100644 --- a/api/icsneoc2/icsneoc2.cpp +++ b/api/icsneoc2/icsneoc2.cpp @@ -271,7 +271,9 @@ static icsneoc2_error_t open_device_with_options(std::shared_ptr dev, ic if(!dev) { return icsneoc2_error_invalid_device; } - if(!dev->enableMessagePolling(std::make_optional())) { + MessageFilter filter; + filter.includeInternalInAny = true; + if(!dev->enableMessagePolling(std::make_optional(filter))) { return icsneoc2_error_enable_message_polling_failed; } if(!dev->isOpen() && !dev->open()) { diff --git a/api/icsneoc2/icsneoc2messages.cpp b/api/icsneoc2/icsneoc2messages.cpp index e2f57d4..e438eb2 100644 --- a/api/icsneoc2/icsneoc2messages.cpp +++ b/api/icsneoc2/icsneoc2messages.cpp @@ -10,6 +10,7 @@ #include "icsneo/communication/message/apperrormessage.h" #include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/ethernetmessage.h" +#include "icsneo/communication/message/ethernetstatusmessage.h" #include "icsneo/communication/packet/canpacket.h" icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is_valid) { @@ -670,9 +671,40 @@ icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message, } icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet) { - if(!message) { + if(!message || !is_ethernet) { return icsneoc2_error_invalid_parameters; } *is_ethernet = std::dynamic_pointer_cast(message->message) != nullptr; return icsneoc2_error_success; } + +icsneoc2_error_t icsneoc2_message_is_ethernet_status(icsneoc2_message_t* message, bool* is_ethernet_status) { + if(!message || !is_ethernet_status) { + return icsneoc2_error_invalid_parameters; + } + *is_ethernet_status = std::dynamic_pointer_cast(message->message) != nullptr; + return icsneoc2_error_success; +} + +icsneoc2_error_t icsneoc2_message_eth_status_props_get(icsneoc2_message_t* message, bool* link_state, bool* duplex, icsneoc2_link_speed_t* link_speed, icsneoc2_link_mode_t* link_mode) { + if(!message) { + return icsneoc2_error_invalid_parameters; + } + auto msg = std::dynamic_pointer_cast(message->message); + if(!msg) { + return icsneoc2_error_invalid_type; + } + if(link_state) { + *link_state = msg->state; + } + if(duplex) { + *duplex = msg->duplex; + } + if(link_speed) { + *link_speed = static_cast(msg->speed); + } + if(link_mode) { + *link_mode = static_cast(msg->mode); + } + return icsneoc2_error_success; +} diff --git a/bindings/python/icsneopy/communication/message/ethernetstatusmessage.cpp b/bindings/python/icsneopy/communication/message/ethernetstatusmessage.cpp index e59a8e3..2908a04 100644 --- a/bindings/python/icsneopy/communication/message/ethernetstatusmessage.cpp +++ b/bindings/python/icsneopy/communication/message/ethernetstatusmessage.cpp @@ -7,7 +7,7 @@ namespace icsneo { void init_ethernetstatusmessage(pybind11::module_& m) { - pybind11::classh ethernetStatusMessage(m, "EthernetStatusMessage"); + pybind11::classh ethernetStatusMessage(m, "EthernetStatusMessage"); pybind11::enum_(ethernetStatusMessage, "LinkSpeed") .value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto) diff --git a/communication/message/ethernetstatusmessage.cpp b/communication/message/ethernetstatusmessage.cpp index 030410e..75986a8 100644 --- a/communication/message/ethernetstatusmessage.cpp +++ b/communication/message/ethernetstatusmessage.cpp @@ -37,7 +37,7 @@ struct Packet { }; #pragma pack(pop) -std::shared_ptr EthernetStatusMessage::DecodeToMessage(const std::vector& bytestream) { +std::shared_ptr EthernetStatusMessage::DecodeToMessage(const std::vector& bytestream) { if(bytestream.size() < sizeof(Packet)) { return nullptr; } @@ -76,5 +76,5 @@ std::shared_ptr EthernetStatusMessage::DecodeToMessage(const std::vecto break; default: return nullptr; } - return std::make_shared(packet->network, packet->state, speed, packet->duplex, mode); -} + return std::make_shared(packet->network, packet->state != 0, speed, packet->duplex != 0, mode); +} diff --git a/docs/icsneoc2/examples.rst b/docs/icsneoc2/examples.rst index e2253ca..3f57223 100644 --- a/docs/icsneoc2/examples.rst +++ b/docs/icsneoc2/examples.rst @@ -74,6 +74,14 @@ Ethernet Receive .. literalinclude:: ../../examples/c2/ethernet_receive/src/main.c :language: c +Ethernet Status +=============== + +:download:`Download example <../../examples/c2/ethernet_status/src/main.c>` + +.. literalinclude:: ../../examples/c2/ethernet_status/src/main.c + :language: c + T1S Loopback ============ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cc66f47..b8ed7cc 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,6 +12,7 @@ option(LIBICSNEO_BUILD_C2_LIN_EXAMPLE "Build the C2 LIN example." ON) option(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE "Build the C2 LIN transmit example." ON) option(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE "Build the C2 ethernet transmit example." ON) option(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE "Build the C2 ethernet receive example." ON) +option(LIBICSNEO_BUILD_C2_ETHERNET_STATUS_EXAMPLE "Build the C2 ethernet status example." ON) option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback example." ON) option(LIBICSNEO_BUILD_C2_TC10_EXAMPLE "Build the C2 TC10 example." ON) option(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE "Build the C2 gPTP settings example." ON) @@ -93,6 +94,10 @@ if(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE) add_subdirectory(c2/ethernet_receive) endif() +if(LIBICSNEO_BUILD_C2_ETHERNET_STATUS_EXAMPLE) + add_subdirectory(c2/ethernet_status) +endif() + if(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE) add_subdirectory(c2/t1s_loopback) endif() diff --git a/examples/c2/ethernet_status/CMakeLists.txt b/examples/c2/ethernet_status/CMakeLists.txt new file mode 100644 index 0000000..26ec2e7 --- /dev/null +++ b/examples/c2/ethernet_status/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(libicsneoc2-ethernet-status-example src/main.c) +target_link_libraries(libicsneoc2-ethernet-status-example icsneoc2-static) + +if(WIN32) + target_compile_definitions(libicsneoc2-ethernet-status-example PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() diff --git a/examples/c2/ethernet_status/src/main.c b/examples/c2/ethernet_status/src/main.c new file mode 100644 index 0000000..e1f89d6 --- /dev/null +++ b/examples/c2/ethernet_status/src/main.c @@ -0,0 +1,228 @@ +#include +#include + +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +void sleep_ms(uint32_t ms) { +#ifdef _WIN32 + Sleep(ms); +#else + usleep(ms * 1000); +#endif +} + +int print_error_code(const char* message, icsneoc2_error_t error) { + char error_str[64] = {0}; + size_t error_str_len = sizeof(error_str); + icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len); + if(res != icsneoc2_error_success) { + printf("%s: Failed to get string for error code %u with error code %u\n", message, error, res); + return (int)res; + } + printf("%s: \"%s\" (%u)\n", message, error_str, error); + return (int)error; +} + +void print_events(void) { + icsneoc2_event_t* events[256] = {0}; + size_t events_count = 256; + for(size_t i = 0; i < events_count; ++i) { + icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL); + if(res != icsneoc2_error_success) { + (void)print_error_code("\tFailed to get events", res); + return; + } + if(events[i] == NULL) { + events_count = i; + break; + } + } + + for(size_t i = 0; i < events_count; i++) { + char description[255] = {0}; + size_t description_length = sizeof(description); + icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length); + if(res != icsneoc2_error_success) { + (void)print_error_code("\tFailed to get event description", res); + continue; + } + printf("\tEvent %zu: %s\n", i, description); + } + + for(size_t i = 0; i < events_count; i++) { + icsneoc2_event_free(events[i]); + } + if(events_count > 0) { + printf("\tReceived %zu events\n", events_count); + } +} + +const char* link_speed_name(icsneoc2_link_speed_t speed) { + switch(speed) { + case icsneoc2_link_speed_auto: + return "Auto"; + case icsneoc2_link_speed_10mbps: + return "10 Mbps"; + case icsneoc2_link_speed_100mbps: + return "100 Mbps"; + case icsneoc2_link_speed_1000mbps: + return "1000 Mbps"; + case icsneoc2_link_speed_2500mbps: + return "2500 Mbps"; + case icsneoc2_link_speed_5000mbps: + return "5000 Mbps"; + case icsneoc2_link_speed_10000mbps: + return "10000 Mbps"; + default: + return "Unknown"; + } +} + +const char* link_mode_name(icsneoc2_link_mode_t mode) { + switch(mode) { + case icsneoc2_link_mode_auto: + return "Auto"; + case icsneoc2_link_mode_master: + return "Master"; + case icsneoc2_link_mode_slave: + return "Slave"; + case icsneoc2_link_mode_invalid: + return "Invalid"; + case icsneoc2_link_mode_none: + return "None"; + default: + return "Unknown"; + } +} + +int print_ethernet_status_message(icsneoc2_message_t* message, size_t index) { + icsneoc2_netid_t netid = 0; + char netid_name[128] = {0}; + size_t netid_name_length = sizeof(netid_name); + bool link_state = false; + bool duplex = false; + icsneoc2_link_speed_t link_speed = icsneoc2_link_speed_auto; + icsneoc2_link_mode_t link_mode = icsneoc2_link_mode_auto; + + icsneoc2_error_t res = icsneoc2_message_netid_get(message, &netid); + if(res != icsneoc2_error_success) { + return print_error_code("\tFailed to get Ethernet status netid", res); + } + + res = icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); + if(res != icsneoc2_error_success) { + return print_error_code("\tFailed to get Ethernet status netid name", res); + } + + res = icsneoc2_message_eth_status_props_get(message, &link_state, &duplex, &link_speed, &link_mode); + if(res != icsneoc2_error_success) { + return print_error_code("\tFailed to get Ethernet status properties", res); + } + + printf("\t%zu) Ethernet status on %s (0x%x)\n", index, netid_name, netid); + printf("\t Link: %s\n", link_state ? "Up" : "Down"); + printf("\t Duplex: %s\n", duplex ? "Full" : "Half"); + printf("\t Speed: %s (%u)\n", link_speed_name(link_speed), link_speed); + printf("\t Mode: %s (%u)\n", link_mode_name(link_mode), link_mode); + + return icsneoc2_error_success; +} + +int main(void) { + printf("Opening first available device offline...\n"); + icsneoc2_device_t* device = NULL; + icsneoc2_open_options_t options = icsneoc2_open_options_default & ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE; + icsneoc2_error_t res = icsneoc2_device_open_first(0, options, &device); + if(res != icsneoc2_error_success) { + return print_error_code("Failed to open first device", res); + } + + char description[255] = {0}; + size_t description_length = sizeof(description); + res = icsneoc2_device_description_get(device, description, &description_length); + if(res != icsneoc2_error_success) { + icsneoc2_device_close(device); + icsneoc2_device_free(device); + return print_error_code("Failed to get device description", res); + } + printf("Opened device: %s\n", description); + + printf("Going online to trigger Ethernet status broadcast...\n"); + res = icsneoc2_device_go_online(device, true); + if(res != icsneoc2_error_success) { + print_events(); + icsneoc2_device_close(device); + icsneoc2_device_free(device); + return print_error_code("Failed to go online", res); + } + + const int listen_seconds = 6; + time_t start_time = time(NULL); + size_t status_count = 0; + size_t total_count = 0; + printf("Listening for Ethernet status messages for %d seconds...\n", listen_seconds); + + while(time(NULL) - start_time < listen_seconds) { + icsneoc2_message_t* message = NULL; + res = icsneoc2_device_message_get(device, &message, 100); + if(res != icsneoc2_error_success) { + print_events(); + icsneoc2_device_close(device); + icsneoc2_device_free(device); + return print_error_code("Failed to get message", res); + } + if(message == NULL) { + sleep_ms(10); + continue; + } + + total_count++; + bool is_ethernet_status = false; + res = icsneoc2_message_is_ethernet_status(message, &is_ethernet_status); + if(res != icsneoc2_error_success) { + icsneoc2_message_free(message); + print_events(); + icsneoc2_device_close(device); + icsneoc2_device_free(device); + return print_error_code("Failed to check for Ethernet status message", res); + } + + if(is_ethernet_status) { + res = print_ethernet_status_message(message, status_count); + if(res != icsneoc2_error_success) { + icsneoc2_message_free(message); + print_events(); + icsneoc2_device_close(device); + icsneoc2_device_free(device); + return (int)res; + } + status_count++; + } + + icsneoc2_message_free(message); + } + + printf("Received %zu Ethernet status messages out of %zu total messages.\n", status_count, total_count); + if(status_count == 0) { + printf("No Ethernet status messages were seen. These messages are broadcast when the device goes online and may depend on device Ethernet support.\n"); + } + + print_events(); + + printf("Closing device...\n"); + res = icsneoc2_device_close(device); + if(res != icsneoc2_error_success) { + icsneoc2_device_free(device); + return print_error_code("Failed to close device", res); + } + + icsneoc2_device_free(device); + return 0; +} diff --git a/examples/c2/read_messages/src/main.c b/examples/c2/read_messages/src/main.c index 6ef63e0..f821f57 100644 --- a/examples/c2/read_messages/src/main.c +++ b/examples/c2/read_messages/src/main.c @@ -176,6 +176,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) { // Print the type and bus type of each message size_t tx_count = 0; size_t can_error_count = 0; + size_t internal_count = 0; icsneoc2_error_t res = icsneoc2_error_success; for(size_t i = 0; i < messages_count; i++) { icsneoc2_message_t* message = messages[i]; @@ -216,13 +217,21 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) { continue; } + // This example only cares about bus traffic, so skip internal + // device/status messages. + icsneoc2_network_type_t internal_check = icsneoc2_network_type_invalid; + res = icsneoc2_message_network_type_get(message, &internal_check); + if(res == icsneoc2_error_success && internal_check == icsneoc2_network_type_internal) { + internal_count++; + continue; + } + bool is_frame = false; res = icsneoc2_message_is_frame(message, &is_frame); if(res != icsneoc2_error_success) { return print_error_code("\tFailed to check if message is a frame", res); } if(!is_frame) { - printf("Ignoring non-frame message at index %zu\n", i); continue; } icsneoc2_network_type_t network_type; @@ -296,7 +305,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) { printf(" ]\n"); } } - printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count); + printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors, %zu internal (skipped)\n", messages_count, tx_count, can_error_count, internal_count); return icsneoc2_error_success; } diff --git a/examples/c2/simple/src/main.c b/examples/c2/simple/src/main.c index d5a9355..e69af7e 100644 --- a/examples/c2/simple/src/main.c +++ b/examples/c2/simple/src/main.c @@ -360,6 +360,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) { size_t tx_count = 0; size_t can_error_count = 0; size_t app_error_count = 0; + size_t internal_count = 0; for(size_t i = 0; i < messages_count; i++) { icsneoc2_message_t* message = messages[i]; @@ -414,13 +415,21 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) { continue; } + // This example only cares about bus traffic, so skip internal + // device/status messages. + icsneoc2_network_type_t internal_check = icsneoc2_network_type_invalid; + res = icsneoc2_message_network_type_get(message, &internal_check); + if(res == icsneoc2_error_success && internal_check == icsneoc2_network_type_internal) { + internal_count++; + continue; + } + bool is_frame = false; res = icsneoc2_message_is_frame(message, &is_frame); if(res != icsneoc2_error_success) { return print_error_code("\tFailed to check if message is a frame", res); } if(!is_frame) { - printf("Ignoring non-frame message at index %zu\n", i); continue; } icsneoc2_network_type_t network_type; @@ -494,7 +503,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) { printf(" ]\n"); } } - printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors, %zu were app errors\n", messages_count, tx_count, can_error_count, app_error_count); + printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors, %zu were app errors, %zu internal (skipped)\n", messages_count, tx_count, can_error_count, app_error_count, internal_count); return icsneoc2_error_success; } diff --git a/include/icsneo/communication/message/ethernetstatusmessage.h b/include/icsneo/communication/message/ethernetstatusmessage.h index 7b83305..22e4b1e 100644 --- a/include/icsneo/communication/message/ethernetstatusmessage.h +++ b/include/icsneo/communication/message/ethernetstatusmessage.h @@ -4,37 +4,41 @@ #ifdef __cplusplus #include "icsneo/communication/message/message.h" +#include "icsneo/icsneoc2types.h" #include namespace icsneo { -class EthernetStatusMessage : public Message { +class EthernetStatusMessage : public RawMessage { public: - enum class LinkSpeed { - LinkSpeedAuto, - LinkSpeed10, - LinkSpeed100, - LinkSpeed1000, - LinkSpeed2500, - LinkSpeed5000, - LinkSpeed10000, + enum class LinkSpeed: icsneoc2_link_speed_t { + LinkSpeedAuto = icsneoc2_link_speed_auto, + LinkSpeed10 = icsneoc2_link_speed_10mbps, + LinkSpeed100 = icsneoc2_link_speed_100mbps, + LinkSpeed1000 = icsneoc2_link_speed_1000mbps, + LinkSpeed2500 = icsneoc2_link_speed_2500mbps, + LinkSpeed5000 = icsneoc2_link_speed_5000mbps, + LinkSpeed10000 = icsneoc2_link_speed_10000mbps, }; - enum class LinkMode { - LinkModeAuto, - LinkModeMaster, - LinkModeSlave, - LinkModeInvalid, - LinkModeNone, + enum class LinkMode: icsneoc2_link_mode_t { + LinkModeAuto = icsneoc2_link_mode_auto, + LinkModeMaster = icsneoc2_link_mode_master, + LinkModeSlave = icsneoc2_link_mode_slave, + LinkModeInvalid = icsneoc2_link_mode_invalid, + LinkModeNone = icsneoc2_link_mode_none, }; - EthernetStatusMessage(Network net, bool state, LinkSpeed speed, bool duplex, LinkMode mode) : Message(Type::EthernetStatus), - network(net), state(state), speed(speed), duplex(duplex), mode(mode) {} - Network network; + + EthernetStatusMessage(Network net, bool state, LinkSpeed speed, bool duplex, LinkMode mode) : RawMessage(Type::EthernetStatus, net), + state(state), speed(speed), duplex(duplex), mode(mode) {} + // Link State: False = Link Down, True = Link Up bool state; LinkSpeed speed; + // Duplex: False = Half, True = Full bool duplex; LinkMode mode; - static std::shared_ptr DecodeToMessage(const std::vector& bytestream); + + static std::shared_ptr DecodeToMessage(const std::vector& bytestream); }; }; // namespace icsneo diff --git a/include/icsneo/icsneoc2messages.h b/include/icsneo/icsneoc2messages.h index fd100f8..a460ea2 100644 --- a/include/icsneo/icsneoc2messages.h +++ b/include/icsneo/icsneoc2messages.h @@ -298,10 +298,32 @@ icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message, */ icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet); +/** + * Check if a message is an Ethernet status message + * + * @param[in] message The message to check. + * @param[out] is_ethernet_status Pointer to a bool to copy the Ethernet status of the message into. + * + * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise. + */ +icsneoc2_error_t icsneoc2_message_is_ethernet_status(icsneoc2_message_t* message, bool* is_ethernet_status); + +/** + * Get the Ethernet status properties from an Ethernet status message + * + * @param[in] message The message to check. + * @param[out] link_state Pointer to a bool to copy the link state into. True if the link is up, false if it's down. If NULL, it's ignored. + * @param[out] duplex Pointer to a bool to copy the duplex state into. True if the link is full duplex, false if it's half duplex. If NULL, it's ignored. + * @param[out] link_speed Pointer to a icsneoc2_link_speed_t to copy the link speed into. If NULL, it's ignored. + * @param[out] link_mode Pointer to a icsneoc2_link_mode_t to copy the link mode into. If NULL, it's ignored. + * + * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters, icsneoc2_error_invalid_type otherwise. + */ +icsneoc2_error_t icsneoc2_message_eth_status_props_get(icsneoc2_message_t* message, bool* link_state, bool* duplex, icsneoc2_link_speed_t* link_speed, icsneoc2_link_mode_t* link_mode); + /** * Check if a message is valid * - * @param[in] device The device to check against. * @param[in] message The message to check. * @param[out] is_valid Pointer to a bool to copy the validity of the message into. * @@ -312,7 +334,6 @@ icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is /** * Check if a message is a raw message (message with data) * - * @param[in] device The device to check against. * @param[in] message The message to check. * @param[out] is_raw Pointer to a bool to copy the raw status of the message into. * @@ -323,7 +344,6 @@ icsneoc2_error_t icsneoc2_message_is_raw(icsneoc2_message_t* message, bool* is_r /** * Check if a message is a frame message (message with data) * - * @param[in] device The device to check against. * @param[in] message The message to check. * @param[out] is_frame Pointer to a bool to copy the frame status of the message into. * @@ -333,8 +353,7 @@ icsneoc2_error_t icsneoc2_message_is_frame(icsneoc2_message_t* message, bool* is /** * Check if a message is a CAN message - * - * @param[in] device The device to check against. + * * @param[in] message The message to check. * @param[out] is_can Pointer to a bool to copy the CAN status of the message into. * diff --git a/include/icsneo/icsneoc2types.h b/include/icsneo/icsneoc2types.h index 173b59a..146ec68 100644 --- a/include/icsneo/icsneoc2types.h +++ b/include/icsneo/icsneoc2types.h @@ -683,6 +683,34 @@ typedef enum _icsneoc2_chip_id_t { typedef uint8_t icsneoc2_chip_id_t; +typedef enum _icsneoc2_link_speed_t { + icsneoc2_link_speed_auto = 0, + icsneoc2_link_speed_10mbps, + icsneoc2_link_speed_100mbps, + icsneoc2_link_speed_1000mbps, + icsneoc2_link_speed_2500mbps, + icsneoc2_link_speed_5000mbps, + icsneoc2_link_speed_10000mbps, + + // Must be last entry. + icsneoc2_link_speed_maxsize +} _icsneoc2_link_speed_t; + +typedef uint8_t icsneoc2_link_speed_t; + +typedef enum _icsneoc2_link_mode_t { + icsneoc2_link_mode_auto = 0, + icsneoc2_link_mode_master, + icsneoc2_link_mode_slave, + icsneoc2_link_mode_invalid, + icsneoc2_link_mode_none, + + // Must be last entry. + icsneoc2_link_mode_maxsize +} _icsneoc2_link_mode_t; + +typedef uint8_t icsneoc2_link_mode_t; + typedef struct icsneoc2_mac_addr_entry_t icsneoc2_mac_addr_entry_t; #ifdef __cplusplus diff --git a/test/unit/icsneoc2.cpp b/test/unit/icsneoc2.cpp index fa7670b..5f559b3 100644 --- a/test/unit/icsneoc2.cpp +++ b/test/unit/icsneoc2.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -407,6 +409,8 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device) ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_t1s_props_set(NULL, NULL, NULL, NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_t1s_props_get(NULL, NULL, NULL, NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_ethernet(NULL, NULL)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_ethernet_status(NULL, NULL)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_status_props_get(NULL, NULL, NULL, NULL, NULL)); } TEST(icsneoc2, test_icsneoc2_devicetype_t) @@ -1144,6 +1148,83 @@ TEST(icsneoc2, test_icsneoc2_open_options_default) ASSERT_EQ(icsneoc2_open_options_default, expected); } +TEST(icsneoc2, test_message_filter_c2_includes_internal_messages) +{ + ASSERT_EQ(static_cast(icsneo::Message::Type::EthernetStatus), 0x8014); + + auto ethernetStatus = std::make_shared( + icsneo::Network::NetID::ETHERNET_01, + true, + icsneo::EthernetStatusMessage::LinkSpeed::LinkSpeed1000, + true, + icsneo::EthernetStatusMessage::LinkMode::LinkModeMaster + ); + auto deviceMessage = std::make_shared(icsneo::Network::NetID::Device); + auto deviceStatusMessage = std::make_shared(icsneo::Network::NetID::DeviceStatus); + auto internalStatusMessage = std::make_shared(icsneo::Message::Type::TC10Status); + auto canMessage = std::make_shared(); + + icsneo::MessageFilter defaultFilter; + ASSERT_FALSE(defaultFilter.match(ethernetStatus)); + ASSERT_FALSE(defaultFilter.match(deviceMessage)); + ASSERT_FALSE(defaultFilter.match(deviceStatusMessage)); + ASSERT_FALSE(defaultFilter.match(internalStatusMessage)); + ASSERT_TRUE(defaultFilter.match(canMessage)); + + icsneo::MessageFilter c2Filter; + c2Filter.includeInternalInAny = true; + ASSERT_TRUE(c2Filter.match(ethernetStatus)); + ASSERT_TRUE(c2Filter.match(deviceMessage)); + ASSERT_TRUE(c2Filter.match(deviceStatusMessage)); + ASSERT_TRUE(c2Filter.match(internalStatusMessage)); + ASSERT_TRUE(c2Filter.match(canMessage)); +} + +TEST(icsneoc2, test_icsneoc2_ethernet_status_props_get) +{ + icsneoc2_message_t message; + message.message = std::make_shared( + icsneo::Network::NetID::ETHERNET_01, + true, + icsneo::EthernetStatusMessage::LinkSpeed::LinkSpeed1000, + false, + icsneo::EthernetStatusMessage::LinkMode::LinkModeMaster + ); + + bool isEthernetStatus = false; + ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_ethernet_status(&message, &isEthernetStatus)); + ASSERT_TRUE(isEthernetStatus); + + bool linkState = false; + bool duplex = true; + icsneoc2_link_speed_t linkSpeed = icsneoc2_link_speed_auto; + icsneoc2_link_mode_t linkMode = icsneoc2_link_mode_auto; + ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_status_props_get(&message, &linkState, &duplex, &linkSpeed, &linkMode)); + ASSERT_TRUE(linkState); + ASSERT_FALSE(duplex); + ASSERT_EQ(linkSpeed, icsneoc2_link_speed_1000mbps); + ASSERT_EQ(linkMode, icsneoc2_link_mode_master); + + icsneoc2_netid_t netid = icsneoc2_netid_invalid; + ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_netid_get(&message, &netid)); + ASSERT_EQ(netid, icsneoc2_netid_ethernet_01); + + size_t dataLength = 1; + ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_get(&message, nullptr, &dataLength)); + ASSERT_EQ(dataLength, 0); + + // A non-Ethernet-status message must be rejected by the props getter and + // reported as not-an-Ethernet-status by the predicate. + icsneoc2_message_t can_message; + can_message.message = std::make_shared(); + + bool isEthernetStatusWrongType = true; + ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_ethernet_status(&can_message, &isEthernetStatusWrongType)); + ASSERT_FALSE(isEthernetStatusWrongType); + + ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_status_props_get(&can_message, &linkState, &duplex, &linkSpeed, &linkMode)); +} + TEST(icsneoc2, test_icsneoc2_message_is_error) { icsneoc2_message_t message;