21 Commits
Author SHA1 Message Date
Thomas StoddardandKyle Schwarz 5620c98eda Examples: Add more error reporting 2026-05-13 17:03:01 -04:00
Thomas StoddardandKyle Schwarz c466d75dae All: neoVI Explorer -> ICS Device Manager 2026-05-13 15:45:28 -04:00
Thomas StoddardandKyle Schwarz d7fc7ffa47 RADGigastar2 & RADGalaxy2: Add PhyEnableFor support 2026-05-12 18:38:32 -04:00
Kyle Schwarz 70ad76771e Servd: Clean up unused parseError 2026-05-12 16:57:04 -04:00
Kyle Schwarz 87c10410e8 Servd: Remove no devices found event 2026-05-12 15:58:11 -04:00
Thomas StoddardandKyle Schwarz 7cca96dcfb All: Switch to Servd default on
See README for details on how to install Servd.
2026-05-08 13:28:49 -04:00
Kyle Schwarz d45b72ef68 Settings: Increase response timeouts 2026-05-07 09:05:57 -04:00
Thomas StoddardandKyle Schwarz da02927da7 APIEvent: Add missing types 2026-05-06 16:57:00 -04:00
Thomas StoddardandKyle Schwarz b5a6f6ace6 Core: MACsec: Validate AN range and enable slots during addition 2026-05-06 13:47:25 -04:00
David RebbeandKyle Schwarz 0d2bbed7d5 C2: Add TC10 APIs 2026-05-06 11:04:44 -04:00
Kyle Schwarz a68b64c641 Device: Refactor supportsNetworkMutex 2026-05-05 20:35:51 -04:00
David RebbeandKyle Schwarz 9abd9389f4 Docs: Add Linux pcap info 2026-05-05 20:34:23 -04:00
David RebbeandKyle Schwarz d682627b40 CI: Fedora 44 & Ubuntu 26.04 2026-05-05 16:11:48 -04:00
David RebbeandKyle Schwarz 9ae3e115fc C2: Add Ethernet message support 2026-04-30 15:28:40 -04:00
Kyle Schwarz 87f45e060e Device: RADGalaxy2: Adjust bootloader pipeline 2026-04-28 15:37:17 -04:00
Thomas StoddardandKyle Schwarz 0cb30cfc5b Bindings: icsneopy: Add install instructions 2026-04-28 15:26:02 -04:00
Max BrombachandKyle Schwarz 79ff19015a Device: RAD-Gigastar 1 & 2: Add SFP flashing to bootloader pipelines 2026-04-24 16:12:45 -04:00
David RebbeandKyle Schwarz 9c4323987f C2: CAN error message support 2026-04-17 11:39:38 -04:00
David RebbeandKyle Schwarz f5f6d0828b C2: Add LIN message support 2026-04-15 15:50:33 -04:00
David RebbeandKyle Schwarz 6dc005fcea C2: Add PCBSN and MAC Address support 2026-04-14 13:37:27 -04:00
David RebbeandKyle Schwarz 5b553b63d3 C2: Add icsneoc2_device_reconnect 2026-04-08 16:19:31 -04:00
93 changed files with 5557 additions and 408 deletions
+48 -48
View File
@@ -119,30 +119,6 @@ unit_test windows/x86:
- linux-build - linux-build
timeout: 5m timeout: 5m
build linux/ubuntu/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/gcc
needs:
- build linux/ubuntu/2204/amd64/gcc
build linux/ubuntu/2204/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/clang
needs:
- build linux/ubuntu/2204/amd64/clang
build linux/ubuntu/2404/amd64/gcc: build linux/ubuntu/2404/amd64/gcc:
<<: *build_linux_ubuntu_gcc <<: *build_linux_ubuntu_gcc
image: ubuntu:24.04 image: ubuntu:24.04
@@ -167,6 +143,30 @@ unit_test linux/ubuntu/2404/amd64/clang:
needs: needs:
- build linux/ubuntu/2404/amd64/clang - build linux/ubuntu/2404/amd64/clang
build linux/ubuntu/2604/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:26.04
unit_test linux/ubuntu/2604/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:26.04
dependencies:
- build linux/ubuntu/2604/amd64/gcc
needs:
- build linux/ubuntu/2604/amd64/gcc
build linux/ubuntu/2604/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:26.04
unit_test linux/ubuntu/2604/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:26.04
dependencies:
- build linux/ubuntu/2604/amd64/clang
needs:
- build linux/ubuntu/2604/amd64/clang
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Fedora # Fedora
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -243,30 +243,6 @@ unit_test linux/ubuntu/2404/amd64/clang:
- linux-build - linux-build
timeout: 5m timeout: 5m
build linux/fedora/42/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:42
unit_test linux/fedora/42/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/gcc
needs:
- build linux/fedora/42/amd64/gcc
build linux/fedora/42/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:42
unit_test linux/fedora/42/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/clang
needs:
- build linux/fedora/42/amd64/clang
build linux/fedora/43/amd64/gcc: build linux/fedora/43/amd64/gcc:
<<: *build_linux_fedora_gcc <<: *build_linux_fedora_gcc
image: fedora:43 image: fedora:43
@@ -291,6 +267,30 @@ unit_test linux/fedora/43/amd64/clang:
needs: needs:
- build linux/fedora/43/amd64/clang - build linux/fedora/43/amd64/clang
build linux/fedora/44/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:44
unit_test linux/fedora/44/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:44
dependencies:
- build linux/fedora/44/amd64/gcc
needs:
- build linux/fedora/44/amd64/gcc
build linux/fedora/44/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:44
unit_test linux/fedora/44/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:44
dependencies:
- build linux/fedora/44/amd64/clang
needs:
- build linux/fedora/44/amd64/clang
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Python Module # Python Module
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
+8
View File
@@ -4,6 +4,14 @@ libicsneo is the [Intrepid Control Systems](https://intrepidcs.com/) device
communication library. Installation and usage documentation can be found within communication library. Installation and usage documentation can be found within
each of the respective APIs. each of the respective APIs.
## Installation
libicsneo relies on Servd, IntrepidCS's device communication server.
Servd can be installed for all platforms from https://cdn.intrepidcs.net/servd/.
Instructions for installing each API can be found in its respective documentation.
## Documentation ## Documentation
- [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/) - [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
+162 -37
View File
@@ -43,7 +43,7 @@ bool safe_str_copy(char* dest, size_t* dest_size, std::string_view src) {
} }
icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* value, size_t* value_length) { icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* value, size_t* value_length) {
static const char* error_strings[icsneoc2_error_maxsize] = { static const char* error_strings[] = {
"Success", // icsneoc2_error_success "Success", // icsneoc2_error_success
"Invalid function parameters", // icsneoc2_error_invalid_parameters "Invalid function parameters", // icsneoc2_error_invalid_parameters
"Open failed", // icsneoc2_error_open_failed "Open failed", // icsneoc2_error_open_failed
@@ -66,6 +66,9 @@ icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* valu
"Script clear failed", // icsneoc2_error_script_clear_failed "Script clear failed", // icsneoc2_error_script_clear_failed
"Script upload failed", // icsneoc2_error_script_upload_failed "Script upload failed", // icsneoc2_error_script_upload_failed
"Script load prepare failed", // icsneoc2_error_script_load_prepare_failed "Script load prepare failed", // icsneoc2_error_script_load_prepare_failed
"Close failed", // icsneoc2_error_close_failed
"Reconnect failed", // icsneoc2_error_reconnect_failed
"Invalid data", // icsneoc2_error_invalid_data
}; };
static_assert(std::size(error_strings) == icsneoc2_error_maxsize, static_assert(std::size(error_strings) == icsneoc2_error_maxsize,
"error_strings is out of sync with _icsneoc2_error_t enum - update both together"); "error_strings is out of sync with _icsneoc2_error_t enum - update both together");
@@ -194,37 +197,27 @@ icsneoc2_error_t icsneoc2_device_is_open(const icsneoc2_device_t* device, bool*
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_is_disconnected(const icsneoc2_device_t* device, bool* is_disconnected) { icsneoc2_error_t icsneoc2_device_create(const icsneoc2_device_info_t* device_info, icsneoc2_device_t** device) {
auto res = icsneoc2_device_is_valid(device); if(!device_info || !device_info->device || !device) {
if(res != icsneoc2_error_success) {
return res;
}
if(!is_disconnected) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
} }
auto dev = device->device; auto* new_device = new (std::nothrow) icsneoc2_device_t;
*is_disconnected = dev->isDisconnected(); if(!new_device) {
return icsneoc2_error_out_of_memory;
}
new_device->device = device_info->device;
*device = new_device;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
static icsneoc2_error_t open_device_with_options(std::shared_ptr<Device> dev, icsneoc2_open_options_t options, icsneoc2_device_t** device) { static icsneoc2_error_t open_device_with_options(std::shared_ptr<Device> dev, icsneoc2_open_options_t options) {
if(!dev) { if(!dev) {
return icsneoc2_error_invalid_device; return icsneoc2_error_invalid_device;
} }
// Nothing to do if already open
if(dev->isOpen()) {
*device = new (std::nothrow) icsneoc2_device_t;
if(!*device) {
return icsneoc2_error_out_of_memory;
}
(*device)->device = dev;
return icsneoc2_error_success;
}
if(!dev->enableMessagePolling(std::make_optional<MessageFilter>())) { if(!dev->enableMessagePolling(std::make_optional<MessageFilter>())) {
return icsneoc2_error_enable_message_polling_failed; return icsneoc2_error_enable_message_polling_failed;
} }
if(!dev->open()) { if(!dev->isOpen() && !dev->open()) {
return icsneoc2_error_open_failed; return icsneoc2_error_open_failed;
} }
if((options & ICSNEOC2_OPEN_OPTIONS_SYNC_RTC) && !dev->setRTC(std::chrono::system_clock::now())) { if((options & ICSNEOC2_OPEN_OPTIONS_SYNC_RTC) && !dev->setRTC(std::chrono::system_clock::now())) {
@@ -235,23 +228,15 @@ static icsneoc2_error_t open_device_with_options(std::shared_ptr<Device> dev, ic
dev->close(); dev->close();
return icsneoc2_error_go_online_failed; return icsneoc2_error_go_online_failed;
} }
*device = new (std::nothrow) icsneoc2_device_t;
if(!*device) {
dev->close();
return icsneoc2_error_out_of_memory;
}
(*device)->device = dev;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_info_t* device_info, icsneoc2_open_options_t options, icsneoc2_device_t** device) { icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_t* device, icsneoc2_open_options_t options) {
if(!device_info || !device) { auto res = icsneoc2_device_is_valid(device);
return icsneoc2_error_invalid_parameters; if(res != icsneoc2_error_success) {
return res;
} }
if(!device_info->device) { return open_device_with_options(device->device, options);
return icsneoc2_error_invalid_device;
}
return open_device_with_options(device_info->device, options, device);
} }
icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_options_t options, icsneoc2_device_t** device) { icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_options_t options, icsneoc2_device_t** device) {
@@ -266,7 +251,15 @@ icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_o
std::string_view target(serial); std::string_view target(serial);
for(auto* cur = devs; cur; cur = cur->next) { for(auto* cur = devs; cur; cur = cur->next) {
if(cur->device && cur->device->getSerial() == target) { if(cur->device && cur->device->getSerial() == target) {
res = open_device_with_options(cur->device, options, device); if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) {
icsneoc2_enumeration_free(devs);
return res;
}
res = open_device_with_options((*device)->device, options);
if (res != icsneoc2_error_success) {
icsneoc2_device_free(*device);
*device = nullptr;
}
icsneoc2_enumeration_free(devs); icsneoc2_enumeration_free(devs);
return res; return res;
} }
@@ -286,7 +279,15 @@ icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, i
} }
for(auto* cur = devs; cur; cur = cur->next) { for(auto* cur = devs; cur; cur = cur->next) {
if(cur->device && !cur->device->isOpen()) { if(cur->device && !cur->device->isOpen()) {
res = open_device_with_options(cur->device, options, device); if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) {
icsneoc2_enumeration_free(devs);
return res;
}
res = open_device_with_options((*device)->device, options);
if (res != icsneoc2_error_success) {
icsneoc2_device_free(*device);
*device = nullptr;
}
icsneoc2_enumeration_free(devs); icsneoc2_enumeration_free(devs);
return res; return res;
} }
@@ -295,6 +296,34 @@ icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, i
return icsneoc2_error_invalid_device; return icsneoc2_error_invalid_device;
} }
icsneoc2_error_t icsneoc2_device_reconnect(icsneoc2_device_t* device, icsneoc2_open_options_t options, uint32_t timeout_ms) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
// If the device is currently open, close it first before trying to reconnect
if (device->device->isOpen()) {
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return res;
}
}
const auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
while(std::chrono::steady_clock::now() < timeout) {
icsneoc2_device_t* new_device = nullptr;
res = icsneoc2_device_open_serial(device->device->getSerial().c_str(), options, &new_device);
if(res == icsneoc2_error_success) {
device->device = new_device->device;
delete new_device;
return icsneoc2_error_success;
}
// Avoid busy looping
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return icsneoc2_error_reconnect_failed;
}
icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device) { icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
@@ -304,7 +333,21 @@ icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device) {
if(!dev->isOpen()) { if(!dev->isOpen()) {
return icsneoc2_error_success; return icsneoc2_error_success;
} }
dev->close();
return dev->close() ? icsneoc2_error_success : icsneoc2_error_close_failed;
}
icsneoc2_error_t icsneoc2_device_free(icsneoc2_device_t* device) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if (device->device->isOpen()) {
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return res;
}
}
delete device; delete device;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -339,6 +382,48 @@ icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, cha
return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
} }
icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value_length) {
return icsneoc2_error_invalid_parameters;
}
auto pcbSerial = device->device->getPCBSerial();
if(!pcbSerial.has_value()) {
return icsneoc2_error_invalid_type;
}
const auto& data = *pcbSerial;
if(value) {
size_t copyLen = std::min(*value_length, data.size());
std::copy(data.begin(), data.begin() + copyLen, value);
}
*value_length = data.size();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_mac_address_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value_length) {
return icsneoc2_error_invalid_parameters;
}
auto macAddress = device->device->getMACAddress();
if(!macAddress.has_value()) {
return icsneoc2_error_invalid_type;
}
const auto& data = *macAddress;
if(value) {
size_t copyLen = std::min(*value_length, data.size());
std::copy(data.begin(), data.begin() + copyLen, value);
}
*value_length = data.size();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) { icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
@@ -555,6 +640,46 @@ icsneoc2_error_t icsneoc2_device_supports_tc10(const icsneoc2_device_t* device,
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_tc10_wake_request(const icsneoc2_device_t* device, icsneoc2_netid_t netid) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->requestTC10Wake(static_cast<Network::NetID>(netid))) {
return icsneoc2_error_transmit_message_failed;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_tc10_sleep_request(const icsneoc2_device_t* device, icsneoc2_netid_t netid) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->requestTC10Sleep(static_cast<Network::NetID>(netid))) {
return icsneoc2_error_transmit_message_failed;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_tc10_status_get(const icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_tc10_sleep_status_t* sleep_status, icsneoc2_tc10_wake_status_t* wake_status) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto cpp_status = device->device->getTC10Status(static_cast<Network::NetID>(netid));
if(!cpp_status.has_value()) {
return icsneoc2_error_invalid_type;
}
if (sleep_status) {
*sleep_status = static_cast<icsneoc2_tc10_sleep_status_t>(cpp_status->sleepStatus);
}
if (wake_status) {
*wake_status = static_cast<icsneoc2_tc10_wake_status_t>(cpp_status->wakeStatus);
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) { icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
+399
View File
@@ -6,6 +6,7 @@
#include "icsneo/icsneocpp.h" #include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
@@ -34,6 +35,19 @@ icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool*
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value) {
if(!message || !value) {
return icsneoc2_error_invalid_parameters;
}
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
if(!frame) {
return icsneoc2_error_invalid_type;
}
*value = frame->error;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc2_netid_t* netid) { icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc2_netid_t* netid) {
if(!message || !netid) { if(!message || !netid) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -55,6 +69,14 @@ icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, char* value, si
return safe_str_copy(value, value_length, netid_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; return safe_str_copy(value, value_length, netid_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
} }
icsneoc2_error_t icsneoc2_netid_network_type_get(icsneoc2_netid_t netid, icsneoc2_network_type_t* network_type) {
if(!network_type) {
return icsneoc2_error_invalid_parameters;
}
*network_type = static_cast<icsneoc2_network_type_t>(Network::GetTypeOfNetID(static_cast<Network::NetID>(netid), true));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_netid_set(icsneoc2_message_t* message, icsneoc2_netid_t netid) { icsneoc2_error_t icsneoc2_message_netid_set(icsneoc2_message_t* message, icsneoc2_netid_t netid) {
if(!message) { if(!message) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -176,6 +198,15 @@ icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uin
if(can_msg->errorStateIndicator) { if(can_msg->errorStateIndicator) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_ESI; *flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_ESI;
} }
if(can_msg->txAborted) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED;
}
if(can_msg->txLostArb) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB;
}
if(can_msg->txError) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR;
}
} }
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -214,5 +245,373 @@ icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_c
} }
*is_can = std::dynamic_pointer_cast<CANMessage>(message->message) != nullptr; *is_can = std::dynamic_pointer_cast<CANMessage>(message->message) != nullptr;
return icsneoc2_error_success; return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_can_error(icsneoc2_message_t* message, bool* is_can_error) {
if(!message || !is_can_error) {
return icsneoc2_error_invalid_parameters;
}
*is_can_error = std::dynamic_pointer_cast<CANErrorMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_error_props_get(
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
icsneoc2_can_error_code_t *error_code,
icsneoc2_can_error_code_t *data_error_code,
icsneoc2_message_can_error_flags_t *flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_err = std::dynamic_pointer_cast<CANErrorMessage>(message->message);
if(!can_err) {
return icsneoc2_error_invalid_type;
}
if(tx_err_count) {
*tx_err_count = can_err->transmitErrorCount;
}
if(rx_err_count) {
*rx_err_count = can_err->receiveErrorCount;
}
if(error_code) {
*error_code = static_cast<icsneoc2_can_error_code_t>(can_err->errorCode);
}
if(data_error_code) {
*data_error_code = static_cast<icsneoc2_can_error_code_t>(can_err->dataErrorCode);
}
if(flags) {
*flags = 0;
if(can_err->busOff) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF;
}
if(can_err->errorPassive) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE;
}
if(can_err->errorWarn) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) {
if(!message || !is_lin) {
return icsneoc2_error_invalid_parameters;
}
*is_lin = std::dynamic_pointer_cast<LINMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_create(icsneoc2_message_t** message, uint8_t id) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
(*message)->message = std::make_shared<LINMessage>(id);
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_get(const icsneoc2_message_t* message,
uint8_t* id, uint8_t* protected_id, uint8_t* checksum,
icsneoc2_lin_msg_type_t* msg_type, bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
*id = lin_msg->ID;
}
if(protected_id) {
*protected_id = lin_msg->protectedID;
}
if(checksum) {
*checksum = lin_msg->checksum;
}
if(msg_type) {
*msg_type = static_cast<icsneoc2_lin_msg_type_t>(lin_msg->linMsgType);
}
if(is_enhanced_checksum) {
*is_enhanced_checksum = lin_msg->isEnhancedChecksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
const uint8_t* id, const uint8_t* checksum,
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
lin_msg->ID = *id & 0x3Fu;
lin_msg->protectedID = lin_msg->calcProtectedID(lin_msg->ID);
}
if(checksum) {
lin_msg->checksum = *checksum;
}
if(msg_type) {
lin_msg->linMsgType = static_cast<LINMessage::Type>(*msg_type);
}
if(is_enhanced_checksum) {
lin_msg->isEnhancedChecksum = *is_enhanced_checksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags) {
if(!message || !err_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*err_flags = 0;
if(lin_msg->errFlags.ErrRxBreakOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_ONLY;
if(lin_msg->errFlags.ErrRxBreakSyncOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_SYNC_ONLY;
if(lin_msg->errFlags.ErrTxRxMismatch) *err_flags |= ICSNEOC2_LIN_ERR_TX_RX_MISMATCH;
if(lin_msg->errFlags.ErrRxBreakNotZero) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_NOT_ZERO;
if(lin_msg->errFlags.ErrRxBreakTooShort) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_TOO_SHORT;
if(lin_msg->errFlags.ErrRxSyncNot55) *err_flags |= ICSNEOC2_LIN_ERR_RX_SYNC_NOT_55;
if(lin_msg->errFlags.ErrRxDataLenOver8) *err_flags |= ICSNEOC2_LIN_ERR_RX_DATA_LEN_OVER_8;
if(lin_msg->errFlags.ErrFrameSync) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_SYNC;
if(lin_msg->errFlags.ErrFrameMessageID) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_MESSAGE_ID;
if(lin_msg->errFlags.ErrFrameResponderData) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_RESPONDER_DATA;
if(lin_msg->errFlags.ErrChecksumMatch) *err_flags |= ICSNEOC2_LIN_ERR_CHECKSUM_MATCH;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_status_flags_t* status_flags) {
if(!message || !status_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*status_flags = 0;
if(lin_msg->statusFlags.TxChecksumEnhanced) *status_flags |= ICSNEOC2_LIN_STATUS_TX_CHECKSUM_ENHANCED;
if(lin_msg->statusFlags.TxCommander) *status_flags |= ICSNEOC2_LIN_STATUS_TX_COMMANDER;
if(lin_msg->statusFlags.TxResponder) *status_flags |= ICSNEOC2_LIN_STATUS_TX_RESPONDER;
if(lin_msg->statusFlags.TxAborted) *status_flags |= ICSNEOC2_LIN_STATUS_TX_ABORTED;
if(lin_msg->statusFlags.UpdateResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_UPDATE_RESPONDER_ONCE;
if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE;
if(lin_msg->statusFlags.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_calc_checksum(icsneoc2_message_t* message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
LINMessage::calcChecksum(*lin_msg);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_create(icsneoc2_message_t** message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
(*message)->message = std::make_shared<EthernetMessage>();
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_flags_t* flags, const bool* has_fcs, const uint32_t* fcs) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
eth_msg->frameTooShort = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT);
eth_msg->noPadding = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING);
eth_msg->fcsVerified = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED);
eth_msg->txAborted = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED);
eth_msg->crcError = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR);
}
if(has_fcs && !*has_fcs) {
eth_msg->fcs = std::nullopt;
} else if(has_fcs && *has_fcs) {
// I'm pretty sure we can leave this alone, setting fcs below will take care of the behavior,
// otherwise we get into a weird state where we have to set fcs to zero if fcs is null but has_fcs is true.
}
if (fcs) {
eth_msg->fcs = *fcs;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_flags_t* flags, bool* has_fcs, uint32_t* fcs) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
*flags = 0;
if(eth_msg->noPadding)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING;
if(eth_msg->fcsVerified)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED;
if(eth_msg->txAborted)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED;
if(eth_msg->crcError)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR;
if(eth_msg->frameTooShort)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT;
}
if(has_fcs) {
*has_fcs = eth_msg->fcs.has_value();
}
if(fcs) {
if(eth_msg->fcs) {
*fcs = eth_msg->fcs.value();
} else {
*fcs = 0;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_mac_get(icsneoc2_message_t* message, uint8_t* dst_mac, uint8_t* src_mac) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(dst_mac) {
if(auto mac = eth_msg->getDestinationMAC(); mac.has_value()) {
const auto& mac_value = mac.value();
std::memcpy(dst_mac, mac_value.data(), mac_value.size());
} else {
return icsneoc2_error_invalid_data;
}
}
if(src_mac) {
if(auto mac = eth_msg->getSourceMAC(); mac.has_value()) {
const auto& mac_value = mac.value();
std::memcpy(src_mac, mac_value.data(), mac_value.size());
} else {
return icsneoc2_error_invalid_data;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_ether_type_get(icsneoc2_message_t* message, uint16_t* ether_type) {
if(!message || !ether_type) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if (auto et = eth_msg->getEtherType(); et.has_value()) {
*ether_type = et.value();
} else {
return icsneoc2_error_invalid_data;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_t1s_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_t1s_flags_t* flags, const uint8_t* node_id, const uint8_t* burst_count, const uint8_t* symbol_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
// If all parameters are null/zero, clear the T1S state. Otherwise, if any parameters are set and we don't have a T1S state, create it.
if(!flags && !node_id && !burst_count && !symbol_type) {
eth_msg->t1s = std::nullopt;
return icsneoc2_error_success;
}
if((flags || node_id || burst_count || symbol_type) && !eth_msg->t1s.has_value()) {
eth_msg->t1s.emplace();
}
if(flags) {
eth_msg->t1s->isSymbol = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL);
eth_msg->t1s->isBurst = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST);
eth_msg->t1s->txCollision = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION);
eth_msg->t1s->isWake = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE);
}
if(node_id) {
eth_msg->t1s->nodeId = *node_id;
}
if(burst_count) {
eth_msg->t1s->burstCount = *burst_count;
}
if(symbol_type) {
eth_msg->t1s->symbolType = *symbol_type;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_t1s_flags_t* flags, uint8_t* node_id, uint8_t* burst_count, uint8_t* symbol_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
*flags = 0;
if(eth_msg->t1s.has_value()) {
if(eth_msg->t1s->isSymbol)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL;
if(eth_msg->t1s->isBurst)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST;
if(eth_msg->t1s->txCollision)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION;
if(eth_msg->t1s->isWake)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE;
}
}
if(node_id) {
*node_id = eth_msg->t1s.has_value() ? eth_msg->t1s->nodeId : 0;
}
if(burst_count) {
*burst_count = eth_msg->t1s.has_value() ? eth_msg->t1s->burstCount : 0;
}
if(symbol_type) {
*symbol_type = eth_msg->t1s.has_value() ? eth_msg->t1s->symbolType : 0;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_ethernet = std::dynamic_pointer_cast<EthernetMessage>(message->message) != nullptr;
return icsneoc2_error_success;
} }
+210
View File
@@ -600,6 +600,36 @@ icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_set(icsneoc2_device_t* devic
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SBurstTimerFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBurstTimerFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) { icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid // Make sure the device is valid
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
@@ -632,6 +662,186 @@ icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_set(icsneoc2_device_t
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SLocalIDAlternateFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SLocalIDAlternateFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_termination_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1STerminationEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_termination_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1STerminationFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_beacons_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SBusDecodingBeaconsEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_beacons_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBusDecodingBeaconsFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_all_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SBusDecodingAllEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_all_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBusDecodingAllFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMultiIDEnableMaskFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMultiIDEnableMaskFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMultiIDFor(network, index); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMultiIDFor(network, index, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_enabled_set(icsneoc2_device_t* device, uint8_t pin, uint8_t value) { icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_enabled_set(icsneoc2_device_t* device, uint8_t pin, uint8_t value) {
// Make sure the device is valid // Make sure the device is valid
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
+75 -29
View File
@@ -22,29 +22,6 @@ void APIEvent::init(Type event, APIEvent::Severity severity) {
eventStruct.timestamp = EventClock::to_time_t(timepoint); eventStruct.timestamp = EventClock::to_time_t(timepoint);
} }
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
ss << getDescription();
return ss.str();
}
void APIEvent::downgradeFromError() noexcept { void APIEvent::downgradeFromError() noexcept {
eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning; eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning;
} }
@@ -86,8 +63,8 @@ static constexpr const char* NO_SERIAL_NUMBER_12V = "Communication could not be
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy."; static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy.";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!"; static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read."; static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer."; static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer."; static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue."; static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device."; static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device."; static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device.";
@@ -118,18 +95,28 @@ static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An idea
static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error."; static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error.";
static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition."; static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream."; static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* I2C_MESSAGE_EXCEED_MAX_LENGTH = "The I2C message was too long.";
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same."; static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected."; static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device."; static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIVE_DATA_INVALID_HANDLE = "The live data handle was invalid.";
static constexpr const char* LIVE_DATA_INVALID_COMMAND = "The live data command was invalid.";
static constexpr const char* LIVE_DATA_INVALID_ARGUMENT = "The live data argument was invalid.";
static constexpr const char* LIVE_DATA_VERSION_MISMATCH = "The live data version between libicsneo and firmware are not the same.";
static constexpr const char* LIVE_DATA_NO_DEVICE_RESPONSE = "Expected a response from the device for live data but none were found.";
static constexpr const char* LIVE_DATA_MAX_SIGNALS_REACHED = "The max amound of signals to subscribe to for live data has been reached.";
static constexpr const char* LIVE_DATA_COMMAND_FAILED = "The live data command failed.";
static constexpr const char* LIVE_DATA_ENCODER_ERROR = "Failure to encode live data message.";
static constexpr const char* LIVE_DATA_DECODER_ERROR = "Failure to decode live data message.";
static constexpr const char* LIVE_DATA_NOT_SUPPORTED = "Live data is not supported on this device.";
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device."; static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
static constexpr const char* MODE_NOT_FOUND = "The mode was not found."; static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
static constexpr const char* APP_ERROR_PARSING_FAILED = "Failure to decode app error message.";
static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device."; static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device.";
static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device"; static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device";
static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device."; static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device.";
static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count."; static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count.";
// Transport Errors // Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed."; static constexpr const char* FAILED_TO_READ = "A read operation failed.";
static constexpr const char* FAILED_TO_WRITE = "A write operation failed."; static constexpr const char* FAILED_TO_WRITE = "A write operation failed.";
@@ -146,6 +133,7 @@ static constexpr const char* FAILED_TO_BIND = "Unable to bind socket.";
static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt() failed."; static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt() failed.";
static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed."; static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed."; static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed.";
static constexpr const char* MDIO_MESSAGE_EXCEED_MAX_LENGTH = "The MDIO message was too long.";
// VSA // VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted."; static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
@@ -178,6 +166,7 @@ static constexpr const char* SERVD_RECV_ERROR = "Error receiving from Servd";
static constexpr const char* SERVD_POLL_ERROR = "Error polling on Servd socket"; static constexpr const char* SERVD_POLL_ERROR = "Error polling on Servd socket";
static constexpr const char* SERVD_NODATA_ERROR = "No data received from Servd"; static constexpr const char* SERVD_NODATA_ERROR = "No data received from Servd";
static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group"; static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group";
static constexpr const char* SERVD_NOT_REACHABLE = "Could not reach Servd; ensure it is installed and running";
// DXX // DXX
static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()"; static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()";
@@ -186,6 +175,7 @@ static constexpr const char* DXX_ERROR_OVERFLOW = "Overflow in DXX";
static constexpr const char* DXX_ERROR_IO = "I/O failure in DXX"; static constexpr const char* DXX_ERROR_IO = "I/O failure in DXX";
static constexpr const char* DXX_ERROR_ARG = "Invalid arg passed to DXX"; static constexpr const char* DXX_ERROR_ARG = "Invalid arg passed to DXX";
static constexpr const char* NO_ERROR_FOUND = "No errors were found.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated."; static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred."; static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred."; static constexpr const char* INVALID = "An invalid internal error occurred.";
@@ -313,6 +303,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return WIVI_STACK_REFRESH_FAILED; return WIVI_STACK_REFRESH_FAILED;
case Type::WiVIUploadStackOverflow: case Type::WiVIUploadStackOverflow:
return WIVI_UPLOAD_STACK_OVERFLOW; return WIVI_UPLOAD_STACK_OVERFLOW;
case Type::I2CMessageExceedsMaxLength:
return I2C_MESSAGE_EXCEED_MAX_LENGTH;
case Type::A2BMessageIncompleteFrame: case Type::A2BMessageIncompleteFrame:
return A2B_MESSAGE_INCOMPLETE_FRAME; return A2B_MESSAGE_INCOMPLETE_FRAME;
case Type::CoreminiUploadVersionMismatch: case Type::CoreminiUploadVersionMismatch:
@@ -321,10 +313,32 @@ const char* APIEvent::DescriptionForType(Type type) {
return DISK_NOT_CONNECTED; return DISK_NOT_CONNECTED;
case Type::UnexpectedResponse: case Type::UnexpectedResponse:
return UNEXPECTED_RESPONSE; return UNEXPECTED_RESPONSE;
case Type::LiveDataInvalidHandle:
return LIVE_DATA_INVALID_HANDLE;
case Type::LiveDataInvalidCommand:
return LIVE_DATA_INVALID_COMMAND;
case Type::LiveDataInvalidArgument:
return LIVE_DATA_INVALID_ARGUMENT;
case Type::LiveDataVersionMismatch:
return LIVE_DATA_VERSION_MISMATCH;
case Type::LiveDataNoDeviceResponse:
return LIVE_DATA_NO_DEVICE_RESPONSE;
case Type::LiveDataMaxSignalsReached:
return LIVE_DATA_MAX_SIGNALS_REACHED;
case Type::LiveDataCommandFailed:
return LIVE_DATA_COMMAND_FAILED;
case Type::LiveDataEncoderError:
return LIVE_DATA_ENCODER_ERROR;
case Type::LiveDataDecoderError:
return LIVE_DATA_DECODER_ERROR;
case Type::LiveDataNotSupported:
return LIVE_DATA_NOT_SUPPORTED;
case Type::LINSettingsNotAvailable: case Type::LINSettingsNotAvailable:
return LIN_SETTINGS_NOT_AVAILABLE; return LIN_SETTINGS_NOT_AVAILABLE;
case Type::ModeNotFound: case Type::ModeNotFound:
return MODE_NOT_FOUND; return MODE_NOT_FOUND;
case Type::AppErrorParsingFailed:
return APP_ERROR_PARSING_FAILED;
case Type::SettingNotAvaiableDevice: case Type::SettingNotAvaiableDevice:
return SETTING_NOT_AVAILABLE; return SETTING_NOT_AVAILABLE;
// Transport Errors // Transport Errors
@@ -358,6 +372,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return GETIFADDRS_ERROR; return GETIFADDRS_ERROR;
case Type::SendToError: case Type::SendToError:
return SEND_TO_ERROR; return SEND_TO_ERROR;
case Type::MDIOMessageExceedsMaxLength:
return MDIO_MESSAGE_EXCEED_MAX_LENGTH;
case Type::GPTPNotSupported: case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED; return GPTP_NOT_SUPPORTED;
case Type::DiskFormatNotSupported: case Type::DiskFormatNotSupported:
@@ -423,6 +439,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return SERVD_NODATA_ERROR; return SERVD_NODATA_ERROR;
case Type::ServdJoinMulticastError: case Type::ServdJoinMulticastError:
return SERVD_JOIN_MULTICAST_ERROR; return SERVD_JOIN_MULTICAST_ERROR;
case Type::ServdNotReachable:
return SERVD_NOT_REACHABLE;
// DXX // DXX
case Type::DXXErrorSys: case Type::DXXErrorSys:
@@ -437,13 +455,41 @@ const char* APIEvent::DescriptionForType(Type type) {
return DXX_ERROR_ARG; return DXX_ERROR_ARG;
// Other Errors // Other Errors
case Type::NoErrorFound:
return NO_ERROR_FOUND;
case Type::TooManyEvents: case Type::TooManyEvents:
return TOO_MANY_EVENTS; return TOO_MANY_EVENTS;
case Type::Unknown: case Type::Unknown:
return UNKNOWN; return UNKNOWN;
default:
return INVALID;
} }
return INVALID;
}
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
const char* description = DescriptionForType(getType());
if(description == INVALID)
ss << description << " (0x" << std::hex << eventStruct.eventNumber << ")";
else
ss << description;
return ss.str();
} }
bool EventFilter::match(const APIEvent& event) const noexcept { bool EventFilter::match(const APIEvent& event) const noexcept {
+1
View File
@@ -126,6 +126,7 @@ void init_event(pybind11::module_& m) {
.value("ServdPollError", APIEvent::Type::ServdPollError) .value("ServdPollError", APIEvent::Type::ServdPollError)
.value("ServdNoDataError", APIEvent::Type::ServdNoDataError) .value("ServdNoDataError", APIEvent::Type::ServdNoDataError)
.value("ServdJoinMulticastError", APIEvent::Type::ServdJoinMulticastError) .value("ServdJoinMulticastError", APIEvent::Type::ServdJoinMulticastError)
.value("ServdNotReachable", APIEvent::Type::ServdNotReachable)
.value("DXXErrorSys", APIEvent::Type::DXXErrorSys) .value("DXXErrorSys", APIEvent::Type::DXXErrorSys)
.value("DXXErrorInt", APIEvent::Type::DXXErrorInt) .value("DXXErrorInt", APIEvent::Type::DXXErrorInt)
.value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow) .value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow)
@@ -15,7 +15,10 @@ void init_canmessage(pybind11::module_& m) {
.def_readwrite("isExtended", &CANMessage::isExtended) .def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD) .def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch) .def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator); .def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator)
.def_readwrite("txAborted", &CANMessage::txAborted)
.def_readwrite("txLostArb", &CANMessage::txLostArb)
.def_readwrite("txError", &CANMessage::txError);
} }
} // namespace icsneo } // namespace icsneo
@@ -7,32 +7,29 @@
namespace icsneo { namespace icsneo {
void init_ethernetmessage(pybind11::module_& m) { void init_ethernetmessage(pybind11::module_& m) {
pybind11::classh<MACAddress>(m, "MACAddress") pybind11::classh<EthernetMessage::T1S>(m, "EthernetMessageT1S")
.def("to_string", &MACAddress::toString) .def(pybind11::init())
.def("__repr__", &MACAddress::toString); .def_readwrite("isSymbol", &EthernetMessage::T1S::isSymbol)
.def_readwrite("isBurst", &EthernetMessage::T1S::isBurst)
.def_readwrite("txCollision", &EthernetMessage::T1S::txCollision)
.def_readwrite("isWake", &EthernetMessage::T1S::isWake)
.def_readwrite("nodeId", &EthernetMessage::T1S::nodeId)
.def_readwrite("burstCount", &EthernetMessage::T1S::burstCount)
.def_readwrite("symbolType", &EthernetMessage::T1S::symbolType);
pybind11::classh<EthernetMessage, Frame>(m, "EthernetMessage") pybind11::classh<EthernetMessage, Frame>(m, "EthernetMessage")
.def(pybind11::init()) .def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("fcs", &EthernetMessage::fcs) .def_readwrite("fcs", &EthernetMessage::fcs)
.def_readwrite("frameTooShort", &EthernetMessage::frameTooShort) .def_readwrite("frameTooShort", &EthernetMessage::frameTooShort)
.def_readwrite("noPadding", &EthernetMessage::noPadding) .def_readwrite("noPadding", &EthernetMessage::noPadding)
.def_readwrite("fcsVerified", &EthernetMessage::fcsVerified) .def_readwrite("fcsVerified", &EthernetMessage::fcsVerified)
.def_readwrite("txAborted", &EthernetMessage::txAborted) .def_readwrite("txAborted", &EthernetMessage::txAborted)
.def_readwrite("crcError", &EthernetMessage::crcError) .def_readwrite("crcError", &EthernetMessage::crcError)
.def_readwrite("isT1S", &EthernetMessage::isT1S) .def_readwrite("t1s", &EthernetMessage::t1s)
.def_readwrite("isT1SSymbol", &EthernetMessage::isT1SSymbol) .def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("isT1SBurst", &EthernetMessage::isT1SBurst) .def("get_destination_mac", &EthernetMessage::getDestinationMAC)
.def_readwrite("txCollision", &EthernetMessage::txCollision) .def("get_source_mac", &EthernetMessage::getSourceMAC)
.def_readwrite("isT1SWake", &EthernetMessage::isT1SWake)
.def_readwrite("t1sNodeId", &EthernetMessage::t1sNodeId)
.def_readwrite("t1sBurstCount", &EthernetMessage::t1sBurstCount)
.def_readwrite("t1sSymbolType", &EthernetMessage::t1sSymbolType)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference)
.def("get_source_mac", &EthernetMessage::getSourceMAC, pybind11::return_value_policy::reference)
.def("get_ether_type", &EthernetMessage::getEtherType); .def("get_ether_type", &EthernetMessage::getEtherType);
} }
} // namespace icsneo } // namespace icsneo
+5 -1
View File
@@ -103,7 +103,7 @@ void init_chipid(pybind11::module_& m) {
.value("neoOBD2Dev_MCHIP", ChipID::neoOBD2Dev_MCHIP) .value("neoOBD2Dev_MCHIP", ChipID::neoOBD2Dev_MCHIP)
.value("neoOBD2Dev_SCHIP", ChipID::neoOBD2Dev_SCHIP) .value("neoOBD2Dev_SCHIP", ChipID::neoOBD2Dev_SCHIP)
.value("neoOBD2SIMDoIP_MCHIP", ChipID::neoOBD2SIMDoIP_MCHIP) .value("neoOBD2SIMDoIP_MCHIP", ChipID::neoOBD2SIMDoIP_MCHIP)
.value("SFPModule_MCHIP", ChipID::SFPModule_MCHIP) .value("SFPModule_88q2112_MCHIP", ChipID::SFPModule_88q2112_MCHIP)
.value("RADEpsilonT_MCHIP", ChipID::RADEpsilonT_MCHIP) .value("RADEpsilonT_MCHIP", ChipID::RADEpsilonT_MCHIP)
.value("RADEpsilonExpress_MCHIP", ChipID::RADEpsilonExpress_MCHIP) .value("RADEpsilonExpress_MCHIP", ChipID::RADEpsilonExpress_MCHIP)
.value("RADProxima_MCHIP", ChipID::RADProxima_MCHIP) .value("RADProxima_MCHIP", ChipID::RADProxima_MCHIP)
@@ -126,10 +126,14 @@ void init_chipid(pybind11::module_& m) {
.value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ) .value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ)
.value("VEM_02_FR_FCHIP", ChipID::VEM_02_FR_FCHIP) .value("VEM_02_FR_FCHIP", ChipID::VEM_02_FR_FCHIP)
.value("Connect_ZCHIP", ChipID::Connect_ZCHIP) .value("Connect_ZCHIP", ChipID::Connect_ZCHIP)
.value("SFPModule_88q2221_MCHIP", ChipID::SFPModule_88q2221_MCHIP)
.value("RADGALAXY2_SYSMON_CHIP", ChipID::RADGALAXY2_SYSMON_CHIP) .value("RADGALAXY2_SYSMON_CHIP", ChipID::RADGALAXY2_SYSMON_CHIP)
.value("SFPModule_88q3244_MCHIP", ChipID::SFPModule_88q3244_MCHIP)
.value("RADCOMET3_ZCHIP", ChipID::RADCOMET3_ZCHIP) .value("RADCOMET3_ZCHIP", ChipID::RADCOMET3_ZCHIP)
.value("Connect_LINUX", ChipID::Connect_LINUX) .value("Connect_LINUX", ChipID::Connect_LINUX)
.value("SFPModule_lan8670_MCHIP", ChipID::SFPModule_lan8670_MCHIP)
.value("RADGigastar2_ZYNQ", ChipID::RADGigastar2_ZYNQ) .value("RADGigastar2_ZYNQ", ChipID::RADGigastar2_ZYNQ)
.value("SFPModule_ent11100_MCHIP", ChipID::SFPModule_ent11100_MCHIP)
.value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP) .value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP)
.value("Invalid", ChipID::Invalid) .value("Invalid", ChipID::Invalid)
.finalize(); .finalize();
+5 -1
View File
@@ -326,11 +326,15 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::GenericBinaryInfo: case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data); result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true; return true;
case ExtendedCommand::SoftwareUpdate: {
result = std::make_shared<ExtendedResponseMessage>(ExtendedCommand::SoftwareUpdate, ExtendedResponse::OperationPending, packet->data);
return true;
}
case ExtendedCommand::GenericReturn: { case ExtendedCommand::GenericReturn: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse)) if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
break; break;
const auto& packedResp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data()); const auto& packedResp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode); result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode, packet->data);
return true; return true;
} }
case ExtendedCommand::LiveData: case ExtendedCommand::LiveData:
+1 -1
View File
@@ -48,7 +48,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
case Network::Type::AutomotiveEthernet: { case Network::Type::AutomotiveEthernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg; neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message); auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags; eth.preemptionFlags = ethmsg->preemptionFlags.value_or(0);
eth.status.incompleteFrame = ethmsg->frameTooShort; eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits // TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled; //eth.status.xyz = ethmsg->preemptionEnabled;
+67 -4
View File
@@ -102,10 +102,71 @@ static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, c
return encoded; return encoded;
} }
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> /* frame */, const device_eventhandler_t& report) { static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
// TODO auto linmsg = std::dynamic_pointer_cast<LINMessage>(frame);
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error); if(!linmsg) {
return {}; report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
if(linmsg->linMsgType == LINMessage::Type::NOT_SET) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return {};
}
size_t dataLen = std::min<size_t>(8, linmsg->data.size());
std::vector<uint8_t> encoded;
encoded.resize(sizeof(TransmitMessage));
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareLINPacket* const linpacket = (HardwareLINPacket*)(msg->commonHeader);
memset(linpacket, 0, sizeof(HardwareLINPacket));
// Protected ID and ID
linmsg->protectedID = linmsg->calcProtectedID(linmsg->ID);
linpacket->CoreMiniBitsLIN.ID = linmsg->protectedID & 0x3F;
// LIN message type flags
switch(linmsg->linMsgType) {
case LINMessage::Type::LIN_COMMANDER_MSG:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_HEADER_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_UPDATE_RESPONDER:
linpacket->CoreMiniBitsLIN.TXResponder = 1;
break;
case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break;
default:
break;
}
// Enhanced checksum
linpacket->CoreMiniBitsLIN.TxChkSumEnhanced = linmsg->isEnhancedChecksum ? 1 : 0;
// Data and checksum
bool hasData = (linmsg->linMsgType == LINMessage::Type::LIN_COMMANDER_MSG ||
linmsg->linMsgType == LINMessage::Type::LIN_UPDATE_RESPONDER) && dataLen > 0;
if(hasData) {
// len includes data bytes + 1 checksum byte
linpacket->CoreMiniBitsLIN.len = static_cast<uint16_t>(dataLen + 1);
std::copy(linmsg->data.begin(), linmsg->data.begin() + dataLen, linpacket->data);
// Checksum goes after data: in data[dataLen] if < 8, otherwise in LINByte9
if(dataLen < 8)
linpacket->data[dataLen] = linmsg->checksum;
else
linpacket->CoreMiniBitsLIN.LINByte9 = linmsg->checksum;
} else {
linpacket->CoreMiniBitsLIN.len = 0;
}
// Description/stats and network
linpacket->stats = linmsg->description;
return encoded;
} }
std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) { std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) {
@@ -127,6 +188,8 @@ std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> f
return result; return result;
} }
// common fields // common fields
if(result.empty())
return result;
TransmitMessage* const msg = (TransmitMessage*)result.data(); TransmitMessage* const msg = (TransmitMessage*)result.data();
msg->options.clientId = client_id; msg->options.clientId = client_id;
msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID()); msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID());
+5
View File
@@ -119,7 +119,12 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
} }
msg->transmitted = data->eid.TXMSG; msg->transmitted = data->eid.TXMSG;
// Set the generic frame error state
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb; msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
// Set specific error states for CANError
msg->txAborted = data->eid.TXAborted;
msg->txLostArb = data->eid.TXLostArb;
msg->txError = data->eid.TXError;
msg->description = data->stats; msg->description = data->stats;
return msg; return msg;
+22 -15
View File
@@ -1,6 +1,7 @@
#include "icsneo/communication/packet/ethernetpacket.h" #include "icsneo/communication/packet/ethernetpacket.h"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <optional>
using namespace icsneo; using namespace icsneo;
@@ -24,9 +25,6 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
message.transmitted = packet->eid.TXMSG; message.transmitted = packet->eid.TXMSG;
if(message.transmitted) if(message.transmitted)
message.description = packet->stats; message.description = packet->stats;
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.frameTooShort = packet->header.RUNT_FRAME; message.frameTooShort = packet->header.RUNT_FRAME;
message.noPadding = !packet->header.ENABLE_PADDING; message.noPadding = !packet->header.ENABLE_PADDING;
message.fcsVerified = packet->header.FCS_VERIFIED; message.fcsVerified = packet->header.FCS_VERIFIED;
@@ -39,15 +37,21 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS; message.timestamp = packet->timestamp.TS;
// Ethernet Frame Preemption for TSN
if(packet->header.PREEMPTION_ENABLED) {
message.preemptionFlags = static_cast<uint8_t>((rawWords[0] & 0x03F8) >> 4);
}
// Check if this is a T1S packet and populate T1S-specific fields // Check if this is a T1S packet and populate T1S-specific fields
message.isT1S = packet->header.T1S_ETHERNET; if(packet->header.T1S_ETHERNET) {
if(message.isT1S) { auto& t1s = message.t1s.emplace();
message.isT1SSymbol = packet->eid.T1S_SYMBOL;
message.isT1SBurst = packet->eid.T1S_BURST; t1s.isSymbol = packet->eid.T1S_SYMBOL;
message.txCollision = packet->t1s_status.TXCollision; t1s.isBurst = packet->eid.T1S_BURST;
message.isT1SWake = packet->t1s_status.T1SWake; t1s.txCollision = packet->t1s_status.TXCollision;
message.t1sNodeId = packet->t1s_node.T1S_NODE_ID; t1s.isWake = packet->t1s_status.T1SWake;
message.t1sBurstCount = packet->t1s_node.T1S_BURST_COUNT; t1s.nodeId = packet->t1s_node.T1S_NODE_ID;
t1s.burstCount = packet->t1s_node.T1S_BURST_COUNT;
} }
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket); const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
@@ -72,7 +76,7 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
if(description & 0x8000) if(description & 0x8000)
return false; return false;
const bool preempt = message.preemptionEnabled; const bool preempt = message.preemptionFlags.has_value();
// full header including parent // full header including parent
const size_t headerByteCount = preempt ? 15 : 14; const size_t headerByteCount = preempt ? 15 : 14;
// local header for netID, description, and flags // local header for netID, description, and flags
@@ -121,12 +125,15 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
uint8_t flags = 0x00; uint8_t flags = 0x00;
if(!message.noPadding) flags |= FLAG_PADDING; if(!message.noPadding) flags |= FLAG_PADDING;
if(message.fcs) flags |= FLAG_FCS; if(message.fcs) flags |= FLAG_FCS;
if(message.preemptionEnabled) flags |= FLAG_PREEMPTION; if(message.preemptionFlags.has_value()) {
flags |= FLAG_PREEMPTION;
}
bytestream.push_back(flags); bytestream.push_back(flags);
if(preempt) if(preempt) {
bytestream.push_back(static_cast<uint8_t>(message.preemptionFlags)); bytestream.push_back(message.preemptionFlags.value());
}
bytestream.insert(bytestream.end(), message.data.begin(), message.data.end()); bytestream.insert(bytestream.end(), message.data.begin(), message.data.end());
+36 -9
View File
@@ -285,14 +285,29 @@ int MACsecConfig::addTxSecY(const MACsecTxSecY& secY, uint8_t saIndex) {
} }
int MACsecConfig::addRxSa(const MACsecRxSa& sa) { int MACsecConfig::addRxSa(const MACsecRxSa& sa) {
// Validate AN is in valid range
if(sa.an > 3) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1;
}
// Check if we've exceeded the maximum SA count
if(rxSa.size() >= maxSa) { if(rxSa.size() >= maxSa) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error); ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1; return -1;
} }
int ret = static_cast<int>(rxSa.size()); // Ensure vector is large enough to hold index sa.an (sparse array)
rxSa.emplace_back(sa); // This allows SA index to match the AN value from the MACsec SecTAG
return ret; if(rxSa.size() <= sa.an) {
rxSa.resize(sa.an + 1);
}
// Mark it enabled; padding slots created by resize() above default to enabled=false.
rxSa[sa.an] = sa;
rxSa[sa.an].enabled = true;
return sa.an;
} }
int MACsecConfig::addTxSa(const MACsecTxSa& sa) { int MACsecConfig::addTxSa(const MACsecTxSa& sa) {
@@ -603,13 +618,23 @@ static void SetHardwareRxSecY(
hwSc->enable = 0x1u; hwSc->enable = 0x1u;
hwSc->secYIndex = index; hwSc->secYIndex = index;
hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u; hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sa_index0 = saIndices.first;
hwSc->sa_index1 = saIndices.second;
hwSc->sa_index0_in_use = 0x1u;
hwSc->sa_index1_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->isActiveSA1 = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sci = secY.sci; hwSc->sci = secY.sci;
if(saIndices.first & 0x1u) {
hwSc->sa_index0 = rekeyEnabled ? saIndices.second : saIndices.first;
hwSc->sa_index1 = saIndices.first;
hwSc->sa_index0_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sa_index1_in_use = 0x1u;
hwSc->isActiveSA1 = rekeyEnabled ? 0x0u : 0x1u;
} else {
hwSc->sa_index0 = saIndices.first;
hwSc->sa_index1 = saIndices.second;
hwSc->sa_index0_in_use = 0x1u;
hwSc->sa_index1_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->isActiveSA1 = rekeyEnabled ? 0x1u : 0x0u;
}
hwMap->index = index; hwMap->index = index;
hwMap->enable = 0x1u; hwMap->enable = 0x1u;
hwMap->secYIndex = index; hwMap->secYIndex = index;
@@ -638,7 +663,9 @@ static void SetHardwareRxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecRxSa&
MACSecSa_t* hwSa = &hwSettings->macsec.rx.sa[index]; MACSecSa_t* hwSa = &hwSettings->macsec.rx.sa[index];
hwSa->index = index; hwSa->index = index;
hwSa->enable = 0x1u; hwSa->enable = sa.enabled ? 0x1u : 0x0u;
if(!sa.enabled)
return;
memcpy(hwSa->sak, sa.sak.data(), 32); memcpy(hwSa->sak, sa.sak.data(), 32);
memcpy(hwSa->hashKey, sa.hashKey.data(), 16); memcpy(hwSa->hashKey, sa.hashKey.data(), 16);
memcpy(hwSa->salt, sa.salt.data(), 12); memcpy(hwSa->salt, sa.salt.data(), 12);
+8 -8
View File
@@ -395,7 +395,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) { if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) {
receivedMessage = false; receivedMessage = false;
} else { } else {
if(!stopHeartbeatThread && !isDisconnected()) { if(!stopHeartbeatThread) {
close(); close();
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error); report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
} }
@@ -560,7 +560,7 @@ bool Device::goOnline() {
return false; return false;
} }
if(supportsNetworkMutex()) { if(supportsNetworkMutex) {
assignedClientId = com->getClientIDSync(); assignedClientId = com->getClientIDSync();
if(assignedClientId) { if(assignedClientId) {
std::set<Network::NetID> nets; std::set<Network::NetID> nets;
@@ -3835,7 +3835,7 @@ bool Device::formatDisk(const DiskDetails& config, const DiskFormatProgress& han
return com->sendCommand(ExtendedCommand::DiskFormatProgress, {}); return com->sendCommand(ExtendedCommand::DiskFormatProgress, {});
}, },
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::DiskFormatProgress), std::make_shared<ExtendedResponseFilter>(ExtendedCommand::DiskFormatProgress),
std::chrono::milliseconds(1000) std::chrono::milliseconds(5000)
); );
if(!response) { if(!response) {
@@ -3927,7 +3927,7 @@ std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds ti
[[nodiscard]] std::optional<int> Device::lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event) [[nodiscard]] std::optional<int> Device::lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
{ {
if(!supportsNetworkMutex()) { if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return std::nullopt; return std::nullopt;
} }
@@ -3977,7 +3977,7 @@ std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds ti
bool Device::unlockNetworks(const std::set<Network::NetID>& networks) bool Device::unlockNetworks(const std::set<Network::NetID>& networks)
{ {
if(!supportsNetworkMutex()) { if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false; return false;
} }
@@ -4017,7 +4017,7 @@ bool Device::unlockNetworks(const std::set<Network::NetID>& networks)
std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetID network) std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetID network)
{ {
if(!supportsNetworkMutex()) { if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return nullptr; return nullptr;
} }
@@ -4039,7 +4039,7 @@ std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetI
[[nodiscard]] std::optional<int> Device::lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event) [[nodiscard]] std::optional<int> Device::lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
{ {
if(!supportsNetworkMutex()) { if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return std::nullopt; return std::nullopt;
} }
@@ -4086,7 +4086,7 @@ std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetI
bool Device::unlockAllNetworks() bool Device::unlockAllNetworks()
{ {
if(!supportsNetworkMutex()) { if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false; return false;
} }
+4 -4
View File
@@ -235,7 +235,7 @@ bool IDeviceSettings::apply(bool temporary) {
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response if(!msg || msg->data[0] != 1) { // We did not receive a response
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -261,7 +261,7 @@ bool IDeviceSettings::apply(bool temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@@ -303,7 +303,7 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings); return com->sendCommand(Command::SetDefaultSettings);
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000))); }, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@@ -338,7 +338,7 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
+57
View File
@@ -25,3 +25,60 @@ Read Messages
.. literalinclude:: ../../examples/c2/read_messages/src/main.c .. literalinclude:: ../../examples/c2/read_messages/src/main.c
:language: c :language: c
Device Info
===========
:download:`Download example <../../examples/c2/device_info/src/main.c>`
.. literalinclude:: ../../examples/c2/device_info/src/main.c
:language: c
LIN
===
:download:`Download example <../../examples/c2/lin/src/main.c>`
.. literalinclude:: ../../examples/c2/lin/src/main.c
:language: c
LIN Transmit
============
:download:`Download example <../../examples/c2/lin_transmit/src/main.c>`
.. literalinclude:: ../../examples/c2/lin_transmit/src/main.c
:language: c
Ethernet Transmit
=================
:download:`Download example <../../examples/c2/ethernet_transmit/src/main.c>`
.. literalinclude:: ../../examples/c2/ethernet_transmit/src/main.c
:language: c
Ethernet Receive
================
:download:`Download example <../../examples/c2/ethernet_receive/src/main.c>`
.. literalinclude:: ../../examples/c2/ethernet_receive/src/main.c
:language: c
T1S Loopback
============
:download:`Download example <../../examples/c2/t1s_loopback/src/main.c>`
.. literalinclude:: ../../examples/c2/t1s_loopback/src/main.c
:language: c
TC10
====
:download:`Download example <../../examples/c2/tc10/src/main.c>`
.. literalinclude:: ../../examples/c2/tc10/src/main.c
:language: c
+1 -1
View File
@@ -6,7 +6,7 @@ Prerequisites
============= =============
- Python 3.8 or higher - Python 3.8 or higher
- icsneopy library installed - icsneopy installed (see :doc:`installation`)
- CAN hardware device connected - CAN hardware device connected
:download:`Download complete example <../../examples/python/can/can_complete_example.py>` :download:`Download complete example <../../examples/python/can/can_complete_example.py>`
+1 -1
View File
@@ -8,7 +8,7 @@ Prerequisites
============= =============
- Python 3.8 or higher - Python 3.8 or higher
- icsneopy library installed - icsneopy installed (see :doc:`installation`)
- Intrepid Control Systems Device - Intrepid Control Systems Device
:download:`Download complete example <../../examples/python/ethernet/ethernet_complete_example.py>` :download:`Download complete example <../../examples/python/ethernet/ethernet_complete_example.py>`
+8
View File
@@ -92,6 +92,14 @@ SPI Example for 10BASE-T1S
.. literalinclude:: ../../examples/python/spi/spi_example.py .. literalinclude:: ../../examples/python/spi/spi_example.py
:language: python :language: python
10BASE-T1S Settings Configuration
=================================
:download:`Download example <../../examples/python/t1s/t1s_settings.py>`
.. literalinclude:: ../../examples/python/t1s/t1s_settings.py
:language: python
Analog Output Control Analog Output Control
===================== =====================
+2 -2
View File
@@ -5,7 +5,7 @@ FlexRay Getting Started
Prerequisites Prerequisites
============= =============
- icsneopy library installed - icsneopy installed (see :doc:`installation`)
- FlexRay hardware device connected (e.g., Fire3 Flexray) - FlexRay hardware device connected (e.g., Fire3 Flexray)
- Proper FlexRay bus termination (100Ω on each channel end) - Proper FlexRay bus termination (100Ω on each channel end)
@@ -127,7 +127,7 @@ FlexRay Coldstart Configuration
To use the Coldstart example, ensure the following: To use the Coldstart example, ensure the following:
Set the Flexray network in neoVI Explorer to Coldstart. Set the Flexray network in ICS Device Manager to Coldstart.
No other nodes should be present on the network during testing. No other nodes should be present on the network during testing.
+1
View File
@@ -5,6 +5,7 @@ icsneopy
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
installation
can_getting_started can_getting_started
ethernet_getting_started ethernet_getting_started
flexray_getting_started flexray_getting_started
+38
View File
@@ -0,0 +1,38 @@
============
Installation
============
icsneopy is available on PyPI at https://pypi.org/project/icsneopy/ and can be installed with pip:
.. code-block:: bash
pip install icsneopy
Pre-release
===========
For the latest features, install with the ``--pre`` flag to include pre-release versions:
.. code-block:: bash
pip install --pre icsneopy
Upgrading
=========
To upgrade an existing installation:
.. code-block:: bash
pip install --pre --upgrade icsneopy
Linux udev Rules
================
Linux users may want to install the included udev rules to run icsneopy-based
applications without root. The rules file can be found in the libicsneo source
repository at https://github.com/intrepidcs/libicsneo/.
.. code-block:: bash
sudo cp 99-intrepidcs.rules /etc/udev/rules.d/
+15
View File
@@ -14,3 +14,18 @@ communication library. The source code for libicsneo can be found on GitHub:
icsneopy/index icsneopy/index
icsneoc/index icsneoc/index
icsneoc2/index icsneoc2/index
Linux Installation
==================
Applications that use raw Ethernet device discovery, such as PCAP-backed
discovery, need permission to open raw network sockets. Instead of running your
application with ``sudo``, grant the installed executable the required Linux
capabilities:
.. code-block:: bash
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/your-app
Replace ``/usr/bin/your-app`` with the full path to the application executable.
+40
View File
@@ -4,6 +4,14 @@ option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the simple C2 example." ON) option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the simple C2 example." ON)
option(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE "Build the C2 read messages example." ON) option(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE "Build the C2 read messages example." ON)
option(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE "Build the C2 disk format example." ON) option(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE "Build the C2 disk format example." ON)
option(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE "Build the C2 reconnect example." ON)
option(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE "Build the C2 device info example." ON)
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_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_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON) option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON) option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
@@ -47,6 +55,38 @@ if(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE)
add_subdirectory(c2/diskformat) add_subdirectory(c2/diskformat)
endif() endif()
if(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE)
add_subdirectory(c2/reconnect)
endif()
if(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE)
add_subdirectory(c2/device_info)
endif()
if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE)
add_subdirectory(c2/lin)
endif()
if(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE)
add_subdirectory(c2/lin_transmit)
endif()
if(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE)
add_subdirectory(c2/ethernet_transmit)
endif()
if(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE)
add_subdirectory(c2/ethernet_receive)
endif()
if(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE)
add_subdirectory(c2/t1s_loopback)
endif()
if(LIBICSNEO_BUILD_C2_TC10_EXAMPLE)
add_subdirectory(c2/tc10)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE) if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple) add_subdirectory(cpp/simple)
endif() endif()
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-device-info-example src/main.c)
target_link_libraries(libicsneoc2-device-info-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-device-info-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+127
View File
@@ -0,0 +1,127 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#include <inttypes.h>
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
int main() {
icsneoc2_error_t res;
/* ===== Device Selection ===== */
printf("Searching for devices...\n");
icsneoc2_device_info_t* found_devices = NULL;
res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(!found_devices) {
printf("No devices found.\n");
return 1;
}
/* Count and display devices */
int device_count = 0;
for(icsneoc2_device_info_t* cur = found_devices; cur; cur = icsneoc2_device_info_next(cur)) {
char desc[128] = {0};
size_t desc_len = sizeof(desc);
icsneoc2_device_info_description_get(cur, desc, &desc_len);
char serial[32] = {0};
size_t serial_len = sizeof(serial);
icsneoc2_device_info_serial_get(cur, serial, &serial_len);
printf(" [%d] %s (Serial: %s)\n", device_count + 1, desc, serial);
device_count++;
}
int device_choice;
printf("Select device (1-%d): ", device_count);
if(scanf("%d", &device_choice) != 1 || device_choice < 1 || device_choice > device_count) {
printf("Invalid selection.\n");
icsneoc2_enumeration_free(found_devices);
return 1;
}
/* Find the selected device_info node */
icsneoc2_device_info_t* selected_info = found_devices;
for(int i = 1; i < device_choice; i++) {
selected_info = icsneoc2_device_info_next(selected_info);
}
/* Open the selected device */
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(selected_info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device from device info", res);
}
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
icsneoc2_enumeration_free(found_devices);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to open device", res);
}
char description[128] = {0};
size_t description_length = sizeof(description);
icsneoc2_device_description_get(device, description, &description_length);
printf("\nOpened device: %s\n\n", description);
/* ===== Serial Number ===== */
char serial[32] = {0};
size_t serial_len = sizeof(serial);
res = icsneoc2_device_serial_get(device, serial, &serial_len);
if(res == icsneoc2_error_success) {
printf("Serial: %s\n", serial);
} else {
print_error_code("Failed to get serial", res);
}
/* ===== PCB Serial Number ===== */
uint8_t pcbsn[16] = {0};
size_t pcbsn_len = sizeof(pcbsn);
res = icsneoc2_device_pcb_serial_get(device, pcbsn, &pcbsn_len);
if(res == icsneoc2_error_success) {
printf("PCB Serial: ");
for(size_t i = 0; i < pcbsn_len; i++) {
printf("%c", pcbsn[i]);
}
printf("\n");
} else {
print_error_code("Failed to get PCB serial (device may not support it)", res);
}
/* ===== MAC Address ===== */
uint8_t mac[6] = {0};
size_t mac_len = sizeof(mac);
res = icsneoc2_device_mac_address_get(device, mac, &mac_len);
if(res == icsneoc2_error_success) {
printf("MAC: ");
for(size_t i = 0; i < mac_len; i++) {
if(i > 0) printf(":");
printf("%02X", mac[i]);
}
printf("\n");
} else {
print_error_code("Failed to get MAC address (device may not support it)", res);
}
/* Cleanup */
printf("\nClosing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
icsneoc2_device_free(device);
return 0;
}
+8
View File
@@ -48,6 +48,7 @@ int main() {
size_t description_length = sizeof(description); size_t description_length = sizeof(description);
res = icsneoc2_device_description_get(device, description, &description_length); res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("\tFailed to get device description", res); return print_error_code("\tFailed to get device description", res);
} }
printf("\tOpened device: %s\n", description); printf("\tOpened device: %s\n", description);
@@ -58,11 +59,13 @@ int main() {
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_error_code("\tFailed to check disk formatting support", res); print_error_code("\tFailed to check disk formatting support", res);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1; return -1;
} }
if(!supported) { if(!supported) {
printf("\terror: %s does not support disk formatting\n", description); printf("\terror: %s does not support disk formatting\n", description);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1; return -1;
} }
@@ -79,6 +82,7 @@ int main() {
printf("FAIL\n"); printf("FAIL\n");
print_error_code("\tFailed to get disk details", res); print_error_code("\tFailed to get disk details", res);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1; return -1;
} }
printf("OK\n"); printf("OK\n");
@@ -122,6 +126,7 @@ int main() {
printf("\n\terror: no disks are present in the device\n"); printf("\n\terror: no disks are present in the device\n");
icsneoc2_disk_details_free(details); icsneoc2_disk_details_free(details);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1; return -1;
} }
@@ -133,6 +138,7 @@ int main() {
printf("\tAborted.\n"); printf("\tAborted.\n");
icsneoc2_disk_details_free(details); icsneoc2_disk_details_free(details);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0; return 0;
} }
@@ -145,6 +151,7 @@ int main() {
print_error_code("\tFormat failed", res); print_error_code("\tFormat failed", res);
icsneoc2_disk_details_free(details); icsneoc2_disk_details_free(details);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1; return -1;
} }
printf("\tFormat complete!\n"); printf("\tFormat complete!\n");
@@ -171,5 +178,6 @@ int main() {
printf("\tClosing device: %s...\n", description); printf("\tClosing device: %s...\n", description);
icsneoc2_device_close(device); icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0; return 0;
} }
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-ethernet-receive-example src/main.c)
target_link_libraries(libicsneoc2-ethernet-receive-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-ethernet-receive-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+223
View File
@@ -0,0 +1,223 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <inttypes.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return 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 = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
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);
}
}
void print_mac(const char* label, const uint8_t* mac) {
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x", label, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
icsneoc2_netid_t netid = 0;
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_error_t res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get 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 netid name", res);
}
/* Get data length first */
size_t data_length = 0;
res = icsneoc2_message_data_get(message, NULL, &data_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get data length", res);
}
printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length);
/* Get MAC addresses and EtherType if we have enough data */
uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0};
uint16_t ether_type = 0;
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) {
printf("\t ");
print_mac("Dst", dst_mac);
printf(" ");
print_mac("Src", src_mac);
printf("\n");
}
res = icsneoc2_message_eth_ether_type_get(message, &ether_type);
if(res == icsneoc2_error_success) {
printf("\t EtherType: 0x%04x\n", ether_type);
}
/* Get flags */
icsneoc2_message_eth_flags_t flags = 0;
res = icsneoc2_message_eth_props_get(message, &flags, NULL, NULL);
if(res == icsneoc2_error_success && flags != 0) {
printf("\t Flags: 0x%" PRIx64, flags);
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR) printf(" [CRC_ERROR]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT) printf(" [FRAME_TOO_SHORT]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED) printf(" [TX_ABORTED]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED) printf(" [FCS_VERIFIED]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_PREEMPTION_ENABLED) printf(" [PREEMPTION]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_IS_T1S) printf(" [T1S]");
printf("\n");
}
/* Print data bytes */
uint8_t data[1600] = {0};
res = icsneoc2_message_data_get(message, data, &data_length);
if(res == icsneoc2_error_success) {
printf("\t Data:\n\t ");
for(size_t x = 0; x < data_length; x++) {
printf("0x%02x ", data[x]);
if((x + 1) % 20 == 0 && x + 1 < data_length) {
printf("\n\t ");
}
}
printf("\n");
}
return icsneoc2_error_success;
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
/* Wait for Ethernet frames to arrive */
const int duration_seconds = 10;
printf("Listening for Ethernet frames for %d seconds...\n", duration_seconds);
sleep_ms(duration_seconds * 1000);
/* Retrieve and process messages */
icsneoc2_message_t* messages[20000] = {0};
size_t message_count = 20000;
size_t eth_count = 0;
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(device, &messages[i], 0);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to get messages", res);
}
if(messages[i] == NULL) {
message_count = i;
break;
}
}
printf("Got %zu messages total, filtering for Ethernet...\n", message_count);
for(size_t i = 0; i < message_count; i++) {
icsneoc2_message_t* message = messages[i];
/* Check if this is a TX echo (skip it) */
bool is_tx = false;
res = icsneoc2_message_is_transmit(message, &is_tx);
if(res != icsneoc2_error_success || is_tx) {
continue;
}
/* Check if this is an Ethernet message */
bool is_ethernet = false;
res = icsneoc2_message_is_ethernet(message, &is_ethernet);
if(res != icsneoc2_error_success || !is_ethernet) {
continue;
}
process_ethernet_message(message, eth_count);
eth_count++;
}
printf("Received %zu Ethernet frames out of %zu total messages\n", eth_count, message_count);
/* Free all messages */
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
/* Print any events */
print_events();
/* Close the device */
printf("Closing device...\n");
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to close device", res);
}
return 0;
}
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-ethernet-transmit-example src/main.c)
target_link_libraries(libicsneoc2-ethernet-transmit-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-ethernet-transmit-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+204
View File
@@ -0,0 +1,204 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <inttypes.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return 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 = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
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);
}
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
icsneoc2_netid_t tx_networks[255] = {0};
size_t tx_net_count = sizeof(tx_networks) / sizeof(tx_networks[0]);
res = icsneoc2_device_supported_tx_networks_get(device, tx_networks, &tx_net_count);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to get TX networks", res);
}
/* Filter for Ethernet/AutomotiveEthernet networks */
icsneoc2_netid_t eth_networks[64] = {0};
char eth_names[64][128] = {{0}};
size_t eth_count = 0;
for(size_t i = 0; i < tx_net_count && eth_count < 64; i++) {
/* Create a temporary message to check network type */
icsneoc2_message_t* tmp = NULL;
res = icsneoc2_message_eth_create(&tmp);
if(res != icsneoc2_error_success) continue;
res = icsneoc2_message_netid_set(tmp, tx_networks[i]);
if(res != icsneoc2_error_success) { icsneoc2_message_free(tmp); continue; }
icsneoc2_network_type_t ntype = 0;
res = icsneoc2_message_network_type_get(tmp, &ntype);
icsneoc2_message_free(tmp);
if(res != icsneoc2_error_success) continue;
if(ntype == icsneoc2_network_type_ethernet || ntype == icsneoc2_network_type_automotive_ethernet) {
eth_networks[eth_count] = tx_networks[i];
size_t name_len = 128;
icsneoc2_netid_name_get(tx_networks[i], eth_names[eth_count], &name_len);
eth_count++;
}
}
if(eth_count == 0) {
printf("No Ethernet TX networks available on this device.\n");
icsneoc2_device_close(device);
return 0;
}
/* Let the user pick */
printf("Available Ethernet TX networks:\n");
for(size_t i = 0; i < eth_count; i++) {
printf(" %zu) %s\n", i + 1, eth_names[i]);
}
printf("Select network [1-%zu]: ", eth_count);
int selection = 0;
if(scanf("%d", &selection) != 1 || selection < 1 || (size_t)selection > eth_count) {
printf("Invalid selection, using first available.\n");
selection = 1;
}
icsneoc2_netid_t netid = eth_networks[selection - 1];
printf("Selected: %s\n", eth_names[selection - 1]);
/* Transmit Ethernet frames */
const size_t msg_count = 10;
printf("Transmitting %zu Ethernet frames on %s...\n", msg_count, eth_names[selection - 1]);
for(size_t i = 0; i < msg_count; i++) {
/* Create an Ethernet message */
icsneoc2_message_t* message = NULL;
res = icsneoc2_message_eth_create(&message);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to create Ethernet message", res);
}
/* Set the network ID */
res = icsneoc2_message_netid_set(message, netid );
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to set netid", res);
}
/* Build Ethernet frame data:
* Bytes 0-5: Destination MAC (00:FC:70:00:01:02)
* Bytes 6-11: Source MAC (00:FC:70:00:01:01)
* Bytes 12-13: EtherType (0x0800 = IPv4)
* Bytes 14+: Payload
*/
uint8_t frame_data[] = {
0x00, 0xFC, 0x70, 0x00, 0x01, 0x02, /* Destination MAC */
0x00, 0xFC, 0x70, 0x00, 0x01, 0x01, /* Source MAC */
0x08, 0x00, /* EtherType (IPv4) */
0x45, 0x00, 0x00, 0x20, /* IPv4: ver/IHL, DSCP, total length (32) */
0x00, 0x00, 0x00, 0x00, /* Identification, flags/fragment offset */
0x40, 0x11, 0x00, 0x00, /* TTL (64), protocol (UDP), checksum (0) */
0xC0, 0xA8, 0x01, 0x01, /* Source IP (192.168.1.1) */
0xC0, 0xA8, 0x01, 0x02, /* Destination IP (192.168.1.2) */
0xC3, 0x50, 0xC3, 0x51, /* UDP: src port (50000), dst port (50001) */
0x00, 0x0C, 0x00, 0x00, /* UDP: length (12), checksum (0) */
0x00, 0x00, 0x00, 0x00 /* UDP payload (4 bytes, frame counter) */
};
/* Put the frame counter in the UDP payload */
frame_data[42] = (uint8_t)((i >> 24) & 0xFF);
frame_data[43] = (uint8_t)((i >> 16) & 0xFF);
frame_data[44] = (uint8_t)((i >> 8) & 0xFF);
frame_data[45] = (uint8_t)(i & 0xFF);
res = icsneoc2_message_data_set(message, frame_data, sizeof(frame_data));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to set frame data", res);
}
/* Transmit the message */
res = icsneoc2_device_message_transmit(device, message);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to transmit Ethernet frame", res);
}
icsneoc2_message_free(message);
printf("\tTransmitted frame %zu\n", i + 1);
}
printf("Successfully transmitted %zu Ethernet frames\n", msg_count);
/* Print any events */
print_events();
/* Close the device */
printf("Closing device...\n");
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to close device", res);
}
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-lin-example src/main.c)
target_link_libraries(libicsneoc2-lin-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-lin-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+311
View File
@@ -0,0 +1,311 @@
/* Note: This example requires LIN 1 and LIN 2 channels to be connected on the device */
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <inttypes.h>
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
void print_events(const char* device_description) {
icsneoc2_event_t* events[1024] = {0};
size_t events_count = 1024;
for(size_t i = 0; i < events_count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_event_free(events[j]);
}
(void)print_error_code("\tFailed to get device events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
for(size_t i = 0; i < events_count; i++) {
char event_description[255] = {0};
size_t event_description_length = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], event_description, &event_description_length);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\t%s: Event %zu: %s\n", device_description, i, event_description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
printf("\t%s: Received %zu events\n", device_description, events_count);
}
void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
for(size_t i = 0; i < count; i++) {
bool is_lin = false;
icsneoc2_error_t res = icsneoc2_message_is_lin(messages[i], &is_lin);
if(res != icsneoc2_error_success || !is_lin)
continue;
uint8_t id = 0;
uint8_t protected_id = 0;
uint8_t checksum = 0;
icsneoc2_lin_msg_type_t msg_type = 0;
bool is_enhanced_checksum = false;
res = icsneoc2_message_lin_props_get(messages[i], &id, &protected_id, &checksum, &msg_type, &is_enhanced_checksum);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get LIN properties", res);
continue;
}
icsneoc2_netid_t netid = 0;
icsneoc2_message_netid_get(messages[i], &netid);
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
uint8_t data[64] = {0};
size_t data_length = 64;
icsneoc2_message_data_get(messages[i], data, &data_length);
icsneoc2_lin_err_flags_t err_flags = 0;
icsneoc2_message_lin_err_flags_get(messages[i], &err_flags);
printf("\t%s RX | ID: 0x%02x | Protected ID: 0x%02x\n", netid_name, id, protected_id);
printf("\tData: [");
for(size_t x = 0; x < data_length; x++) {
printf(" 0x%02x", data[x]);
}
printf(" ]\n");
printf("\tChecksum type: %s\n", is_enhanced_checksum ? "Enhanced" : "Classic");
printf("\tChecksum: 0x%02x\n", checksum);
printf("\tChecksum valid: %s\n\n", (!(err_flags & ICSNEOC2_LIN_ERR_CHECKSUM_MATCH)) ? "yes" : "no");
}
}
int main() {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to open first device", res);
}
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_close(device);
return print_error_code("\tFailed to get device description", res);
}
printf("\tOpened device: %s\n\n", description);
/* Configure LIN settings */
int64_t baud = 19200;
printf("Enable LIN 01 commander resistor... ");
res = icsneoc2_settings_commander_resistor_set(device, icsneoc2_netid_lin_01, true);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Disable LIN 02 commander resistor... ");
res = icsneoc2_settings_commander_resistor_set(device, icsneoc2_netid_lin_02, false);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 01 baudrate to %" PRId64 " bit/s... ", baud);
res = icsneoc2_settings_baudrate_set(device, icsneoc2_netid_lin_01, baud);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 02 baudrate to %" PRId64 " bit/s... ", baud);
res = icsneoc2_settings_baudrate_set(device, icsneoc2_netid_lin_02, baud);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 01 mode to NORMAL... ");
res = icsneoc2_settings_lin_mode_set(device, icsneoc2_netid_lin_01, icsneoc2_lin_mode_normal);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 02 mode to NORMAL... ");
res = icsneoc2_settings_lin_mode_set(device, icsneoc2_netid_lin_02, icsneoc2_lin_mode_normal);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Applying settings... ");
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to apply settings", res);
}
printf("OK\n");
printf("Getting LIN 01 baudrate... ");
int64_t read_baud = 0;
res = icsneoc2_settings_baudrate_get(device, icsneoc2_netid_lin_01, &read_baud);
if(res == icsneoc2_error_success)
printf("OK, %" PRId64 " bit/s\n", read_baud);
else
printf("FAIL\n");
printf("Getting LIN 02 baudrate... ");
res = icsneoc2_settings_baudrate_get(device, icsneoc2_netid_lin_02, &read_baud);
if(res == icsneoc2_error_success)
printf("OK, %" PRId64 " bit/s\n\n", read_baud);
else
printf("FAIL\n\n");
/* Transmit a LIN responder data update on LIN 02 */
printf("Transmitting a LIN 02 responder data frame... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x11);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_update_responder;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, NULL);
uint8_t data[] = {0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22, 0x33, 0x44};
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_02);
res += icsneoc2_message_lin_calc_checksum(msg);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN responder message", res);
}
printf("OK\n");
}
/* Transmit a LIN commander header on LIN 01 */
printf("Transmitting a LIN 01 commander header... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x11);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_header_only;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, NULL);
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_01);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN header", res);
}
printf("OK\n\n");
}
sleep_ms(100);
/* Transmit a LIN commander message with data on LIN 01 */
printf("Transmitting a LIN 01 commander frame with data... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x22);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_commander_msg;
bool enhanced = true;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
uint8_t data[] = {0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd};
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_01);
res += icsneoc2_message_lin_calc_checksum(msg);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN commander message", res);
}
printf("OK\n\n");
}
sleep_ms(100);
/* Read back any received messages and display LIN frames */
icsneoc2_message_t* messages[2048] = {0};
size_t message_count = 2048;
printf("Getting messages...\n");
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(device, &messages[i], 0);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_message_free(messages[j]);
}
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to get messages", res);
}
if(messages[i] == NULL) {
message_count = i;
break;
}
}
printf("\tReceived %zu messages\n", message_count);
process_lin_messages(messages, message_count);
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
/* Cleanup */
print_events(description);
printf("Closing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-lin-transmit-example src/main.c)
target_link_libraries(libicsneoc2-lin-transmit-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-lin-transmit-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+276
View File
@@ -0,0 +1,276 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
int read_int(const char* prompt, int min_val, int max_val) {
int value;
while(1) {
printf("%s", prompt);
if(scanf("%d", &value) != 1) {
/* Clear invalid input */
int c;
while((c = getchar()) != '\n' && c != EOF) {}
printf("Invalid input, try again.\n");
continue;
}
if(value < min_val || value > max_val) {
printf("Please enter a value between %d and %d.\n", min_val, max_val);
continue;
}
return value;
}
}
int read_hex(const char* prompt, int min_val, int max_val) {
int value;
while(1) {
printf("%s", prompt);
if(scanf("%x", &value) != 1) {
/* Clear invalid input */
int c;
while((c = getchar()) != '\n' && c != EOF) {}
printf("Invalid input, try again.\n");
continue;
}
if(value < min_val || value > max_val) {
printf("Please enter a value between 0x%X and 0x%X.\n", min_val, max_val);
continue;
}
return value;
}
}
int main() {
icsneoc2_error_t res;
/* ===== Device Selection ===== */
printf("Searching for devices...\n");
icsneoc2_device_info_t* found_devices = NULL;
res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(!found_devices) {
printf("No devices found.\n");
return 1;
}
/* Count and display devices */
int device_count = 0;
for(icsneoc2_device_info_t* cur = found_devices; cur; cur = icsneoc2_device_info_next(cur)) {
char desc[128] = {0};
size_t desc_len = sizeof(desc);
icsneoc2_device_info_description_get(cur, desc, &desc_len);
printf(" [%d] %s\n", device_count + 1, desc);
device_count++;
}
int device_choice = read_int("Select device: ", 1, device_count);
/* Find the selected device_info node */
icsneoc2_device_info_t* selected_info = found_devices;
for(int i = 1; i < device_choice; i++) {
selected_info = icsneoc2_device_info_next(selected_info);
}
/* Open the selected device */
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(selected_info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device from device info", res);
}
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
icsneoc2_enumeration_free(found_devices);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to open device", res);
}
char description[128] = {0};
size_t description_length = sizeof(description);
icsneoc2_device_description_get(device, description, &description_length);
printf("Opened device: %s\n\n", description);
/* ===== LIN Network Selection ===== */
/* Get all supported TX networks */
size_t tx_net_count = 0;
res = icsneoc2_device_supported_tx_networks_get(device, NULL, &tx_net_count);
if(res != icsneoc2_error_success || tx_net_count == 0) {
printf("No supported TX networks.\n");
icsneoc2_device_close(device);
return 1;
}
icsneoc2_netid_t* tx_networks = (icsneoc2_netid_t*)malloc(tx_net_count * sizeof(icsneoc2_netid_t));
if(!tx_networks) {
printf("Out of memory.\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
res = icsneoc2_device_supported_tx_networks_get(device, tx_networks, &tx_net_count);
if(res != icsneoc2_error_success) {
free(tx_networks);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to get TX networks", res);
}
/* Filter for LIN networks */
icsneoc2_netid_t lin_networks[64] = {0};
char lin_names[64][128] = {{0}};
size_t lin_count = 0;
for(size_t i = 0; i < tx_net_count && lin_count < 64; i++) {
icsneoc2_message_t* tmp = NULL;
res = icsneoc2_message_lin_create(&tmp, 0);
if(res != icsneoc2_error_success) continue;
res = icsneoc2_message_netid_set(tmp, tx_networks[i]);
if(res != icsneoc2_error_success) { icsneoc2_message_free(tmp); continue; }
icsneoc2_network_type_t ntype = 0;
res = icsneoc2_message_network_type_get(tmp, &ntype);
icsneoc2_message_free(tmp);
if(res != icsneoc2_error_success) continue;
if(ntype == icsneoc2_network_type_lin) {
lin_networks[lin_count] = tx_networks[i];
size_t name_len = 128;
icsneoc2_netid_name_get(tx_networks[i], lin_names[lin_count], &name_len);
lin_count++;
}
}
free(tx_networks);
if(lin_count == 0) {
printf("No LIN networks available on this device.\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
printf("Available LIN networks:\n");
for(size_t i = 0; i < lin_count; i++) {
printf(" [%zu] %s\n", i + 1, lin_names[i]);
}
int lin_choice = read_int("Select LIN network: ", 1, (int)lin_count);
icsneoc2_netid_t selected_netid = lin_networks[lin_choice - 1];
printf("Selected: %s\n\n", lin_names[lin_choice - 1]);
/* ===== Commander / Responder Selection ===== */
printf("Message type:\n");
printf(" [1] Commander frame\n");
printf(" [2] Responder frame (update responder + header only)\n");
int type_choice = read_int("Select message type: ", 1, 2);
bool is_commander = (type_choice == 1);
printf("Selected: %s\n\n", is_commander ? "Commander" : "Responder");
uint8_t id_choice = (uint8_t)read_hex("Select LIN ID (0x00-0x3F): ", 0, 0x3F);
printf("Selected: 0x%02X\n\n", id_choice);
/* ===== Configure LIN ===== */
printf("Configuring %s... ", lin_names[lin_choice - 1]);
res = icsneoc2_settings_commander_resistor_set(device, selected_netid, is_commander);
res += icsneoc2_settings_baudrate_set(device, selected_netid, 19200);
res += icsneoc2_settings_lin_mode_set(device, selected_netid, icsneoc2_lin_mode_normal);
res += icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to configure LIN", res);
}
printf("OK\n\n");
/* ===== Transmit Loop ===== */
printf("Transmitting on %s every second for 10 seconds...\n", lin_names[lin_choice - 1]);
uint8_t counter = 0;
for(int i = 0; i < 10; i++) {
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, id_choice);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to create LIN message", res);
break;
}
uint8_t data[] = {counter, counter + 1, counter + 2, counter + 3, 0xAA, 0xBB, 0xCC, 0xDD};
bool enhanced = true;
if(is_commander) {
/* Commander: send header-only frame to poll the bus */
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_header_only;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
res += icsneoc2_message_netid_set(msg, selected_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_error_code("\tFailed to set commander properties", res);
break;
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to transmit header", res);
break;
}
} else {
/* Responder: update the responder table with new data */
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_update_responder;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_lin_calc_checksum(msg);
res += icsneoc2_message_netid_set(msg, selected_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_error_code("\tFailed to update responder", res);
break;
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to transmit responder update", res);
break;
}
}
printf("[%2d/10] Transmitted %s msg ID=0x%02X, counter=%u\n",
i + 1, is_commander ? "commander" : "responder", id_choice, counter);
counter += 4;
sleep_ms(1000);
}
/* Cleanup */
printf("\nClosing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
icsneoc2_device_free(device);
return 0;
}
+88 -15
View File
@@ -69,6 +69,8 @@ int print_error_code(const char* message, icsneoc2_error_t error) {
*/ */
int process_message(icsneoc2_message_t** messages, size_t messages_count); int process_message(icsneoc2_message_t** messages, size_t messages_count);
int transmit_can_messages(icsneoc2_device_t* device);
int main() { int main() {
// Open the first available device with default options // Open the first available device with default options
printf("Opening first available device...\n"); printf("Opening first available device...\n");
@@ -83,10 +85,15 @@ int main() {
size_t description_length = 255; size_t description_length = 255;
res = icsneoc2_device_description_get(open_device, description, &description_length); res = icsneoc2_device_description_get(open_device, description, &description_length);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get device description", res); return print_error_code("\tFailed to get device description", res);
}; };
printf("\tOpened device: %s\n", description); printf("\tOpened device: %s\n", description);
// Transmit messages for debugging purposes
// transmit_can_messages(open_device);
// sleep_ms(1000);
// Get the messages // Get the messages
icsneoc2_message_t* messages[20000] = {0}; icsneoc2_message_t* messages[20000] = {0};
size_t message_count = 20000; size_t message_count = 20000;
@@ -96,6 +103,7 @@ int main() {
res = icsneoc2_device_message_get(open_device, &messages[i], 0); res = icsneoc2_device_message_get(open_device, &messages[i], 0);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get messages from device", res); return print_error_code("\tFailed to get messages from device", res);
}; };
if(messages[i] == NULL) { if(messages[i] == NULL) {
@@ -106,6 +114,7 @@ int main() {
} }
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get messages from device", res); return print_error_code("\tFailed to get messages from device", res);
} }
time_t end_time = time(NULL); time_t end_time = time(NULL);
@@ -114,6 +123,7 @@ int main() {
res = process_message(messages, message_count); res = process_message(messages, message_count);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to process messages", res); return print_error_code("\tFailed to process messages", res);
} }
// Finally, close the device. // Finally, close the device.
@@ -121,8 +131,10 @@ int main() {
res = icsneoc2_device_close(open_device); res = icsneoc2_device_close(open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to close device", res); return print_error_code("\tFailed to close device", res);
}; };
icsneoc2_device_free(open_device);
printf("\n"); printf("\n");
return 0; return 0;
@@ -163,10 +175,49 @@ void print_events(const char* device_description) {
int process_message(icsneoc2_message_t** messages, size_t messages_count) { int process_message(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message // Print the type and bus type of each message
size_t tx_count = 0; size_t tx_count = 0;
size_t can_error_count = 0;
icsneoc2_error_t res = icsneoc2_error_success;
for(size_t i = 0; i < messages_count; i++) { for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i]; icsneoc2_message_t* message = messages[i];
bool is_can_error = false;
res = icsneoc2_message_is_can_error(message, &is_can_error);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a CAN error", res);
}
if(is_can_error) {
icsneoc2_network_type_t network_type;
uint8_t tec = 0;
uint8_t rec = 0;
icsneoc2_can_error_code_t error_code = 0;
icsneoc2_can_error_code_t data_error_code = 0;
icsneoc2_message_can_error_flags_t error_flags = 0;
icsneoc2_netid_t netid = 0;
char network_type_name[128] = {0};
size_t network_type_name_length = 128;
char netid_name[128] = {0};
size_t netid_name_length = 128;
res = icsneoc2_message_network_type_get(message, &network_type);
res += icsneoc2_network_type_name_get(network_type, network_type_name, &network_type_name_length);
res += icsneoc2_message_netid_get(message, &netid);
res += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get CAN error properties", res);
}
printf("\t%zd) CAN Error on %s [%s] (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
i, netid_name, network_type_name, netid, tec, rec, error_code, data_error_code,
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
can_error_count++;
continue;
}
bool is_frame = false; bool is_frame = false;
icsneoc2_error_t res = icsneoc2_message_is_frame(message, &is_frame); res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res); return print_error_code("\tFailed to check if message is a frame", res);
} }
@@ -186,37 +237,55 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type name", res); return print_error_code("\tFailed to get message bus type name", res);
} }
bool is_tx = false;
res = icsneoc2_message_is_transmit(message, &is_tx);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message is transmit", res); return print_error_code("\tFailed to get message is transmit", res);
} }
if(is_tx) {
tx_count++;
continue;
}
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type); printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) { if(network_type == icsneoc2_network_type_can) {
uint32_t arbid = 0; uint64_t arbid = 0;
int32_t dlc = 0; int32_t dlc = 0;
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
bool is_remote = false; icsneoc2_message_can_flags_t can_flags = 0;
bool is_canfd = false;
bool is_extended = false;
uint8_t data[64] = {0}; uint8_t data[64] = {0};
size_t data_length = 64; size_t data_length = 64;
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
bool is_error = false;
bool is_tx = false;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length); result += icsneoc2_message_data_get(message, data, &data_length);
result += icsneoc2_message_is_transmit(message, &is_tx);
result += icsneoc2_message_is_error(message, &is_error);
if(result != icsneoc2_error_success) { if(result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i); printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i);
continue; continue;
} }
printf("\t NetID: %s (0x%x)\tArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %zu\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length); tx_count += is_tx ? 1 : 0;
bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length;
printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : "");
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "",
is_extended ? " IDE" : "",
is_canfd ? " FDF" : "",
is_brs ? " BRS" : "",
is_esi ? " ESI" : "",
tx_aborted ? " TX_ABORTED" : "",
tx_lost_arb ? " TX_LOST_ARB" : "",
tx_error ? " TX_ERROR" : "");
printf("\t Data: ["); printf("\t Data: [");
for(size_t x = 0; x < data_length; x++) { for(size_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]); printf(" 0x%x", data[x]);
@@ -224,14 +293,14 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
printf(" ]\n"); printf(" ]\n");
} }
} }
printf("\tReceived %zu messages total, %zu were TX messages\n", messages_count, tx_count); printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
return icsneoc2_error_success; return icsneoc2_error_success;
} }
int transmit_can_messages(icsneoc2_device_t* device) { int transmit_can_messages(icsneoc2_device_t* device) {
uint64_t counter = 0; uint64_t counter = 0;
const size_t msg_count = 100; const size_t msg_count = 10;
printf("\tTransmitting %zd messages...\n", msg_count); printf("\tTransmitting %zd messages...\n", msg_count);
for(size_t i = 0; i < msg_count; i++) { for(size_t i = 0; i < msg_count; i++) {
// Create the message // Create the message
@@ -242,8 +311,12 @@ int transmit_can_messages(icsneoc2_device_t* device) {
} }
// Set the message attributes // Set the message attributes
res = icsneoc2_message_netid_set(message, icsneoc2_netid_dwcan_01); res = icsneoc2_message_netid_set(message, icsneoc2_netid_dwcan_01);
uint64_t arb_id = 0x10;
uint64_t flags = 0;
res += icsneoc2_message_can_props_set(message, &arb_id, &flags);
res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter)); res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter));
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("\tFailed to modify message", res); return print_error_code("\tFailed to modify message", res);
} }
res = icsneoc2_device_message_transmit(device, message); res = icsneoc2_device_message_transmit(device, message);
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-reconnect-example src/main.c)
target_link_libraries(libicsneoc2-reconnect-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-reconnect-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+132
View File
@@ -0,0 +1,132 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#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];
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 %d with error code %d\n", message, error, res);
return 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 = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
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);
}
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
/* Wait for the device to disconnect */
printf("Waiting for device to disconnect (unplug device from PC)...\n");
for(;;) {
bool is_open = true;
res = icsneoc2_device_is_open(device, &is_open);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_free(device);
return print_error_code("Failed to check open status", res);
}
if(!is_open) {
printf("Device disconnected!\n");
break;
}
sleep_ms(500);
}
/* Attempt to reconnect */
uint32_t timeout_ms = 20000; // 20 second timeout
printf("Attempting to reconnect (%u second timeout)...\n", timeout_ms / 1000);
res = icsneoc2_device_reconnect(device, icsneoc2_open_options_default, timeout_ms);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_free(device);
return print_error_code("Failed to reconnect", res);
}
printf("Reconnected successfully!\n");
/* Verify by getting the description again */
description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res == icsneoc2_error_success) {
printf("Device: %s\n", description);
}
/* Print any events */
print_events();
/* Close the device */
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);
printf("Done.\n");
return 0;
}
+105 -9
View File
@@ -116,6 +116,7 @@ int main() {
size_t description_length = 255; size_t description_length = 255;
res = icsneoc2_device_info_description_get(cur, description, &description_length); res = icsneoc2_device_info_description_get(cur, description, &description_length);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get device description", res); return print_error_code("\tFailed to get device description", res);
}; };
printf("%.*s\n", (int)description_length, description); printf("%.*s\n", (int)description_length, description);
@@ -126,8 +127,15 @@ int main() {
printf("\tDevice open options: 0x%x\n", options); printf("\tDevice open options: 0x%x\n", options);
printf("\tOpening device: %s...\n", description); printf("\tOpening device: %s...\n", description);
icsneoc2_device_t* open_device = NULL; icsneoc2_device_t* open_device = NULL;
res = icsneoc2_device_open(cur, options, &open_device); res = icsneoc2_device_create(cur, &open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to create device", res);
}
res = icsneoc2_device_open(open_device, options);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to open device", res); return print_error_code("\tFailed to open device", res);
}; };
@@ -137,6 +145,8 @@ int main() {
res = icsneoc2_device_timestamp_resolution_get(open_device, &timestamp_resolution); res = icsneoc2_device_timestamp_resolution_get(open_device, &timestamp_resolution);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get timestamp resolution", res); return print_error_code("\tFailed to get timestamp resolution", res);
} }
printf("%uns\n", timestamp_resolution); printf("%uns\n", timestamp_resolution);
@@ -146,6 +156,8 @@ int main() {
res = icsneoc2_settings_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &baudrate); res = icsneoc2_settings_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &baudrate);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get baudrate", res); return print_error_code("\tFailed to get baudrate", res);
}; };
printf("%" PRIu64 "mbit/s\n", baudrate); printf("%" PRIu64 "mbit/s\n", baudrate);
@@ -155,6 +167,8 @@ int main() {
res = icsneoc2_settings_canfd_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &fd_baudrate); res = icsneoc2_settings_canfd_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &fd_baudrate);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get FD baudrate", res); return print_error_code("\tFailed to get FD baudrate", res);
}; };
printf("%" PRIu64 "mbit/s\n", fd_baudrate); printf("%" PRIu64 "mbit/s\n", fd_baudrate);
@@ -165,6 +179,8 @@ int main() {
res = icsneoc2_settings_baudrate_set(open_device, icsneoc2_netid_dwcan_01, baudrate); res = icsneoc2_settings_baudrate_set(open_device, icsneoc2_netid_dwcan_01, baudrate);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set baudrate", res); return print_error_code("\tFailed to set baudrate", res);
}; };
printf("Ok\n"); printf("Ok\n");
@@ -173,6 +189,8 @@ int main() {
res = icsneoc2_settings_canfd_baudrate_set(open_device, icsneoc2_netid_dwcan_01, fd_baudrate); res = icsneoc2_settings_canfd_baudrate_set(open_device, icsneoc2_netid_dwcan_01, fd_baudrate);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set FD baudrate", res); return print_error_code("\tFailed to set FD baudrate", res);
}; };
printf("Ok\n"); printf("Ok\n");
@@ -181,6 +199,8 @@ int main() {
res = get_and_print_rtc(open_device); res = get_and_print_rtc(open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get RTC", res); return print_error_code("\tFailed to get RTC", res);
} }
// Set RTC // Set RTC
@@ -189,6 +209,8 @@ int main() {
res = icsneoc2_device_rtc_set(open_device, current_time); res = icsneoc2_device_rtc_set(open_device, current_time);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set RTC", res); return print_error_code("\tFailed to set RTC", res);
} }
printf("Ok\n"); printf("Ok\n");
@@ -197,6 +219,8 @@ int main() {
res = get_and_print_rtc(open_device); res = get_and_print_rtc(open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get RTC", res); return print_error_code("\tFailed to get RTC", res);
} }
// Go online, start acking traffic // Go online, start acking traffic
@@ -204,6 +228,8 @@ int main() {
res = icsneoc2_device_go_online(open_device, true); res = icsneoc2_device_go_online(open_device, true);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to go online", res); return print_error_code("\tFailed to go online", res);
} }
// Redundant check to show how to check if the device is online, if the previous // Redundant check to show how to check if the device is online, if the previous
@@ -212,6 +238,8 @@ int main() {
res = icsneoc2_device_is_online(open_device, &is_online); res = icsneoc2_device_is_online(open_device, &is_online);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to check if online", res); return print_error_code("\tFailed to check if online", res);
} }
printf("%s\n", is_online ? "Online" : "Offline"); printf("%s\n", is_online ? "Online" : "Offline");
@@ -219,6 +247,8 @@ int main() {
res = transmit_can_messages(open_device); res = transmit_can_messages(open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to transmit CAN messages", res); return print_error_code("\tFailed to transmit CAN messages", res);
} }
// Wait for the bus to collect some messages, requires an active bus to get messages // Wait for the bus to collect some messages, requires an active bus to get messages
@@ -231,7 +261,12 @@ int main() {
for(size_t i = 0; i < message_count; ++i) { for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(open_device, &messages[i], 0); res = icsneoc2_device_message_get(open_device, &messages[i], 0);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_message_free(messages[j]);
}
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get messages from device", res); return print_error_code("\tFailed to get messages from device", res);
}; };
if(messages[i] == NULL) { if(messages[i] == NULL) {
@@ -243,7 +278,12 @@ int main() {
// Process the messages // Process the messages
res = process_messages(messages, message_count); res = process_messages(messages, message_count);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to process messages", res); return print_error_code("\tFailed to process messages", res);
} }
for(size_t i = 0; i < message_count; ++i) { for(size_t i = 0; i < message_count; ++i) {
@@ -254,11 +294,13 @@ int main() {
res = icsneoc2_device_close(open_device); res = icsneoc2_device_close(open_device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to close device", res); return print_error_code("\tFailed to close device", res);
}; };
// Print device events // Print device events
print_events(description); print_events(description);
icsneoc2_device_free(open_device);
} }
icsneoc2_enumeration_free(found_devices); icsneoc2_enumeration_free(found_devices);
printf("\n"); printf("\n");
@@ -285,6 +327,9 @@ void print_events(const char* device_description) {
// no device filter, get all events // no device filter, get all events
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL); icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_event_free(events[j]);
}
(void)print_error_code("\tFailed to get device events", res); (void)print_error_code("\tFailed to get device events", res);
return; return;
} }
@@ -313,10 +358,42 @@ void print_events(const char* device_description) {
int process_messages(icsneoc2_message_t** messages, size_t messages_count) { int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message // Print the type and bus type of each message
size_t tx_count = 0; size_t tx_count = 0;
size_t can_error_count = 0;
for(size_t i = 0; i < messages_count; i++) { for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i]; icsneoc2_message_t* message = messages[i];
// Check for CAN error messages
bool is_can_error = false;
icsneoc2_error_t res = icsneoc2_message_is_can_error(message, &is_can_error);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a CAN error", res);
}
if(is_can_error) {
uint8_t tec = 0;
uint8_t rec = 0;
icsneoc2_can_error_code_t error_code = 0;
icsneoc2_can_error_code_t data_error_code = 0;
icsneoc2_message_can_error_flags_t error_flags = 0;
icsneoc2_netid_t netid = 0;
res = icsneoc2_message_netid_get(message, &netid);
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get CAN error properties", res);
}
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
printf("\t%zd) CAN Error on %s (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
i, netid_name, netid, tec, rec, error_code, data_error_code,
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
can_error_count++;
continue;
}
bool is_frame = false; bool is_frame = false;
icsneoc2_error_t res = icsneoc2_message_is_frame(message, &is_frame); res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res); return print_error_code("\tFailed to check if message is a frame", res);
} }
@@ -349,24 +426,42 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type); printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) { if(network_type == icsneoc2_network_type_can) {
uint32_t arbid = 0; uint64_t arbid = 0;
int32_t dlc = 0; int32_t dlc = 0;
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
bool is_remote = false; icsneoc2_message_can_flags_t can_flags = 0;
bool is_canfd = false;
bool is_extended = false;
uint8_t data[64] = {0}; uint8_t data[64] = {0};
size_t data_length = 64; size_t data_length = 64;
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length); result += icsneoc2_message_data_get(message, data, &data_length);
if(result != icsneoc2_error_success) { if(result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i); printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i);
continue; continue;
} }
printf("\t NetID: %s (0x%x)\tArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %zu\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length); bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length;
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "",
is_extended ? " IDE" : "",
is_canfd ? " FDF" : "",
is_brs ? " BRS" : "",
is_esi ? " ESI" : "",
tx_aborted ? " TX_ABORTED" : "",
tx_lost_arb ? " TX_LOST_ARB" : "",
tx_error ? " TX_ERROR" : "");
printf("\t Data: ["); printf("\t Data: [");
for(size_t x = 0; x < data_length; x++) { for(size_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]); printf(" 0x%x", data[x]);
@@ -374,7 +469,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
printf(" ]\n"); printf(" ]\n");
} }
} }
printf("\tReceived %zu messages total, %zu were TX messages\n", messages_count, tx_count); printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -397,6 +492,7 @@ int transmit_can_messages(icsneoc2_device_t* device) {
res += icsneoc2_message_can_props_set(message, &arb_id, &flags); res += icsneoc2_message_can_props_set(message, &arb_id, &flags);
res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter)); res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter));
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("\tFailed to modify message", res); return print_error_code("\tFailed to modify message", res);
} }
res = icsneoc2_device_message_transmit(device, message); res = icsneoc2_device_message_transmit(device, message);
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-t1s-loopback-example src/main.c)
target_link_libraries(libicsneoc2-t1s-loopback-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-t1s-loopback-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+643
View File
@@ -0,0 +1,643 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#define TX_LOCAL_ID 0u
#define RX_LOCAL_ID 1u
#define T1S_MAX_NODES 8u
#define T1S_TX_OPP_TIMER 20u
#define T1S_BURST_TIMER 64u
#define T1S_MAX_BURST 128u
#define LOOPBACK_ETHER_TYPE 0x9000u
#define LOOPBACK_FRAME_SIZE 60u
typedef struct selectable_network {
icsneoc2_netid_t netid;
char name[64];
} selectable_network_t;
/* Sleep for a short period while waiting for the device to apply settings. */
static void sleep_ms(uint32_t ms);
/* Print a readable error string and return the same failure code to the caller. */
static int print_error_code(const char* message, icsneoc2_error_t error);
/* Drain and print queued library events when the example encounters an error. */
static void print_events(void);
/* Convert a netid to a readable name such as "AE 02". */
static int get_netid_name(icsneoc2_netid_t netid, char* buffer, size_t buffer_size);
/* Gather the device's TX and RX networks, keeping only automotive Ethernet ports. */
static int get_available_networks(const icsneoc2_device_t* device,
selectable_network_t* tx_networks,
size_t* tx_count,
selectable_network_t* rx_networks,
size_t* rx_count);
/* Prompt the user to choose one TX or RX network from the filtered list. */
static int prompt_for_network_selection(const char* label, const selectable_network_t* networks, size_t count, icsneoc2_netid_t* selected_netid, char* selected_name, size_t selected_name_size);
/* Apply the small set of T1S settings needed for this two-port loopback example. */
static int configure_t1s_port(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t local_id);
/* Print a MAC address in a compact human-readable form. */
static void print_mac(const char* label, const uint8_t* mac);
/* Print payload bytes as hex for the TX echo and RX frame output. */
static void print_payload_hex(const uint8_t* data, size_t length);
/* Build one recognizable Ethernet frame that both transmit and receive paths share. */
static void build_loopback_frame(uint8_t* frame_data, size_t frame_size, const char* tx_name, const char* rx_name);
/* Check whether a received Ethernet frame matches the loopback frame this example sent. */
static int message_matches_loopback_frame(icsneoc2_message_t* message, const uint8_t* expected, size_t expected_length, bool* matches);
/* Print the key details of an Ethernet message found during the loopback test. */
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label);
/* Transmit the loopback Ethernet frame on the selected TX port. */
static int transmit_loopback_frame(icsneoc2_device_t* device, icsneoc2_netid_t tx_netid, const char* tx_name, const char* rx_name);
/* Poll until the example sees both the TX echo and the matching RX frame. */
static int poll_for_loopback_messages(icsneoc2_device_t* device,
icsneoc2_netid_t tx_netid,
icsneoc2_netid_t rx_netid,
const char* tx_name,
const char* rx_name,
const uint8_t* expected_frame,
size_t expected_frame_length);
int main(void) {
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res;
char description[255] = {0};
char serial[64] = {0};
size_t description_length = sizeof(description);
size_t serial_length = sizeof(serial);
selectable_network_t available_tx_networks[128] = {0};
selectable_network_t available_rx_networks[128] = {0};
size_t available_tx_count = 0;
size_t available_rx_count = 0;
icsneoc2_netid_t tx_netid = 0;
icsneoc2_netid_t rx_netid = 0;
uint8_t expected_frame[LOOPBACK_FRAME_SIZE] = {0};
char tx_name[64] = {0};
char rx_name[64] = {0};
int status = 1;
printf("RAD-Comet3 C2 T1S loopback example\n");
printf("Opening first available RAD-Comet3...\n");
res = icsneoc2_device_open_first(icsneoc2_devicetype_rad_comet3, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open a RAD-Comet3", res);
}
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get device description", res);
goto cleanup;
}
res = icsneoc2_device_serial_get(device, serial, &serial_length);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get device serial", res);
goto cleanup;
}
printf("Opened device: %s [%s]\n", description, serial);
if(get_available_networks(device, available_tx_networks, &available_tx_count, available_rx_networks, &available_rx_count) != 0) {
goto cleanup;
}
if(prompt_for_network_selection("TX", available_tx_networks, available_tx_count, &tx_netid, tx_name, sizeof(tx_name)) != 0) {
goto cleanup;
}
if(prompt_for_network_selection("RX", available_rx_networks, available_rx_count, &rx_netid, rx_name, sizeof(rx_name)) != 0) {
goto cleanup;
}
printf("Selected loopback wiring: %s connected to %s\n", tx_name, rx_name);
if(tx_netid == rx_netid) {
printf("TX and RX networks are the same. This example is intended for a physical loopback between two ports.\n");
goto cleanup;
}
// Use the same expected frame bytes for transmit and for receive-side matching.
build_loopback_frame(expected_frame, sizeof(expected_frame), tx_name, rx_name);
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success) {
print_error_code("Failed to refresh device settings", res);
goto cleanup;
}
if(configure_t1s_port(device, tx_netid, TX_LOCAL_ID) != 0) {
goto cleanup;
}
if(configure_t1s_port(device, rx_netid, RX_LOCAL_ID) != 0) {
goto cleanup;
}
printf("Applying T1S settings to the device.\n");
printf("Note: icsneoc2_settings_apply() persists these settings on the device.\n");
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
print_error_code("Failed to apply T1S settings", res);
goto cleanup;
}
sleep_ms(500);
if(transmit_loopback_frame(device, tx_netid, tx_name, rx_name) != 0) {
goto cleanup;
}
if(poll_for_loopback_messages(device, tx_netid, rx_netid, tx_name, rx_name, expected_frame, sizeof(expected_frame)) != 0) {
print_events();
goto cleanup;
}
status = 0;
cleanup:
if(device != NULL) {
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to close device", res);
}
res = icsneoc2_device_free(device);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to free device", res);
}
}
return status;
}
static void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
static 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;
}
static void print_events(void) {
icsneoc2_event_t* events[64] = {0};
size_t count = sizeof(events) / sizeof(events[0]);
for(size_t i = 0; i < count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to get events", res);
return;
}
if(events[i] == NULL) {
count = i;
break;
}
}
for(size_t i = 0; i < 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) {
printf("Event %zu: %s\n", i, description);
}
icsneoc2_event_free(events[i]);
}
}
static int get_netid_name(icsneoc2_netid_t netid, char* buffer, size_t buffer_size) {
size_t length = buffer_size;
icsneoc2_error_t res = icsneoc2_netid_name_get(netid, buffer, &length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get netid name", res);
}
return 0;
}
static int get_available_networks(const icsneoc2_device_t* device,
selectable_network_t* tx_networks,
size_t* tx_count,
selectable_network_t* rx_networks,
size_t* rx_count) {
icsneoc2_netid_t supported_tx_networks[128] = {0};
icsneoc2_netid_t supported_rx_networks[128] = {0};
size_t tx_supported_count = sizeof(supported_tx_networks) / sizeof(supported_tx_networks[0]);
size_t rx_supported_count = sizeof(supported_rx_networks) / sizeof(supported_rx_networks[0]);
icsneoc2_message_t* probe = NULL;
icsneoc2_network_type_t network_type = 0;
icsneoc2_error_t res = icsneoc2_device_supported_tx_networks_get(device, supported_tx_networks, &tx_supported_count);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get supported TX networks", res);
}
res = icsneoc2_device_supported_rx_networks_get(device, supported_rx_networks, &rx_supported_count);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get supported RX networks", res);
}
*tx_count = 0;
*rx_count = 0;
// Reuse one temporary Ethernet message to classify each netid by network type.
res = icsneoc2_message_eth_create(&probe);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to create temporary Ethernet message", res);
}
for(size_t i = 0; i < tx_supported_count; ++i) {
res = icsneoc2_message_netid_set(probe, supported_tx_networks[i]);
if(res != icsneoc2_error_success) {
continue;
}
res = icsneoc2_message_network_type_get(probe, &network_type);
if(res != icsneoc2_error_success || network_type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
tx_networks[*tx_count].netid = supported_tx_networks[i];
if(get_netid_name(supported_tx_networks[i], tx_networks[*tx_count].name, sizeof(tx_networks[*tx_count].name)) != 0) {
icsneoc2_message_free(probe);
return 1;
}
(*tx_count)++;
}
for(size_t i = 0; i < rx_supported_count; ++i) {
res = icsneoc2_message_netid_set(probe, supported_rx_networks[i]);
if(res != icsneoc2_error_success) {
continue;
}
res = icsneoc2_message_network_type_get(probe, &network_type);
if(res != icsneoc2_error_success || network_type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
rx_networks[*rx_count].netid = supported_rx_networks[i];
if(get_netid_name(supported_rx_networks[i], rx_networks[*rx_count].name, sizeof(rx_networks[*rx_count].name)) != 0) {
icsneoc2_message_free(probe);
return 1;
}
(*rx_count)++;
}
icsneoc2_message_free(probe);
if(*tx_count == 0) {
printf("No automotive Ethernet TX networks are available on this device.\n");
return 1;
}
if(*rx_count == 0) {
printf("No automotive Ethernet RX networks are available on this device.\n");
return 1;
}
return 0;
}
static int prompt_for_network_selection(const char* label, const selectable_network_t* networks, size_t count, icsneoc2_netid_t* selected_netid, char* selected_name, size_t selected_name_size) {
char input[32] = {0};
char* end_ptr = NULL;
long selected_index = 0;
if(!label || !networks || count == 0 || !selected_netid || !selected_name || selected_name_size == 0) {
return print_error_code("Invalid network selection parameters", icsneoc2_error_invalid_parameters);
}
printf("Available automotive Ethernet %s networks:\n", label);
for(size_t i = 0; i < count; ++i) {
printf(" %zu) %s\n", i + 1, networks[i].name);
}
printf("Select %s network [1-%zu, default 1]: ", label, count);
if(fgets(input, sizeof(input), stdin) == NULL || input[0] == '\n') {
selected_index = 1;
} else {
selected_index = strtol(input, &end_ptr, 10);
if(end_ptr == input || selected_index < 1 || (size_t)selected_index > count) {
printf("Invalid selection, using %s.\n", networks[0].name);
selected_index = 1;
}
}
*selected_netid = networks[selected_index - 1].netid;
strncpy(selected_name, networks[selected_index - 1].name, selected_name_size - 1);
selected_name[selected_name_size - 1] = '\0';
return 0;
}
static int configure_t1s_port(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t local_id) {
char netid_name[64] = {0};
icsneoc2_error_t res;
bool termination = false;
if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) {
return 1;
}
printf("Configuring %s: PLCA on, LocalID=%u, MaxNodes=%u, TxOpp=%u, BurstTimer=%u, MaxBurst=%u\n",
netid_name,
(unsigned)local_id,
(unsigned)T1S_MAX_NODES,
(unsigned)T1S_TX_OPP_TIMER,
(unsigned)T1S_BURST_TIMER,
(unsigned)T1S_MAX_BURST);
// Keep the example explicit about the small set of T1S settings needed for loopback.
res = icsneoc2_settings_t1s_plca_enabled_for_set(device, netid, true);
if(res != icsneoc2_error_success) return print_error_code("Failed to enable T1S PLCA", res);
res = icsneoc2_settings_t1s_local_id_set(device, netid, local_id);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S local ID", res);
res = icsneoc2_settings_t1s_max_nodes_set(device, netid, T1S_MAX_NODES);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S max nodes", res);
res = icsneoc2_settings_t1s_tx_opp_timer_set(device, netid, T1S_TX_OPP_TIMER);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S TX opportunity timer", res);
res = icsneoc2_settings_t1s_burst_timer_set(device, netid, T1S_BURST_TIMER);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S burst timer", res);
res = icsneoc2_settings_t1s_max_burst_timer_for_set(device, netid, T1S_MAX_BURST);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S max burst", res);
res = icsneoc2_settings_t1s_is_termination_enabled_for(device, netid, &termination);
if(res == icsneoc2_error_success) {
res = icsneoc2_settings_t1s_termination_for_set(device, netid, true);
if(res != icsneoc2_error_success) return print_error_code("Failed to enable T1S termination", res);
} else if(res != icsneoc2_error_get_settings_failure) {
return print_error_code("Failed to query T1S termination support", res);
}
return 0;
}
static void print_mac(const char* label, const uint8_t* mac) {
printf("%s %02x:%02x:%02x:%02x:%02x:%02x", label, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
static void print_payload_hex(const uint8_t* data, size_t length) {
for(size_t i = 0; i < length; ++i) {
printf("%02x", data[i]);
if(i + 1 < length) {
printf(" ");
}
}
printf("\n");
}
static void build_loopback_frame(uint8_t* frame_data, size_t frame_size, const char* tx_name, const char* rx_name) {
const char* tx_label = tx_name ? tx_name : "TX";
const char* rx_label = rx_name ? rx_name : "RX";
// Build one recognizable Ethernet frame so the receive side can match exactly what we sent.
memset(frame_data, 0, frame_size);
frame_data[0] = 0x00;
frame_data[1] = 0xFC;
frame_data[2] = 0x70;
frame_data[3] = 0x00;
frame_data[4] = 0x00;
frame_data[5] = 0x02;
frame_data[6] = 0x00;
frame_data[7] = 0xFC;
frame_data[8] = 0x70;
frame_data[9] = 0x00;
frame_data[10] = 0x00;
frame_data[11] = 0x01;
frame_data[12] = (uint8_t)((LOOPBACK_ETHER_TYPE >> 8) & 0xFF);
frame_data[13] = (uint8_t)(LOOPBACK_ETHER_TYPE & 0xFF);
snprintf((char*)&frame_data[14], frame_size - 14, "C2 T1S loopback %s->%s", tx_label, rx_label);
}
static int message_matches_loopback_frame(icsneoc2_message_t* message, const uint8_t* expected, size_t expected_length, bool* matches) {
uint8_t data[1600] = {0};
size_t data_length = sizeof(data);
uint16_t ether_type = 0;
icsneoc2_error_t res;
if(!expected || !matches || expected_length < 14) {
return print_error_code("Invalid loopback match output", icsneoc2_error_invalid_parameters);
}
*matches = false;
res = icsneoc2_message_eth_ether_type_get(message, &ether_type);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to read loopback EtherType", res);
}
if(ether_type != LOOPBACK_ETHER_TYPE) {
return 0;
}
res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to read loopback frame data", res);
}
if(data_length < 14) {
return 0;
}
if(data_length >= expected_length) {
*matches = memcmp(data, expected, expected_length) == 0;
} else {
*matches = memcmp(data, expected, data_length) == 0;
}
return 0;
}
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) {
icsneoc2_netid_t netid = 0;
char netid_name[64] = {0};
uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0};
uint16_t ether_type = 0;
icsneoc2_message_eth_t1s_flags_t t1s_flags = 0;
uint8_t node_id = 0;
uint8_t burst_count = 0;
uint8_t symbol_type = 0;
uint8_t data[1600] = {0};
size_t data_length = sizeof(data);
icsneoc2_error_t res;
res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message netid", res);
if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) return 1;
res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) return print_error_code("Failed to get Ethernet data", res);
printf("%s on %s: %zu bytes\n", direction_label, netid_name, data_length);
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) {
print_mac(" Dst", dst_mac);
printf(" ");
print_mac("Src", src_mac);
printf("\n");
}
res = icsneoc2_message_eth_ether_type_get(message, &ether_type);
if(res == icsneoc2_error_success) {
printf(" EtherType: 0x%04x\n", ether_type);
}
res = icsneoc2_message_eth_t1s_props_get(message, &t1s_flags, &node_id, &burst_count, &symbol_type);
if(res == icsneoc2_error_success && (t1s_flags != 0 || node_id != 0 || burst_count != 0 || symbol_type != 0)) {
printf(" T1S: node=%u burst=%u symbol=%u", (unsigned)node_id, (unsigned)burst_count, (unsigned)symbol_type);
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL) printf(" [SYMBOL]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST) printf(" [BURST]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION) printf(" [TX_COLLISION]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE) printf(" [WAKE]");
printf("\n");
}
printf(" Payload bytes: ");
if(data_length > 14) {
print_payload_hex(&data[14], data_length - 14);
} else {
printf("<none>\n");
}
return 0;
}
static int transmit_loopback_frame(icsneoc2_device_t* device, icsneoc2_netid_t tx_netid, const char* tx_name, const char* rx_name) {
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res;
uint8_t frame_data[LOOPBACK_FRAME_SIZE] = {0};
build_loopback_frame(frame_data, sizeof(frame_data), tx_name, rx_name);
res = icsneoc2_message_eth_create(&message);
if(res != icsneoc2_error_success) return print_error_code("Failed to create Ethernet message", res);
res = icsneoc2_message_netid_set(message, tx_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to set Ethernet netid", res);
}
res = icsneoc2_message_data_set(message, frame_data, sizeof(frame_data));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to set Ethernet payload", res);
}
printf("Transmitting one T1S loopback frame on %s...\n", tx_name ? tx_name : "selected TX network");
res = icsneoc2_device_message_transmit(device, message);
icsneoc2_message_free(message);
if(res != icsneoc2_error_success) return print_error_code("Failed to transmit loopback frame", res);
return 0;
}
static int poll_for_loopback_messages(icsneoc2_device_t* device,
icsneoc2_netid_t tx_netid,
icsneoc2_netid_t rx_netid,
const char* tx_name,
const char* rx_name,
const uint8_t* expected_frame,
size_t expected_frame_length) {
bool saw_tx_echo = false;
bool saw_rx_frame = false;
printf("Polling for TX echo on %s and RX frame on %s...\n", tx_name, rx_name);
for(size_t attempt = 0; attempt < 60 && !(saw_tx_echo && saw_rx_frame); ++attempt) {
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_device_message_get(device, &message, 100);
if(res != icsneoc2_error_success) {
return print_error_code("Failed while polling for loopback messages", res);
}
if(message == NULL) {
continue;
}
bool is_ethernet = false;
bool matches_loopback = false;
res = icsneoc2_message_is_ethernet(message, &is_ethernet);
if(res != icsneoc2_error_success || !is_ethernet) {
icsneoc2_message_free(message);
continue;
}
icsneoc2_netid_t netid = 0;
res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to get polled netid", res);
}
if(netid != tx_netid && netid != rx_netid) {
icsneoc2_message_free(message);
continue;
}
// Ignore unrelated traffic on the selected ports and only count the frame this example transmitted.
if(message_matches_loopback_frame(message, expected_frame, expected_frame_length, &matches_loopback) != 0) {
icsneoc2_message_free(message);
return 1;
}
if(!matches_loopback) {
icsneoc2_message_free(message);
continue;
}
bool is_tx = false;
res = icsneoc2_message_is_transmit(message, &is_tx);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to determine TX status", res);
}
if(netid == tx_netid && is_tx && !saw_tx_echo) {
if(print_ethernet_message(message, "TX echo") != 0) {
icsneoc2_message_free(message);
return 1;
}
saw_tx_echo = true;
} else if(netid == rx_netid && !saw_rx_frame) {
if(print_ethernet_message(message, "RX frame") != 0) {
icsneoc2_message_free(message);
return 1;
}
if(is_tx) {
printf(" Note: RX port message was also marked as transmit.\n");
}
saw_rx_frame = true;
}
icsneoc2_message_free(message);
}
if(!saw_tx_echo || !saw_rx_frame) {
printf("Loopback incomplete: saw_tx_echo=%s, saw_rx_frame=%s\n",
saw_tx_echo ? "true" : "false",
saw_rx_frame ? "true" : "false");
printf("Confirm %s is physically connected to %s and both ports are configured for 10BASE-T1S.\n", tx_name, rx_name);
return 1;
}
printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-tc10-example src/main.c)
target_link_libraries(libicsneoc2-tc10-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-tc10-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+393
View File
@@ -0,0 +1,393 @@
/*
* TC10 example.
*
* Sends TC10 wake/sleep requests, queries TC10 status, or lists connected
* devices and the Automotive Ethernet networks they support. Loosely based
* on examples/python/tc10/tc10.py. If --serial is omitted, the first
* available device is used.
*/
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* serial; /* may be NULL */
const char** networks; /* points into argv */
size_t networks_count;
bool send_wake;
bool send_sleep;
bool status;
bool list;
} args_t;
static int print_error_code(const char* message, icsneoc2_error_t error);
static void str_tolower(char* s);
static bool resolve_netid(const char* name, icsneoc2_netid_t* out);
static void print_usage(const char* prog);
static int parse_args(int argc, char** argv, args_t* out);
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial);
static int list_devices(icsneoc2_device_info_t* list);
static const char* tc10_wake_status_str(icsneoc2_tc10_wake_status_t s);
static const char* tc10_sleep_status_str(icsneoc2_tc10_sleep_status_t s);
int main(int argc, char** argv) {
args_t args;
if(parse_args(argc, argv, &args) != 0) {
return 1;
}
icsneoc2_device_info_t* found_devices = NULL;
icsneoc2_error_t res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(found_devices == NULL) {
fprintf(stderr, "error: no devices found\n");
return 1;
}
if(args.list) {
int rc = list_devices(found_devices);
icsneoc2_enumeration_free(found_devices);
return rc;
}
icsneoc2_device_info_t* info = find_device(found_devices, args.serial);
if(info == NULL) {
fprintf(stderr, "error: unable to find device %s\n", args.serial ? args.serial : "(any)");
icsneoc2_enumeration_free(found_devices);
return 1;
}
char description[256] = {0};
size_t description_len = sizeof(description);
res = icsneoc2_device_info_description_get(info, description, &description_len);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to get device description", res);
}
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device", res);
}
printf("Opening device %s\n", description);
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to open device", res);
}
bool supports_tc10 = false;
res = icsneoc2_device_supports_tc10(device, &supports_tc10);
if(res != icsneoc2_error_success || !supports_tc10) {
fprintf(stderr, "error: device does not support TC10 (%s)\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return 1;
}
int rc = 0;
for(size_t i = 0; i < args.networks_count; ++i) {
const char* name = args.networks[i];
icsneoc2_netid_t netid = icsneoc2_netid_invalid;
if(!resolve_netid(name, &netid)) {
fprintf(stderr, "error: unknown network '%s'\n", name);
rc = 1;
break;
}
if(args.send_wake) {
printf("requesting TC10 wake on network %s\n", name);
res = icsneoc2_device_tc10_wake_request(device, netid);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to send TC10 wake", res);
break;
}
} else if(args.send_sleep) {
printf("requesting TC10 sleep on network %s\n", name);
res = icsneoc2_device_tc10_sleep_request(device, netid);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to send TC10 sleep", res);
break;
}
} else { /* args.status */
icsneoc2_tc10_sleep_status_t sleep_s = icsneoc2_tc10_sleep_status_no_sleep_received;
icsneoc2_tc10_wake_status_t wake_s = icsneoc2_tc10_wake_status_no_wake_received;
res = icsneoc2_device_tc10_status_get(device, netid, &sleep_s, &wake_s);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to get TC10 status", res);
break;
}
printf("TC10 status on network %s: wake=%s sleep=%s\n", name,
tc10_wake_status_str(wake_s), tc10_sleep_status_str(sleep_s));
}
}
printf("Closing device %s\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return rc;
}
static int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
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 %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
static void str_tolower(char* s) {
for(; *s; ++s) {
*s = (char)tolower((unsigned char)*s);
}
}
/*
* Resolve a network name (e.g. "ETHERNET_01", "ae_01") to its icsneoc2_netid_t
* by iterating over all known netids and comparing names case-insensitively.
*/
static bool resolve_netid(const char* name, icsneoc2_netid_t* out) {
char want[64];
strncpy(want, name, sizeof(want) - 1);
want[sizeof(want) - 1] = '\0';
str_tolower(want);
for(uint16_t i = 0; i < icsneoc2_netid_maxsize; ++i) {
char buf[64];
size_t buf_len = sizeof(buf);
if(icsneoc2_netid_name_get((icsneoc2_netid_t)i, buf, &buf_len) != icsneoc2_error_success) {
continue;
}
str_tolower(buf);
if(strcmp(buf, want) == 0) {
*out = (icsneoc2_netid_t)i;
return true;
}
}
return false;
}
static void print_usage(const char* prog) {
printf("Usage:\n");
printf(" %s --list\n", prog);
printf(" %s [--serial SERIAL] --networks NET1 [NET2 ...] (--send-wake | --send-sleep | --status)\n", prog);
printf("\n");
printf(" --list List connected devices and the Automotive Ethernet networks they support.\n");
printf(" --serial SERIAL Serial number of the device. If omitted, the first available device is used.\n");
printf(" --networks NET ... One or more network names (e.g. ETHERNET_01 AE_01). Consumes args until the next flag.\n");
printf(" --send-wake Trigger TC10 wake on the selected networks.\n");
printf(" --send-sleep Trigger TC10 sleep on the selected networks.\n");
printf(" --status Query TC10 wake/sleep status on the selected networks.\n");
printf(" -h, --help Show this message.\n");
}
static int parse_args(int argc, char** argv, args_t* out) {
memset(out, 0, sizeof(*out));
for(int i = 1; i < argc; ++i) {
const char* a = argv[i];
if(strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
print_usage(argv[0]);
exit(0);
} else if(strcmp(a, "--serial") == 0) {
if(i + 1 >= argc) {
fprintf(stderr, "error: --serial requires a value\n");
return 1;
}
out->serial = argv[++i];
} else if(strcmp(a, "--send-wake") == 0) {
out->send_wake = true;
} else if(strcmp(a, "--send-sleep") == 0) {
out->send_sleep = true;
} else if(strcmp(a, "--status") == 0) {
out->status = true;
} else if(strcmp(a, "--list") == 0) {
out->list = true;
} else if(strcmp(a, "--networks") == 0) {
if(i + 1 >= argc || argv[i + 1][0] == '-') {
fprintf(stderr, "error: --networks requires at least one network name\n");
return 1;
}
out->networks = (const char**)&argv[i + 1];
size_t count = 0;
while(i + 1 < argc && argv[i + 1][0] != '-') {
++count;
++i;
}
out->networks_count = count;
} else {
fprintf(stderr, "error: unknown argument '%s'\n", a);
print_usage(argv[0]);
return 1;
}
}
if(out->list) {
if(out->send_wake || out->send_sleep || out->status || out->networks_count > 0 || out->serial) {
fprintf(stderr, "error: --list cannot be combined with other options\n");
print_usage(argv[0]);
return 1;
}
return 0;
}
if(out->networks_count == 0) {
fprintf(stderr, "error: --networks is required\n");
print_usage(argv[0]);
return 1;
}
int action_count = (out->send_wake ? 1 : 0) + (out->send_sleep ? 1 : 0) + (out->status ? 1 : 0);
if(action_count != 1) {
fprintf(stderr, "error: exactly one of --send-wake, --send-sleep, or --status is required\n");
print_usage(argv[0]);
return 1;
}
return 0;
}
static const char* tc10_wake_status_str(icsneoc2_tc10_wake_status_t s) {
switch(s) {
case icsneoc2_tc10_wake_status_no_wake_received: return "no_wake_received";
case icsneoc2_tc10_wake_status_wake_received: return "wake_received";
default: return "unknown";
}
}
static const char* tc10_sleep_status_str(icsneoc2_tc10_sleep_status_t s) {
switch(s) {
case icsneoc2_tc10_sleep_status_no_sleep_received: return "no_sleep_received";
case icsneoc2_tc10_sleep_status_sleep_received: return "sleep_received";
case icsneoc2_tc10_sleep_status_sleep_failed: return "sleep_failed";
case icsneoc2_tc10_sleep_status_sleep_aborted: return "sleep_aborted";
default: return "unknown";
}
}
/*
* Find a device matching the provided serial, or the first available device if serial is NULL.
* Returns NULL on failure (caller is responsible for the enumeration list).
*/
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial) {
if(serial == NULL) {
return list;
}
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
char dev_serial[64] = {0};
size_t dev_serial_len = sizeof(dev_serial);
if(icsneoc2_device_info_serial_get(cur, dev_serial, &dev_serial_len) != icsneoc2_error_success) {
continue;
}
if(strcmp(dev_serial, serial) == 0) {
return cur;
}
}
return NULL;
}
/*
* List connected devices and the Automotive Ethernet networks each one supports.
*/
static int list_devices(icsneoc2_device_info_t* list) {
size_t index = 0;
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
char serial[64] = {0};
size_t serial_len = sizeof(serial);
(void)icsneoc2_device_info_serial_get(cur, serial, &serial_len);
char description[256] = {0};
size_t description_len = sizeof(description);
(void)icsneoc2_device_info_description_get(cur, description, &description_len);
printf("[%zu] %s (%s)\n", index++, description, serial);
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_create(cur, &device);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to create device", res);
continue;
}
icsneoc2_open_options_t options = icsneoc2_open_options_default;
options &= ~ICSNEOC2_OPEN_OPTIONS_SYNC_RTC;
options &= ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
res = icsneoc2_device_open(device, options);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to open device", res);
icsneoc2_device_free(device);
continue;
}
bool supports_tc10 = false;
(void)icsneoc2_device_supports_tc10(device, &supports_tc10);
printf(" TC10 supported: %s\n", supports_tc10 ? "yes" : "no");
size_t count = 0;
res = icsneoc2_device_supported_tx_networks_get(device, NULL, &count);
if(res != icsneoc2_error_success || count == 0) {
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
icsneoc2_netid_t* nets = (icsneoc2_netid_t*)calloc(count, sizeof(icsneoc2_netid_t));
if(nets == NULL) {
fprintf(stderr, " error: out of memory\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
res = icsneoc2_device_supported_tx_networks_get(device, nets, &count);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to get supported networks", res);
free(nets);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
printf(" Automotive Ethernet networks:\n");
bool any = false;
for(size_t i = 0; i < count; ++i) {
icsneoc2_network_type_t type = icsneoc2_network_type_invalid;
if(icsneoc2_netid_network_type_get(nets[i], &type) != icsneoc2_error_success) {
continue;
}
if(type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
char name[64] = {0};
size_t name_len = sizeof(name);
if(icsneoc2_netid_name_get(nets[i], name, &name_len) != icsneoc2_error_success) {
continue;
}
printf(" %s\n", name);
any = true;
}
if(!any) {
printf(" (none)\n");
}
free(nets);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
}
return 0;
}
+3
View File
@@ -406,6 +406,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) { if(it == devices.end()) {
std::cerr << "Could not find RAD-A2B." << std::endl; std::cerr << "Could not find RAD-A2B." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -92,6 +92,9 @@ int main(int argc, const char** argv) {
if(!device) { if(!device) {
std::cerr << "Device with serial " << serial << " not found" << std::endl; std::cerr << "Device with serial " << serial << " not found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1; return -1;
} }
} else { } else {
@@ -99,6 +102,9 @@ int main(int argc, const char** argv) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) { if(devices.empty()) {
std::cerr << "No devices found" << std::endl; std::cerr << "No devices found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1; return -1;
} }
device = devices[0]; device = devices[0];
@@ -9,7 +9,7 @@
/* /*
* App errors are responses from the device indicating internal runtime errors * App errors are responses from the device indicating internal runtime errors
* NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device * NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device
* (e.g. with neoVI Explorer) * (e.g. with ICS Device Manager)
*/ */
int main() { int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl; std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
@@ -17,6 +17,13 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+3
View File
@@ -33,6 +33,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) { if(it == devices.end()) {
std::cout << "Failed to find device." << std::endl; std::cout << "Failed to find device." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -12,7 +12,9 @@ int main() {
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) { if(devices.empty()) {
std::cout << "error: no devices found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
@@ -138,6 +138,12 @@ std::vector<std::shared_ptr<icsneo::FlexRayMessage>> makeDummyFlexRayMessages(si
int main() { int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1;
}
std::shared_ptr<icsneo::Device> flexrayDevice = nullptr; std::shared_ptr<icsneo::Device> flexrayDevice = nullptr;
for (auto&& device : devices) { for (auto&& device : devices) {
if (device->getExtension("FlexRay")) { if (device->getExtension("FlexRay")) {
@@ -223,8 +223,30 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n"; std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member // The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n"; auto printMAC = [](const icsneo::MACAddress& mac) {
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC(); std::ostringstream oss;
for(size_t i = 0; i < mac.size(); i++) {
oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mac[i];
if(i != mac.size() - 1)
oss << ':';
}
return oss.str();
};
if (auto destMAC = ethMessage->getDestinationMAC(); destMAC.has_value()) {
std::cout << "\t\t Destination:\t" << printMAC(*destMAC) << "\n";
} else {
std::cout << "\t\t Destination:\t N/A\n";
}
if (auto srcMAC = ethMessage->getSourceMAC(); srcMAC.has_value()) {
std::cout << "\t\t Source:\t" << printMAC(*srcMAC) << "\n";
} else {
std::cout << "\t\t Source:\t N/A\n";
}
if (auto etherType = ethMessage->getEtherType(); etherType.has_value()) {
std::cout << "\t\t EtherType:\t" << std::hex << std::setw(4) << std::setfill('0') << *etherType << "\n";
} else {
std::cout << "\t\t EtherType:\t N/A\n";
}
// Print the data // Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) { for(size_t i = 0; i < ethMessage->data.size(); i++) {
+7
View File
@@ -15,6 +15,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -14,6 +14,13 @@ int main() {
auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>> auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>>
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+4 -2
View File
@@ -9,8 +9,10 @@ int main(int, char**) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.size() == 0) { if(devices.empty()) {
std::cout << "No device found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
+7
View File
@@ -48,6 +48,13 @@ int main()
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for (auto &device : devices) for (auto &device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+7
View File
@@ -76,6 +76,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+28 -3
View File
@@ -22,6 +22,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -208,8 +215,26 @@ int main() {
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n"; std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member // The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n"; // The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC(); auto printMAC = [](const icsneo::MACAddress& mac) {
std::ostringstream oss;
for(size_t i = 0; i < mac.size(); i++) {
oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mac[i];
if(i != mac.size() - 1)
oss << ':';
}
return oss.str();
};
if (auto destMAC = ethMessage->getDestinationMAC(); destMAC.has_value()) {
std::cout << "\t\t Destination:\t" << printMAC(*destMAC) << "\n";
} else {
std::cout << "\t\t Destination:\t N/A\n";
}
if (auto srcMAC = ethMessage->getSourceMAC(); srcMAC.has_value()) {
std::cout << "\t\t Source:\t" << printMAC(*srcMAC) << "\n";
} else {
std::cout << "\t\t Source:\t N/A\n";
}
// Print the data // Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) { for(size_t i = 0; i < ethMessage->data.size(); i++) {
@@ -321,7 +346,7 @@ int main() {
if(val.has_value()) if(val.has_value())
std::cout << " - OK (" << val.value() << "V)" << std::endl; std::cout << " - OK (" << val.value() << "V)" << std::endl;
else else
std::cout << " - FAIL, it may need to be enabled in neoVI Explorer (" << icsneo::GetLastError() << ")" << std::endl; std::cout << " - FAIL, it may need to be enabled in ICS Device Manager (" << icsneo::GetLastError() << ")" << std::endl;
} }
} }
+3
View File
@@ -86,6 +86,9 @@ int main(int argc, const char** argv) {
} }
if(!device) { if(!device) {
std::cerr << "Failed to find device" << std::endl; std::cerr << "Failed to find device" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
std::cerr << usage; std::cerr << usage;
return -1; return -1;
} }
+4 -2
View File
@@ -216,8 +216,10 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if (devices.empty()) { if(devices.empty()) {
std::cout << "No devices found!" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 1; return 1;
} }
@@ -154,12 +154,12 @@ void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
auto ethMsg = std::static_pointer_cast<icsneo::EthernetMessage>(frame); auto ethMsg = std::static_pointer_cast<icsneo::EthernetMessage>(frame);
if (!ethMsg->isT1S) if (!ethMsg->t1s)
return; return;
double timestamp_ms = ethMsg->timestamp / 1000000.0; double timestamp_ms = ethMsg->timestamp / 1000000.0;
if (ethMsg->isT1SSymbol) { if (ethMsg->t1s->isSymbol) {
size_t numSymbols = ethMsg->data.size(); size_t numSymbols = ethMsg->data.size();
std::cout << std::fixed << std::setprecision(3) std::cout << std::fixed << std::setprecision(3)
@@ -169,7 +169,7 @@ void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
if (numSymbols > 0) { if (numSymbols > 0) {
std::cout << " (" << numSymbols << " symbol" << (numSymbols > 1 ? "s" : "") << ")"; std::cout << " (" << numSymbols << " symbol" << (numSymbols > 1 ? "s" : "") << ")";
} }
std::cout << " | Node ID: " << (int)ethMsg->t1sNodeId << std::endl; std::cout << " | Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
for (size_t i = 0; i < numSymbols; i++) { for (size_t i = 0; i < numSymbols; i++) {
uint8_t symbolValue = ethMsg->data[i]; uint8_t symbolValue = ethMsg->data[i];
@@ -188,8 +188,8 @@ void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
<< std::dec << std::endl; << std::dec << std::endl;
} }
if (numSymbols == 0 && ethMsg->t1sSymbolType != 0) { if (numSymbols == 0 && ethMsg->t1s->symbolType != 0) {
uint8_t symbolValue = ethMsg->t1sSymbolType; uint8_t symbolValue = ethMsg->t1s->symbolType;
std::string symbolName = getSymbolName(symbolValue); std::string symbolName = getSymbolName(symbolValue);
stats.symbolCount++; stats.symbolCount++;
@@ -205,20 +205,20 @@ void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
<< std::dec << " (from t1sSymbolType field)" << std::endl; << std::dec << " (from t1sSymbolType field)" << std::endl;
} }
} }
else if (ethMsg->isT1SBurst) { else if (ethMsg->t1s->isBurst) {
stats.burstCount++; stats.burstCount++;
std::cout << std::fixed << std::setprecision(3) std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] " << "[" << std::setw(12) << timestamp_ms << " ms] "
<< "BURST | " << "BURST | "
<< "Node ID: " << (int)ethMsg->t1sNodeId << " | " << "Node ID: " << (int)ethMsg->t1s->nodeId << " | "
<< "Burst Count: " << (int)ethMsg->t1sBurstCount << std::endl; << "Burst Count: " << (int)ethMsg->t1s->burstCount << std::endl;
} }
else if (ethMsg->isT1SWake) { else if (ethMsg->t1s->isWake) {
stats.wakeCount++; stats.wakeCount++;
std::cout << std::fixed << std::setprecision(3) std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] " << "[" << std::setw(12) << timestamp_ms << " ms] "
<< "WAKE signal detected | " << "WAKE signal detected | "
<< "Node ID: " << (int)ethMsg->t1sNodeId << std::endl; << "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
} }
else { else {
stats.dataFrameCount++; stats.dataFrameCount++;
@@ -226,7 +226,7 @@ void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
<< "[" << std::setw(12) << timestamp_ms << " ms] " << "[" << std::setw(12) << timestamp_ms << " ms] "
<< "T1S Data Frame | " << "T1S Data Frame | "
<< "Length: " << ethMsg->data.size() << " bytes | " << "Length: " << ethMsg->data.size() << " bytes | "
<< "Node ID: " << (int)ethMsg->t1sNodeId << std::endl; << "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
if (!ethMsg->data.empty()) { if (!ethMsg->data.empty()) {
std::cout << " Data: "; std::cout << " Data: ";
@@ -260,8 +260,10 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if (devices.empty()) { if(devices.empty()) {
std::cerr << "No devices found!" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return 1; return 1;
} }
+3 -1
View File
@@ -106,7 +106,9 @@ int main(int argc, char* argv[]) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) { if(devices.empty()) {
std::cout << "error: no devices found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
@@ -47,14 +47,23 @@ def setup_ethernet_reception(device):
def frame_handler(frame): def frame_handler(frame):
nonlocal frame_count nonlocal frame_count
frame_count += 1 frame_count += 1
dst = frame.get_destination_mac()
src = frame.get_source_mac()
et = frame.get_ether_type()
dst_str = ":".join(f"{b:02x}" for b in dst) if dst is not None else "N/A"
src_str = ":".join(f"{b:02x}" for b in src) if src is not None else "N/A"
et_str = f"0x{et:04x}" if et is not None else "N/A"
print(f"[RX {frame_count}], " print(f"[RX {frame_count}], "
f"Data: {[hex(b) for b in frame.data]}, " f"dst={dst_str}, src={src_str}, ethertype={et_str}, "
f"Length: {len(frame.data)}") f"Data: {[hex(b) for b in frame.data]}, "
frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.ETHERNET_01) f"Length: {len(frame.data)}")
frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.ETHERNET_02)
callback = icsneopy.MessageCallback(frame_handler, frame_filter) callback = icsneopy.MessageCallback(frame_handler, frame_filter)
device.add_message_callback(callback) device.add_message_callback(callback)
print("CAN frame reception configured") print("Ethernet frame reception configured")
return 0 return 0
+22 -32
View File
@@ -97,27 +97,27 @@ def display_t1s_settings(device, network):
"""Display T1S settings for a network.""" """Display T1S settings for a network."""
print(f"\t{network} T1S Settings:") print(f"\t{network} T1S Settings:")
settings = device.get_settings() settings = device.settings
if not settings: if not settings:
print("\t Unable to read settings") print("\t Unable to read settings")
return return
print(f"\t PLCA Enabled: {opt_to_string(settings.get_t1s_plca_enabled(network))}") print(f"\t PLCA Enabled: {opt_to_string(settings.is_t1s_plca_enabled(network))}")
print(f"\t Local ID: {opt_to_string(settings.get_t1s_local_id(network))}") print(f"\t Local ID: {opt_to_string(settings.get_t1s_local_id(network))}")
print(f"\t Max Nodes: {opt_to_string(settings.get_t1s_max_nodes(network))}") print(f"\t Max Nodes: {opt_to_string(settings.get_t1s_max_nodes(network))}")
print(f"\t TX Opp Timer: {opt_to_string(settings.get_t1s_tx_opp_timer(network))}") print(f"\t TX Opp Timer: {opt_to_string(settings.get_t1s_tx_opp_timer(network))}")
print(f"\t Max Burst: {opt_to_string(settings.get_t1s_max_burst(network))}") print(f"\t Max Burst: {opt_to_string(settings.get_t1s_max_burst(network))}")
print(f"\t Burst Timer: {opt_to_string(settings.get_t1s_burst_timer(network))}") print(f"\t Burst Timer: {opt_to_string(settings.get_t1s_burst_timer(network))}")
term_enabled = settings.get_t1s_termination_enabled(network) term_enabled = settings.is_t1s_termination_enabled(network)
if term_enabled is not None: if term_enabled is not None:
print(f"\t Termination: {opt_to_string(term_enabled)}") print(f"\t Termination: {opt_to_string(term_enabled)}")
local_id_alt = settings.get_t1s_local_id_alternate(network) local_id_alt = settings.get_t1s_local_id_alternate(network)
if local_id_alt is not None: if local_id_alt is not None:
print(f"\t Local ID Alternate: {opt_to_string(local_id_alt)}") print(f"\t Local ID Alternate: {opt_to_string(local_id_alt)}")
print(f"\t Bus Dec Beacons: {opt_to_string(settings.get_t1s_bus_decoding_beacons_enabled(network))}") print(f"\t Bus Dec Beacons: {opt_to_string(settings.is_t1s_bus_decoding_beacons_enabled(network))}")
print(f"\t Bus Dec All: {opt_to_string(settings.get_t1s_bus_decoding_all_enabled(network))}") print(f"\t Bus Dec All: {opt_to_string(settings.is_t1s_bus_decoding_all_enabled(network))}")
multi_id_mask = settings.get_t1s_multi_id_enable_mask(network) multi_id_mask = settings.get_t1s_multi_id_enable_mask(network)
if multi_id_mask is not None: if multi_id_mask is not None:
@@ -138,7 +138,7 @@ def configure_t1s_network(device, network):
print(f"Configuring T1S Network: {network}") print(f"Configuring T1S Network: {network}")
print("=" * 70) print("=" * 70)
settings = device.get_settings() settings = device.settings
if not settings: if not settings:
print("Unable to read settings") print("Unable to read settings")
return return
@@ -162,7 +162,7 @@ def configure_t1s_network(device, network):
burst_timer = get_uint16_input("Burst Timer (0-65535)", 64) burst_timer = get_uint16_input("Burst Timer (0-65535)", 64)
settings.set_t1s_burst_timer(network, burst_timer) settings.set_t1s_burst_timer(network, burst_timer)
if settings.get_t1s_termination_enabled(network) is not None: if settings.is_t1s_termination_enabled(network) is not None:
print("\n--- Termination Settings ---") print("\n--- Termination Settings ---")
term_enabled = get_user_confirmation("Enable Termination") term_enabled = get_user_confirmation("Enable Termination")
settings.set_t1s_termination(network, term_enabled) settings.set_t1s_termination(network, term_enabled)
@@ -187,10 +187,7 @@ def configure_t1s_network(device, network):
multi_id = get_uint8_input(f" Multi-ID [{i}]", 0) multi_id = get_uint8_input(f" Multi-ID [{i}]", 0)
settings.set_t1s_multi_id(network, i, multi_id) settings.set_t1s_multi_id(network, i, multi_id)
if not device.set_settings(settings): print(f"\n[OK] Configuration staged for {network}")
print("✗ Failed to update device settings")
else:
print(f"\n✓ Configuration complete for {network}")
def main(): def main():
@@ -217,7 +214,7 @@ def main():
device = None device = None
for d in devices: for d in devices:
if d.get_type() == icsneopy.DeviceType.RADComet3: if d.get_type().get_device_type() == icsneopy.DeviceType.Enum.RADComet3:
device = d device = d
break break
@@ -233,24 +230,17 @@ def main():
print("\nOpening device... ", end="", flush=True) print("\nOpening device... ", end="", flush=True)
if not device.open(): if not device.open():
print("✗ Failed") print("FAIL")
return 1 return 1
print("") print("OK")
candidate_networks = [ settings = device.settings
icsneopy.Network.NetID.AE_01, icsneopy.Network.NetID.AE_02,
icsneopy.Network.NetID.AE_03, icsneopy.Network.NetID.AE_04,
icsneopy.Network.NetID.AE_05, icsneopy.Network.NetID.AE_06,
icsneopy.Network.NetID.AE_07, icsneopy.Network.NetID.AE_08,
icsneopy.Network.NetID.AE_09, icsneopy.Network.NetID.AE_10
]
settings = device.get_settings()
t1s_networks = [] t1s_networks = []
for net_id in candidate_networks: for net in device.get_supported_tx_networks():
local_id = settings.get_t1s_local_id(net_id) if net.get_type() != icsneopy.Network.Type.AutomotiveEthernet:
if local_id is not None: continue
t1s_networks.append(net_id) if settings.get_t1s_local_id(net) is not None:
t1s_networks.append(net)
if not t1s_networks: if not t1s_networks:
print("No T1S networks found on this device") print("No T1S networks found on this device")
@@ -273,7 +263,7 @@ def main():
print("\nNo networks selected for configuration.") print("\nNo networks selected for configuration.")
print("Closing device... ", end="", flush=True) print("Closing device... ", end="", flush=True)
device.close() device.close()
print("") print("OK")
return 0 return 0
print(f"\nConfiguring {len(networks_to_config)} network{'s' if len(networks_to_config) != 1 else ''}...") print(f"\nConfiguring {len(networks_to_config)} network{'s' if len(networks_to_config) != 1 else ''}...")
@@ -285,14 +275,14 @@ def main():
save_to_eeprom = get_user_confirmation("Save settings to EEPROM (permanent)?") save_to_eeprom = get_user_confirmation("Save settings to EEPROM (permanent)?")
print("=" * 70) print("=" * 70)
settings = device.get_settings() settings = device.settings
print(f"\nApplying settings{' to EEPROM' if save_to_eeprom else ' temporarily'}... ", end="", flush=True) print(f"\nApplying settings{' to EEPROM' if save_to_eeprom else ' temporarily'}... ", end="", flush=True)
success = settings.apply(not save_to_eeprom) success = settings.apply(not save_to_eeprom)
if not success: if not success:
print("✗ Failed") print("FAIL")
device.close() device.close()
return 1 return 1
print("") print("OK")
print("\n" + "-" * 70) print("\n" + "-" * 70)
print("Updated T1S Settings:") print("Updated T1S Settings:")
@@ -302,7 +292,7 @@ def main():
print("Closing device... ", end="", flush=True) print("Closing device... ", end="", flush=True)
device.close() device.close()
print("") print("OK")
except KeyboardInterrupt: except KeyboardInterrupt:
print("\n\nInterrupted by user") print("\n\nInterrupted by user")
+43 -34
View File
@@ -38,7 +38,7 @@ def get_user_confirmation(prompt):
def configure_t1s_decoding(device, network, enable_symbols, enable_beacons): def configure_t1s_decoding(device, network, enable_symbols, enable_beacons):
"""Configure T1S bus decoding settings.""" """Configure T1S bus decoding settings."""
settings = device.get_settings() settings = device.settings
if not settings: if not settings:
raise RuntimeError("Failed to get device settings") raise RuntimeError("Failed to get device settings")
@@ -46,21 +46,15 @@ def configure_t1s_decoding(device, network, enable_symbols, enable_beacons):
if not settings.set_t1s_bus_decoding_all(network, enable_symbols): if not settings.set_t1s_bus_decoding_all(network, enable_symbols):
raise RuntimeError("Failed to set T1S symbol decoding") raise RuntimeError("Failed to set T1S symbol decoding")
if enable_symbols: print(f" [{'X' if enable_symbols else ' '}] Decoding of all T1S symbols")
print(" ✓ Enabled decoding of all T1S symbols")
else:
print(" • T1S symbol decoding disabled")
if not settings.set_t1s_bus_decoding_beacons(network, enable_beacons): if not settings.set_t1s_bus_decoding_beacons(network, enable_beacons):
raise RuntimeError("Failed to set T1S beacon decoding") raise RuntimeError("Failed to set T1S beacon decoding")
if enable_beacons: print(f" [{'X' if enable_beacons else ' '}] T1S beacon decoding")
print(" ✓ Enabled T1S beacon decoding")
else:
print(" • T1S beacon decoding disabled")
if not device.set_settings(settings): if not settings.apply(True):
raise RuntimeError("Failed to apply settings to device") raise RuntimeError("Failed to apply settings to device")
print(" Settings applied successfully") print(" [OK] Settings applied successfully")
def setup_symbol_monitoring(device, network): def setup_symbol_monitoring(device, network):
@@ -79,18 +73,18 @@ def setup_symbol_monitoring(device, network):
if not isinstance(msg, icsneopy.EthernetMessage): if not isinstance(msg, icsneopy.EthernetMessage):
return return
if not msg.isT1S: if not msg.t1s:
return return
timestamp_ms = msg.timestamp / 1000000.0 timestamp_ms = msg.timestamp / 1000000.0
if msg.isT1SSymbol: if msg.t1s.isSymbol:
num_symbols = len(msg.data) num_symbols = len(msg.data)
print(f"[{timestamp_ms:12.3f} ms] T1S Symbols", end="") print(f"[{timestamp_ms:12.3f} ms] T1S Symbols", end="")
if num_symbols > 0: if num_symbols > 0:
print(f" ({num_symbols} symbol{'s' if num_symbols > 1 else ''})", end="") print(f" ({num_symbols} symbol{'s' if num_symbols > 1 else ''})", end="")
print(f" | Node ID: {msg.t1sNodeId}") print(f" | Node ID: {msg.t1s.nodeId}")
for i, symbol_value in enumerate(msg.data): for i, symbol_value in enumerate(msg.data):
symbol_name = T1SSymbol.get_name(symbol_value) symbol_name = T1SSymbol.get_name(symbol_value)
@@ -105,8 +99,8 @@ def setup_symbol_monitoring(device, network):
print(f" [{i}] {symbol_name:10s} = 0x{symbol_value:02X}") print(f" [{i}] {symbol_name:10s} = 0x{symbol_value:02X}")
if num_symbols == 0 and msg.t1sSymbolType != 0: if num_symbols == 0 and msg.t1s.symbolType != 0:
symbol_value = msg.t1sSymbolType symbol_value = msg.t1s.symbolType
symbol_name = T1SSymbol.get_name(symbol_value) symbol_name = T1SSymbol.get_name(symbol_value)
state['symbol_count'] += 1 state['symbol_count'] += 1
@@ -119,22 +113,22 @@ def setup_symbol_monitoring(device, network):
print(f" {symbol_name:10s} = 0x{symbol_value:02X} (from t1sSymbolType field)") print(f" {symbol_name:10s} = 0x{symbol_value:02X} (from t1sSymbolType field)")
elif msg.isT1SBurst: elif msg.t1s.isBurst:
state['burst_count'] += 1 state['burst_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] BURST | " print(f"[{timestamp_ms:12.3f} ms] BURST | "
f"Node ID: {msg.t1sNodeId} | " f"Node ID: {msg.t1s.nodeId} | "
f"Burst Count: {msg.t1sBurstCount}") f"Burst Count: {msg.t1s.burstCount}")
elif msg.isT1SWake: elif msg.t1s.isWake:
state['wake_count'] += 1 state['wake_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] WAKE signal detected | " print(f"[{timestamp_ms:12.3f} ms] WAKE signal detected | "
f"Node ID: {msg.t1sNodeId}") f"Node ID: {msg.t1s.nodeId}")
else: else:
state['data_frame_count'] += 1 state['data_frame_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] T1S Data Frame | " print(f"[{timestamp_ms:12.3f} ms] T1S Data Frame | "
f"Length: {len(msg.data)} bytes | " f"Length: {len(msg.data)} bytes | "
f"Node ID: {msg.t1sNodeId}") f"Node ID: {msg.t1s.nodeId}")
if msg.data and len(msg.data) > 0: if msg.data and len(msg.data) > 0:
preview = ' '.join([f"{b:02X}" for b in msg.data[:16]]) preview = ' '.join([f"{b:02X}" for b in msg.data[:16]])
@@ -142,7 +136,7 @@ def setup_symbol_monitoring(device, network):
preview += " ..." preview += " ..."
print(f" Data: {preview}") print(f" Data: {preview}")
frame_filter = icsneopy.MessageFilter(network) frame_filter = icsneopy.MessageFilter(network.get_net_id())
callback = icsneopy.MessageCallback(symbol_handler, frame_filter) callback = icsneopy.MessageCallback(symbol_handler, frame_filter)
device.add_message_callback(callback) device.add_message_callback(callback)
@@ -175,7 +169,6 @@ def main():
device = None device = None
try: try:
MONITOR_NETWORK = icsneopy.Network.NetID.AE_02
MONITOR_DURATION = 30 MONITOR_DURATION = 30
print("\n" + "=" * 70) print("\n" + "=" * 70)
@@ -197,7 +190,7 @@ def main():
device = None device = None
for d in devices: for d in devices:
if d.get_type() == icsneopy.DeviceType.RADComet3: if d.get_type().get_device_type() == icsneopy.DeviceType.Enum.RADComet3:
device = d device = d
break break
@@ -220,28 +213,44 @@ def main():
print("\nOpening device... ", end="", flush=True) print("\nOpening device... ", end="", flush=True)
if not device.open(): if not device.open():
print("✗ Failed") print("FAIL")
return 1 return 1
print("") print("OK")
print("Enabling message polling... ", end="", flush=True) print("Enabling message polling... ", end="", flush=True)
if not device.enable_message_polling(): if not device.enable_message_polling():
print("✗ Failed") print("FAIL")
device.close() device.close()
return 1 return 1
device.set_polling_message_limit(100000) device.set_polling_message_limit(100000)
print("") print("OK")
configure_t1s_decoding(device, MONITOR_NETWORK, enable_symbols, enable_beacons) monitor_network = None
settings = device.settings
for net in device.get_supported_rx_networks():
if net.get_type() != icsneopy.Network.Type.AutomotiveEthernet:
continue
if settings.get_t1s_local_id(net) is not None:
monitor_network = net
break
if monitor_network is None:
print("No T1S network found on this device")
device.close()
return 1
print(f"Monitoring network: {monitor_network}")
configure_t1s_decoding(device, monitor_network, enable_symbols, enable_beacons)
print("Going online... ", end="", flush=True) print("Going online... ", end="", flush=True)
if not device.go_online(): if not device.go_online():
print("✗ Failed") print("FAIL")
device.close() device.close()
return 1 return 1
print("") print("OK")
state = setup_symbol_monitoring(device, MONITOR_NETWORK) state = setup_symbol_monitoring(device, monitor_network)
print("\n" + "-" * 70) print("\n" + "-" * 70)
print(f"Monitoring T1S traffic for {MONITOR_DURATION} seconds...") print(f"Monitoring T1S traffic for {MONITOR_DURATION} seconds...")
@@ -256,7 +265,7 @@ def main():
print("Closing device... ", end="", flush=True) print("Closing device... ", end="", flush=True)
device.close() device.close()
time.sleep(0.1) time.sleep(0.1)
print("") print("OK")
print_statistics(state) print_statistics(state)
+1
View File
@@ -165,6 +165,7 @@ public:
ServdPollError = ServdBindError + 8, ServdPollError = ServdBindError + 8,
ServdNoDataError = ServdBindError + 9, ServdNoDataError = ServdBindError + 9,
ServdJoinMulticastError = ServdBindError + 10, ServdJoinMulticastError = ServdBindError + 10,
ServdNotReachable = ServdBindError + 11,
// DXX // DXX
DXXErrorSys = 0x6100, DXXErrorSys = 0x6100,
+1
View File
@@ -55,6 +55,7 @@ enum class ExtendedCommand : uint16_t {
GetSupportedFeatures = 0x0018, GetSupportedFeatures = 0x0018,
GetGPTPStatus = 0x0019, GetGPTPStatus = 0x0019,
GetComponentVersions = 0x001A, GetComponentVersions = 0x001A,
SoftwareUpdate = 0x001B,
Reboot = 0x001C, Reboot = 0x001C,
SetRootFSEntryFlags = 0x0027, SetRootFSEntryFlags = 0x0027,
TransmitCoreminiMessage = 0x0028, TransmitCoreminiMessage = 0x0028,
@@ -4,24 +4,24 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include "icsneo/icsneoc2types.h"
namespace icsneo { namespace icsneo {
enum class CANErrorCode : uint8_t enum class CANErrorCode : icsneoc2_can_error_code_t
{ {
NoError = 0, NoError = icsneoc2_can_error_code_no_error,
StuffError = 1, StuffError = icsneoc2_can_error_code_stuff_error,
FormError = 2, FormError = icsneoc2_can_error_code_form_error,
AckError = 3, AckError = icsneoc2_can_error_code_ack_error,
Bit1Error = 4, Bit1Error = icsneoc2_can_error_code_bit1_error,
Bit0Error = 5, Bit0Error = icsneoc2_can_error_code_bit0_error,
CRCError = 6, CRCError = icsneoc2_can_error_code_crc_error,
NoChange = 7 NoChange = icsneoc2_can_error_code_no_change
}; };
class CANErrorMessage : public Message { class CANErrorMessage : public RawMessage {
public: public:
CANErrorMessage() : Message(Type::CANError) {} CANErrorMessage() : RawMessage(Type::CANError) {}
Network network;
uint8_t transmitErrorCount; uint8_t transmitErrorCount;
uint8_t receiveErrorCount; uint8_t receiveErrorCount;
bool busOff; bool busOff;
@@ -16,6 +16,9 @@ public:
bool isCANFD = false; bool isCANFD = false;
bool baudrateSwitch = false; // CAN FD only bool baudrateSwitch = false; // CAN FD only
bool errorStateIndicator = false; // CAN FD only bool errorStateIndicator = false; // CAN FD only
bool txAborted = false;
bool txLostArb = false;
bool txError = false;
}; };
} }
@@ -4,63 +4,89 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <cstring> #include <cstring>
#include <optional>
namespace icsneo { namespace icsneo {
struct MACAddress { using MACAddress = std::array<uint8_t, 6>;
uint8_t data[6];
std::string toString() const {
std::stringstream ss;
for(size_t i = 0; i < 6; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
if(i != 5)
ss << ':';
}
return ss.str();
}
friend std::ostream& operator<<(std::ostream& os, const MACAddress& mac) {
os << mac.toString();
return os;
}
};
class EthernetMessage : public Frame { class EthernetMessage : public Frame {
public: public:
// Standard Ethernet fields // Standard Ethernet fields
bool preemptionEnabled = false; // Frame Check Sequence
uint8_t preemptionFlags = 0;
std::optional<uint32_t> fcs; std::optional<uint32_t> fcs;
bool frameTooShort = false; bool frameTooShort = false;
bool noPadding = false; bool noPadding = false;
bool fcsVerified = false; bool fcsVerified = false;
bool txAborted = false; bool txAborted = false;
bool crcError = false; bool crcError = false;
bool isT1S = false;
bool isT1SSymbol = false; // T1S-specific fields
bool isT1SBurst = false; struct T1S {
bool txCollision = false; T1S() {}
bool isT1SWake = false;
uint8_t t1sNodeId = 0;
uint8_t t1sBurstCount = 0;
uint8_t t1sSymbolType = 0;
// Accessors bool isSymbol = false;
const MACAddress& getDestinationMAC() const { return *(const MACAddress*)(data.data() + 0); } bool isBurst = false;
const MACAddress& getSourceMAC() const { return *(const MACAddress*)(data.data() + 6); } bool txCollision = false;
uint16_t getEtherType() const { return (data[12] << 8) | data[13]; } bool isWake = false;
uint8_t nodeId = 0;
uint8_t burstCount = 0;
uint8_t symbolType = 0;
};
std::optional<T1S> t1s;
// TSN-specific fields
// If we expand TSN we should probably do something similar to what we did above with T1S.
// IEEE 802.1Qbu frame preemption
std::optional<uint8_t> preemptionFlags;
// Helper functions to extract Destination MAC from the data payload
// returns std::nullopt if the data payload is not large enough
std::optional<MACAddress> getDestinationMAC() const {
if(data.size() < 6) {
return std::nullopt;
}
MACAddress mac;
std::copy(data.begin(), data.begin() + 6, mac.begin());
return mac;
}
// Helper functions to extract Source MAC from the data payload
// returns std::nullopt if the data payload is not large enough
std::optional<MACAddress> getSourceMAC() const {
if(data.size() < 12) {
return std::nullopt;
}
MACAddress mac;
std::copy(data.begin() + 6, data.begin() + 12, mac.begin());
return mac;
}
// Helper function to extract EtherType from the data payload
//
// EtherType is a two-octet field in an Ethernet frame (big-endian).
// It is used to indicate which protocol is encapsulated in the payload of the frame
// and is used at the receiving end by the data link layer to determine how the payload is processed.
// For example, an EtherType of 0x0800 indicates that the payload is an IPv4 packet, while 0x86DD indicates an IPv6 packet.
//
// returns std::nullopt if the data payload is not large enough
std::optional<uint16_t> getEtherType() const {
if(data.size() < 14) {
return std::nullopt;
}
// EtherType is stored in a 2-byte network byte order (big-endian)
return static_cast<uint16_t>((uint16_t(data[12]) << 8) | uint16_t(data[13]));
}
}; };
} }
#endif // __cplusplus #endif // __cplusplus
#endif #endif // __ETHERNETMESSAGE_H_
@@ -10,8 +10,8 @@ namespace icsneo {
class ExtendedResponseMessage : public Message { class ExtendedResponseMessage : public Message {
public: public:
ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp = ExtendedResponse::OK) ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp = ExtendedResponse::OK, const std::vector<uint8_t>& buf = {})
: Message(Message::Type::ExtendedResponse), command(cmd), response(resp) {} : Message(Message::Type::ExtendedResponse), command(cmd), response(resp), data(buf) {}
const ExtendedCommand command; const ExtendedCommand command;
const ExtendedResponse response; const ExtendedResponse response;
@@ -1,6 +1,8 @@
#ifndef __LINMESSAGE_H_ #ifndef __LINMESSAGE_H_
#define __LINMESSAGE_H_ #define __LINMESSAGE_H_
#include "icsneo/icsneoc2messages.h"
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
@@ -36,14 +38,14 @@ struct LINStatusFlags {
class LINMessage : public Frame { class LINMessage : public Frame {
public: public:
enum class Type : uint8_t { enum class Type : icsneoc2_lin_msg_type_t {
NOT_SET = 0, NOT_SET = icsneoc2_lin_msg_type_not_set,
LIN_COMMANDER_MSG, LIN_COMMANDER_MSG = icsneoc2_lin_msg_type_commander_msg,
LIN_HEADER_ONLY, LIN_HEADER_ONLY = icsneoc2_lin_msg_type_header_only,
LIN_BREAK_ONLY, LIN_BREAK_ONLY = icsneoc2_lin_msg_type_break_only,
LIN_SYNC_ONLY, LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only,
LIN_UPDATE_RESPONDER, LIN_UPDATE_RESPONDER = icsneoc2_lin_msg_type_update_responder,
LIN_ERROR LIN_ERROR = icsneoc2_lin_msg_type_error
}; };
static void calcChecksum(LINMessage& message); static void calcChecksum(LINMessage& message);
@@ -10,6 +10,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <optional>
namespace icsneo { namespace icsneo {
+9 -8
View File
@@ -4,19 +4,20 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <cstdint> #include <cstdint>
#include "icsneo/icsneoc2types.h"
namespace icsneo { namespace icsneo {
enum class TC10WakeStatus : uint8_t { enum class TC10WakeStatus : icsneoc2_tc10_wake_status_t {
NoWakeReceived, NoWakeReceived = icsneoc2_tc10_wake_status_no_wake_received,
WakeReceived, WakeReceived = icsneoc2_tc10_wake_status_wake_received,
}; };
enum class TC10SleepStatus : uint8_t { enum class TC10SleepStatus : icsneoc2_tc10_sleep_status_t {
NoSleepReceived, NoSleepReceived = icsneoc2_tc10_sleep_status_no_sleep_received,
SleepReceived, SleepReceived = icsneoc2_tc10_sleep_status_sleep_received,
SleepFailed, SleepFailed = icsneoc2_tc10_sleep_status_sleep_failed,
SleepAborted, SleepAborted = icsneoc2_tc10_sleep_status_sleep_aborted,
}; };
} }
+2
View File
@@ -136,7 +136,9 @@ struct MACsecRxSa {
std::array<uint8_t, 16> hashKey = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 128b Hash Key: Key used for authentication. */ std::array<uint8_t, 16> hashKey = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 128b Hash Key: Key used for authentication. */
std::array<uint8_t, 12> salt = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 96b Salt value: Salt value used in XPN ciphers. */ std::array<uint8_t, 12> salt = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; /*!< 96b Salt value: Salt value used in XPN ciphers. */
uint32_t ssci = 0x01u; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */ uint32_t ssci = 0x01u; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */
uint8_t an = 0x00u; /*!< 2b SecTag Association Number (AN). SA will be placed at this index (0-3). */
uint64_t nextPn = 0x01u; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */ uint64_t nextPn = 0x01u; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */
bool enabled = false; /*!< Set by addRxSa(); slots created by internal padding during sparse placement are left disabled. Do not set this directly. */
}; };
class MACsecConfig { class MACsecConfig {
+5 -1
View File
@@ -102,7 +102,7 @@ enum class ChipID : uint8_t {
neoOBD2Dev_MCHIP = 94, neoOBD2Dev_MCHIP = 94,
neoOBD2Dev_SCHIP = 95, neoOBD2Dev_SCHIP = 95,
neoOBD2SIMDoIP_MCHIP = 96, neoOBD2SIMDoIP_MCHIP = 96,
SFPModule_MCHIP = 97, SFPModule_88q2112_MCHIP = 97,
RADEpsilonT_MCHIP = 98, RADEpsilonT_MCHIP = 98,
RADEpsilonExpress_MCHIP = 99, RADEpsilonExpress_MCHIP = 99,
RADProxima_MCHIP = 100, RADProxima_MCHIP = 100,
@@ -125,12 +125,16 @@ enum class ChipID : uint8_t {
RADGigastar_FFG_ZYNQ = 117, RADGigastar_FFG_ZYNQ = 117,
VEM_02_FR_FCHIP = 118, VEM_02_FR_FCHIP = 118,
Connect_ZCHIP = 121, Connect_ZCHIP = 121,
SFPModule_88q2221_MCHIP = 122,
RADGALAXY2_SYSMON_CHIP = 123, RADGALAXY2_SYSMON_CHIP = 123,
SFPModule_88q3244_MCHIP = 124,
RADCOMET3_ZCHIP = 125, RADCOMET3_ZCHIP = 125,
Connect_LINUX = 126, Connect_LINUX = 126,
SFPModule_lan8670_MCHIP = 127,
VEM_04_T1S_LIN_ZCHIP = 129, VEM_04_T1S_LIN_ZCHIP = 129,
RADMOONT1S_ZCHIP = 130, RADMOONT1S_ZCHIP = 130,
RADGigastar2_ZYNQ = 131, RADGigastar2_ZYNQ = 131,
SFPModule_ent11100_MCHIP = 132,
RADGemini_MCHIP = 135, RADGemini_MCHIP = 135,
Invalid = 255 Invalid = 255
}; };
+7 -3
View File
@@ -130,14 +130,18 @@ public:
EtherBADGE = 38, EtherBADGE = 38,
RADEpsilon = 39, RADEpsilon = 39,
RADA2B = 40, RADA2B = 40,
SFPModule = 41, SFPModule_88q2112 = 41,
RADGalaxy2 = 47, RADGalaxy2 = 47,
RADMoon3 = 49, RADMoon3 = 49,
RADComet = 50, RADComet = 50,
Connect = 51, Connect = 51,
SFPModule_88q2221m = 52,
SFPModule_88q4364 = 53,
RADComet3 = 54, RADComet3 = 54,
SFPModule_lan8670 = 55,
RADMoonT1S = 56, RADMoonT1S = 56,
RADGigastar2 = 57, RADGigastar2 = 57,
SFPModule_ent11100 = 58,
RADGemini = 60, RADGemini = 60,
}; };
@@ -874,8 +878,6 @@ public:
bool unlockNetworks(const std::set<Network::NetID>& networks); bool unlockNetworks(const std::set<Network::NetID>& networks);
bool unlockAllNetworks(); bool unlockAllNetworks();
std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network); std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network);
virtual bool supportsNetworkMutex() const { return false; }
protected: protected:
bool online = false; bool online = false;
@@ -994,6 +996,8 @@ protected:
std::optional<HardwareInfo::Version> bootloaderVersion = std::nullopt; std::optional<HardwareInfo::Version> bootloaderVersion = std::nullopt;
bool supportsNetworkMutex = false;
private: private:
neodevice_t data; neodevice_t data;
std::shared_ptr<ResetStatusMessage> latestResetStatus; std::shared_ptr<ResetStatusMessage> latestResetStatus;
@@ -81,6 +81,7 @@ public:
} }
protected: protected:
NeoVIFIRE3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { NeoVIFIRE3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
supportsNetworkMutex = true;
initialize<NeoVIFIRE3Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<NeoVIFIRE3Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -123,8 +124,6 @@ protected:
size_t getDiskCount() const override { size_t getDiskCount() const override {
return 2; return 2;
} }
bool supportsNetworkMutex() const override { return true; }
}; };
} }
@@ -86,6 +86,7 @@ public:
} }
protected: protected:
NeoVIFIRE3FlexRay(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { NeoVIFIRE3FlexRay(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
supportsNetworkMutex = true;
initialize<NeoVIFIRE3FlexRaySettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<NeoVIFIRE3FlexRaySettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -150,8 +151,6 @@ protected:
size_t getDiskCount() const override { size_t getDiskCount() const override {
return 2; return 2;
} }
bool supportsNetworkMutex() const override { return true; }
}; };
} }
@@ -89,6 +89,7 @@ public:
} }
protected: protected:
NeoVIFIRE3T1SLIN(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { NeoVIFIRE3T1SLIN(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
supportsNetworkMutex = true;
initialize<NeoVIFIRE3T1SLINSettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<NeoVIFIRE3T1SLINSettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -132,10 +133,6 @@ protected:
return 2; return 2;
} }
bool supportsNetworkMutex() const override {
return true;
}
}; };
} }
@@ -64,6 +64,7 @@ public:
} }
protected: protected:
NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
supportsNetworkMutex = true;
initialize<NeoVIRED2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<NeoVIRED2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -104,8 +105,6 @@ protected:
size_t getDiskCount() const override { size_t getDiskCount() const override {
return 2; return 2;
} }
bool supportsNetworkMutex() const override { return true; }
}; };
} }
@@ -89,9 +89,7 @@ public:
.add<FlashPhase>(ChipID::RAD_GALAXY_2_ZMPCHIP_ID, BootloaderCommunication::RAD) .add<FlashPhase>(ChipID::RAD_GALAXY_2_ZMPCHIP_ID, BootloaderCommunication::RAD)
.add<EnterApplicationPhase>(ChipID::RAD_GALAXY_2_ZMPCHIP_ID) .add<EnterApplicationPhase>(ChipID::RAD_GALAXY_2_ZMPCHIP_ID)
.add<ReconnectPhase>() .add<ReconnectPhase>()
.add<FlashPhase>(ChipID::RADGALAXY2_SYSMON_CHIP, BootloaderCommunication::RADGalaxy2Peripheral) .add<FlashPhase>(ChipID::RADGALAXY2_SYSMON_CHIP, BootloaderCommunication::RADGalaxy2Peripheral);
.add<ReconnectPhase>()
.add<WaitPhase>(std::chrono::milliseconds(3000));
} }
protected: protected:
@@ -190,6 +190,75 @@ public:
return nullptr; return nullptr;
} }
} }
bool setPhyEnableFor(Network net, bool enable) override {
auto cfg = getMutableStructurePointer<radgalaxy2_settings_t>();
if(cfg == nullptr)
return false;
if(net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
auto coreMini = net.getCoreMini();
if(!coreMini.has_value()) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
const uint64_t networkID = static_cast<uint64_t>(coreMini.value());
uint64_t bitfields[2] = {
(uint64_t)cfg->network_enables | ((uint64_t)cfg->network_enables_2 << 16) |
((uint64_t)cfg->network_enables_3 << 32) | ((uint64_t)cfg->network_enables_4 << 48),
cfg->network_enables_5
};
const bool success = enable ?
SetNetworkEnabled(bitfields, 2, networkID) :
ClearNetworkEnabled(bitfields, 2, networkID);
if(!success) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
cfg->network_enables = static_cast<uint16_t>(bitfields[0]);
cfg->network_enables_2 = static_cast<uint16_t>(bitfields[0] >> 16);
cfg->network_enables_3 = static_cast<uint16_t>(bitfields[0] >> 32);
cfg->network_enables_4 = static_cast<uint16_t>(bitfields[0] >> 48);
cfg->network_enables_5 = bitfields[1];
return true;
}
std::optional<bool> getPhyEnableFor(Network net) const override {
auto cfg = getStructurePointer<radgalaxy2_settings_t>();
if(cfg == nullptr) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return std::nullopt;
}
auto coreMini = net.getCoreMini();
if(!coreMini.has_value()) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return std::nullopt;
}
const uint64_t networkID = static_cast<uint64_t>(coreMini.value());
const uint64_t bitfields[2] = {
(uint64_t)cfg->network_enables | ((uint64_t)cfg->network_enables_2 << 16) |
((uint64_t)cfg->network_enables_3 << 32) | ((uint64_t)cfg->network_enables_4 << 48),
cfg->network_enables_5
};
return GetNetworkEnabled(bitfields, 2, networkID);
}
}; };
} }
@@ -35,6 +35,11 @@ public:
{ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip},
{ChipID::SFPModule_88q2112_MCHIP, true, "SFP-MV2112", "sfp_mv2112_a2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q2221_MCHIP, true, "SFP-MV2221M", "sfp_mv2221m_b2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_lan8670_MCHIP, true, "SFP-MC8670", "sfp_module_lan8670_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q3244_MCHIP, true, "SFP-MV3244", "sfp_module_88q3244_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_ent11100_MCHIP, true, "SFP-EN11100", "sfp_module_ent11100_ief", 3, FirmwareType::IEF}
}; };
return chips; return chips;
} }
@@ -80,8 +85,9 @@ public:
} }
BootloaderPipeline pipeline; BootloaderPipeline pipeline;
for(const auto& version : chipVersions) { for(size_t i = 0; i < chipVersions.size(); i++) {
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip); const auto& version = chipVersions[i];
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0);
} }
pipeline.add<EnterApplicationPhase>(mainChipID); pipeline.add<EnterApplicationPhase>(mainChipID);
pipeline.add<WaitPhase>(std::chrono::milliseconds(3000)); pipeline.add<WaitPhase>(std::chrono::milliseconds(3000));
@@ -129,6 +129,11 @@ public:
{ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip},
{ChipID::SFPModule_88q2112_MCHIP, true, "SFP-MV2112", "sfp_mv2112_a2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q2221_MCHIP, true, "SFP-MV2221M", "sfp_mv2221m_b2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_lan8670_MCHIP, true, "SFP-MC8670", "sfp_module_lan8670_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q3244_MCHIP, true, "SFP-MV3244", "sfp_module_88q3244_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_ent11100_MCHIP, true, "SFP-EN11100", "sfp_module_ent11100_ief", 3, FirmwareType::IEF}
}; };
static std::vector<ChipInfo> t1sChips = { static std::vector<ChipInfo> t1sChips = {
@@ -136,6 +141,11 @@ public:
{ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_ZYNQ, true, "USB ZCHIP", "RADGigastar_USBz_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7010_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7010_SW_bin", 2, FirmwareType::Zip},
{ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip}, {ChipID::RADGigastar_USBZ_Z7007S_ZYNQ, false, "USB ZCHIP", "RADGigastar_USBz_Z7007s_SW_bin", 2, FirmwareType::Zip},
{ChipID::SFPModule_88q2112_MCHIP, true, "SFP-MV2112", "sfp_mv2112_a2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q2221_MCHIP, true, "SFP-MV2221M", "sfp_mv2221m_b2_mchip_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_lan8670_MCHIP, true, "SFP-MC8670", "sfp_module_lan8670_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_88q3244_MCHIP, true, "SFP-MV3244", "sfp_module_88q3244_ief", 3, FirmwareType::IEF},
{ChipID::SFPModule_ent11100_MCHIP, true, "SFP-EN11100", "sfp_module_ent11100_ief", 3, FirmwareType::IEF}
}; };
if(variantToFlash == FirmwareVariant::T1Sx8_CANx4_LINx6) { if(variantToFlash == FirmwareVariant::T1Sx8_CANx4_LINx6) {
@@ -159,8 +169,9 @@ public:
} }
BootloaderPipeline pipeline; BootloaderPipeline pipeline;
for(const auto& version : chipVersions) { for(size_t i = 0; i < chipVersions.size(); i++) {
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip); const auto& version = chipVersions[i];
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0);
} }
pipeline.add<EnterApplicationPhase>(mainChipID); pipeline.add<EnterApplicationPhase>(mainChipID);
pipeline.add<WaitPhase>(std::chrono::milliseconds(3000)); pipeline.add<WaitPhase>(std::chrono::milliseconds(3000));
@@ -465,6 +465,64 @@ namespace icsneo
return std::make_optional(t1sExt->multi_id[index]); return std::make_optional(t1sExt->multi_id[index]);
} }
bool setPhyEnableFor(Network net, bool enable) override {
auto cfg = getMutableStructurePointer<radgigastar2_settings_t>();
if(cfg == nullptr)
return false;
if(net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
auto coreMini = net.getCoreMini();
if(!coreMini.has_value()) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
const uint64_t networkID = static_cast<uint64_t>(coreMini.value());
uint64_t bitfields[2] = { cfg->network_enables, cfg->network_enables_2 };
const bool success = enable ?
SetNetworkEnabled(bitfields, 2, networkID) :
ClearNetworkEnabled(bitfields, 2, networkID);
if(!success) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
cfg->network_enables = bitfields[0];
cfg->network_enables_2 = bitfields[1];
return true;
}
std::optional<bool> getPhyEnableFor(Network net) const override {
auto cfg = getStructurePointer<radgigastar2_settings_t>();
if(cfg == nullptr) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(net.getType() != Network::Type::Ethernet && net.getType() != Network::Type::AutomotiveEthernet) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return std::nullopt;
}
auto coreMini = net.getCoreMini();
if(!coreMini.has_value()) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return std::nullopt;
}
const uint64_t networkID = static_cast<uint64_t>(coreMini.value());
const uint64_t bitfields[2] = { cfg->network_enables, cfg->network_enables_2 };
return GetNetworkEnabled(bitfields, 2, networkID);
}
bool setT1SMultiIDFor(Network net, uint8_t index, uint8_t id) override { bool setT1SMultiIDFor(Network net, uint8_t index, uint8_t id) override {
ETHERNET10T1S_SETTINGS_EXT* t1sExt = getMutableT1SSettingsExtFor(net); ETHERNET10T1S_SETTINGS_EXT* t1sExt = getMutableT1SSettingsExtFor(net);
if(t1sExt == nullptr) if(t1sExt == nullptr)
+96 -15
View File
@@ -42,6 +42,9 @@ typedef enum _icsneoc2_error_t {
icsneoc2_error_script_clear_failed, // Failed to clear script icsneoc2_error_script_clear_failed, // Failed to clear script
icsneoc2_error_script_upload_failed, // Failed to upload coremini script icsneoc2_error_script_upload_failed, // Failed to upload coremini script
icsneoc2_error_script_load_prepare_failed, // Failed to prepare script load icsneoc2_error_script_load_prepare_failed, // Failed to prepare script load
icsneoc2_error_close_failed, // Failed to close device
icsneoc2_error_reconnect_failed, // Failed to reconnect to device
icsneoc2_error_invalid_data, // Failed to get/set data due to invalid data pointer or size
// NOTE: Any new values added here should be updated in icsneoc2_error_code_get // NOTE: Any new values added here should be updated in icsneoc2_error_code_get
icsneoc2_error_maxsize icsneoc2_error_maxsize
} _icsneoc2_error_t; } _icsneoc2_error_t;
@@ -166,29 +169,31 @@ icsneoc2_error_t icsneoc2_device_is_valid(const icsneoc2_device_t* device);
icsneoc2_error_t icsneoc2_device_is_open(const icsneoc2_device_t* device, bool* is_open); icsneoc2_error_t icsneoc2_device_is_open(const icsneoc2_device_t* device, bool* is_open);
/** /**
* Check if a device is disconnected. * Create a device handle from an enumeration node without opening it. Need to call icsneoc2_device_free() to free the handle when finished.
* * The device can then be opened with icsneoc2_device_open().
* @param[in] device The device to check. *
* @param[out] is_disconnected true if the device is disconnected, false otherwise * @param[in] device_info The device info node to create from.
* * @param[out] device Pointer to receive the created device handle.
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise. *
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_device otherwise.
*
* @see icsneoc2_device_open icsneoc2_device_free
*/ */
icsneoc2_error_t icsneoc2_device_is_disconnected(const icsneoc2_device_t* device, bool* is_disconnected); icsneoc2_error_t icsneoc2_device_create(const icsneoc2_device_info_t* device_info, icsneoc2_device_t** device);
/** /**
* Open a device from an enumeration node. * Open a device from an enumeration node.
* *
* After a successful call, icsneoc2_device_close() must be called to close the device. * After a successful call, icsneoc2_device_close() must be called to close the device.
* *
* @param[in] device_info The device info node to open. * @param[in] device Pointer to the device to open.
* @param[in] options Open options (e.g. icsneoc2_open_options_default). * @param[in] options Open options (e.g. icsneoc2_open_options_default).
* @param[out] device Pointer to receive the opened device handle.
* *
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_open_failed otherwise. * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_open_failed otherwise.
* *
* @see icsneoc2_device_close * @see icsneoc2_device_close icsneoc2_device_free
*/ */
icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_info_t* device_info, icsneoc2_open_options_t options, icsneoc2_device_t** device); icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_t* device, icsneoc2_open_options_t options);
/** /**
* Convenience: enumerate, find by serial, open, and free enumeration. * Convenience: enumerate, find by serial, open, and free enumeration.
@@ -199,13 +204,14 @@ icsneoc2_error_t icsneoc2_device_open(const icsneoc2_device_info_t* device_info,
* *
* @return icsneoc2_error_t icsneoc2_error_success if successful. * @return icsneoc2_error_t icsneoc2_error_success if successful.
* *
* @see icsneoc2_device_close * @see icsneoc2_device_close icsneoc2_device_free
*/ */
icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_options_t options, icsneoc2_device_t** device); icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_options_t options, icsneoc2_device_t** device);
/** /**
* Convenience: enumerate, find first available device (optionally filtered by type), open, and free enumeration. * Convenience: enumerate, find first available device (optionally filtered by type), open, and free enumeration.
* Pass 0 for device_type to match any device. * Pass 0 for device_type to match any device.
*
* *
* @param[in] device_type The device type to match, or 0 for any. * @param[in] device_type The device type to match, or 0 for any.
* @param[in] options Open options (e.g. icsneoc2_open_options_default). * @param[in] options Open options (e.g. icsneoc2_open_options_default).
@@ -213,24 +219,46 @@ icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_o
* *
* @return icsneoc2_error_t icsneoc2_error_success if successful. * @return icsneoc2_error_t icsneoc2_error_success if successful.
* *
* @see icsneoc2_device_close * @see icsneoc2_device_close icsneoc2_device_free
*/ */
icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, icsneoc2_open_options_t options, icsneoc2_device_t** device); icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, icsneoc2_open_options_t options, icsneoc2_device_t** device);
/**
* Reconnect to a device. This is useful if the device was disconnected and reconnected, or if the connection was lost for some reason.
*
* @param[in] device The device to reconnect.
* @param[in] options Open options (e.g. icsneoc2_open_options_default).
* @param[in] timeout_ms The timeout in milliseconds to keep trying to reconnect before giving up.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_reconnect_failed if the timeout was reached without reconnecting, or icsneoc2_device_is_valid() errors otherwise.
*/
icsneoc2_error_t icsneoc2_device_reconnect(icsneoc2_device_t* device, icsneoc2_open_options_t options, uint32_t timeout_ms);
/** /**
* Close a connection to a previously opened device. * Close a connection to a previously opened device.
* *
* After a successful call to icsneoc2_device_open(), this function must be called to close the device. * After a successful call to icsneoc2_device_open(), this function must be called to close the device.
* An already closed device will still succeed. All messages and events related to the device will be freed. * An already closed device will still succeed. The device handle must be freed with icsneoc2_device_free() when finished.
* *
* @param[in,out] device Pointer to the device to close. * @param[in,out] device Pointer to the device to close.
* *
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_device_is_valid() errors otherwise. * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_device_is_valid() errors otherwise.
* *
* @see icsneoc2_device_open icsneoc2_device_is_valid * @see icsneoc2_device_open icsneoc2_device_is_valid icsneoc2_device_free
*/ */
icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device); icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device);
/**
* Free a device handle created by icsneoc2_device_create(). Device should be closed before freeing.
*
* @param[in] device The device handle to free.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_device_is_valid() errors otherwise.
*
* @see icsneoc2_device_create icsneoc2_device_close
*/
icsneoc2_error_t icsneoc2_device_free(icsneoc2_device_t* device);
/** /**
* Get the description of a device * Get the description of a device
* *
@@ -263,6 +291,28 @@ icsneoc2_error_t icsneoc2_device_type_get(const icsneoc2_device_t* device, icsne
*/ */
icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, char* value, size_t* value_length); icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, char* value, size_t* value_length);
/**
* Get the PCB serial of a device.
*
* @param[in] device The device to get the PCB serial of.
* @param[out] value Pointer to a buffer to copy the PCB serial into. If NULL, only value_length is written.
* @param[in,out] value_length Size of the value buffer in bytes. Modified with the length of the PCB serial.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if the device does not have a PCB serial.
*/
icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length);
/**
* Get the MAC address of a device.
*
* @param[in] device The device to get the MAC address of.
* @param[out] value Pointer to a buffer to copy the MAC address into. If NULL, only value_length is written.
* @param[in,out] value_length Size of the value buffer in bytes. Modified with the length of the MAC address.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if the device does not have a MAC address.
*/
icsneoc2_error_t icsneoc2_device_mac_address_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length);
/** /**
* Set the online state of a device. * Set the online state of a device.
* *
@@ -423,6 +473,37 @@ icsneoc2_error_t icsneoc2_device_rtc_set(const icsneoc2_device_t* device, int64_
*/ */
icsneoc2_error_t icsneoc2_device_supports_tc10(const icsneoc2_device_t* device, bool* supported); icsneoc2_error_t icsneoc2_device_supports_tc10(const icsneoc2_device_t* device, bool* supported);
/**
* Send a TC10 wake request to the device on a specific network. This is used to wake up ECUs that support TC10 wake on the specified network.
*
* @param[in] device The device to send the wake request from.
* @param[in] netid The network to send the wake request on.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_transmit_message_failed otherwise.
*/
icsneoc2_error_t icsneoc2_device_tc10_wake_request(const icsneoc2_device_t* device, icsneoc2_netid_t netid);
/**
* Send a TC10 sleep request to the device on a specific network. This is used to put ECUs that support TC10 sleep on the specified network to sleep.
*
* @param[in] device The device to send the sleep request from.
* @param[in] netid The network to send the sleep request on.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_transmit_message_failed otherwise.
*/
icsneoc2_error_t icsneoc2_device_tc10_sleep_request(const icsneoc2_device_t* device, icsneoc2_netid_t netid);
/**
* Get the current TC10 sleep/wake status of a specific network.
*
* @param[in] device The device to query.
* @param[in] netid The network to query the TC10 status of.
* @param[out] sleep_status Pointer to a icsneoc2_tc10_sleep_status_t to copy the sleep status into. May be NULL if sleep status is not needed.
* @param[out] wake_status Pointer to a icsneoc2_tc10_wake_status_t to copy the wake status into. May be NULL if wake status is not needed.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_device_tc10_status_get(const icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_tc10_sleep_status_t* sleep_status, icsneoc2_tc10_wake_status_t* wake_status);
/** /**
* Get the current state of a digital I/O pin. * Get the current state of a digital I/O pin.
* *
+314 -5
View File
@@ -41,6 +41,17 @@ icsneoc2_error_t icsneoc2_message_free(icsneoc2_message_t* message);
*/ */
icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool* value); icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool* value);
/**
* Get the frame error status of a message.
*
* @param[in] message The message to check.
* @param[out] value Pointer to a bool to copy the frame error status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or
* icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value);
/** /**
* Get the Network ID (netid) of a bus message * Get the Network ID (netid) of a bus message
* *
@@ -64,6 +75,18 @@ icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc
*/ */
icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, char* value, size_t* value_length); icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, char* value, size_t* value_length);
/**
* Get the network type for a icsneoc2_netid_t.
*
* @param[in] netid The network id to get the type of.
* @param[out] network_type Pointer to a icsneoc2_network_type_t to copy the network type into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*
* @see icsneoc2_network_type_t, icsneoc2_network_type_name_get
*/
icsneoc2_error_t icsneoc2_netid_network_type_get(icsneoc2_netid_t netid, icsneoc2_network_type_t* network_type);
/** /**
* Set the Network ID (netid) of a bus message * Set the Network ID (netid) of a bus message
* *
@@ -97,11 +120,14 @@ icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_message_t* message, uint8_t*
*/ */
icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length); icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length);
#define ICSNEOC2_MESSAGE_CAN_FLAGS_RTR 0x01 // Remote Transmission Request #define ICSNEOC2_MESSAGE_CAN_FLAGS_RTR 0x01 // Remote Transmission Request
#define ICSNEOC2_MESSAGE_CAN_FLAGS_IDE 0x02 // Identifier Extension #define ICSNEOC2_MESSAGE_CAN_FLAGS_IDE 0x02 // Identifier Extension
#define ICSNEOC2_MESSAGE_CAN_FLAGS_FDF 0x04 // FD Format Indicator #define ICSNEOC2_MESSAGE_CAN_FLAGS_FDF 0x04 // FD Format Indicator
#define ICSNEOC2_MESSAGE_CAN_FLAGS_BRS 0x08 // Bit Rate Switch (FD only) #define ICSNEOC2_MESSAGE_CAN_FLAGS_BRS 0x08 // Bit Rate Switch (FD only)
#define ICSNEOC2_MESSAGE_CAN_FLAGS_ESI 0x10 // Error State Indicator (FD only) #define ICSNEOC2_MESSAGE_CAN_FLAGS_ESI 0x10 // Error State Indicator (FD only)
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED 0x20 // CAN transmit was aborted
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB 0x40 // CAN transmit lost arbitration
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR 0x80 // CAN transmit reported an error
typedef uint64_t icsneoc2_message_can_flags_t; typedef uint64_t icsneoc2_message_can_flags_t;
@@ -122,11 +148,132 @@ icsneoc2_error_t icsneoc2_message_can_props_set(icsneoc2_message_t* message, con
* @param[in] message The message to check. * @param[in] message The message to check.
* @param[out] arb_id Pointer to a uint64_t to copy the arbitration ID into. If NULL, it's ignored. * @param[out] arb_id Pointer to a uint64_t to copy the arbitration ID into. If NULL, it's ignored.
* @param[out] flags Pointer to a series of flags. If NULL, it's ignored. See icsneoc2_message_can_flags_t for details. * @param[out] flags Pointer to a series of flags. If NULL, it's ignored. See icsneoc2_message_can_flags_t for details.
* TX status flags are read-only and are only reported for CAN frames received back from the device.
* *
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise. * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/ */
icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uint64_t* arb_id, icsneoc2_message_can_flags_t* flags); icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uint64_t* arb_id, icsneoc2_message_can_flags_t* flags);
/**
* Create Ethernet message
*
* @param[out] message Pointer to icsneoc2_message_t to copy the message into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_create(icsneoc2_message_t** message);
// Standard Ethernet frame flags
#define ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT 0x001
#define ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING 0x002
#define ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED 0x004
#define ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED 0x008
#define ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR 0x010
#define ICSNEOC2_MESSAGE_ETH_FLAGS_IS_T1S 0x020
#define ICSNEOC2_MESSAGE_ETH_FLAGS_PREEMPTION_ENABLED 0x040
typedef uint64_t icsneoc2_message_eth_flags_t;
// T1S-specific Ethernet frame flags
#define ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL 0x002
#define ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST 0x004
#define ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION 0x008
#define ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE 0x010
typedef uint64_t icsneoc2_message_eth_t1s_flags_t;
/**
* Set the Ethernet specific properties of a message
*
* @param[in] message The message to modify.
* @param[in] flags Pointer to a icsneoc2_message_eth_flags_t containing the flags to set. If NULL, flags are not modified.
* @param[in] has_fcs Pointer to a bool indicating whether the FCS is present. If NULL, it's ignored.
* @param[in] fcs Pointer to a uint32_t containing the FCS value. If NULL, the FCS is not modified.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_flags_t* flags, const bool* has_fcs, const uint32_t* fcs);
/**
* Get the Ethernet specific properties of a message
*
* @param[in] message The message to check.
* @param[out] flags Pointer to a icsneoc2_message_eth_flags_t to copy the flags into. If NULL, it's ignored.
* @param[out] has_fcs Pointer to a bool indicating whether the FCS is present. If NULL, it's ignored.
* @param[out] fcs Pointer to a uint32_t to copy the FCS value into. Only valid if has_fcs is true, set to 0 if FCS is not present. If NULL, it's ignored.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_flags_t* flags, bool* has_fcs, uint32_t* fcs);
/**
* Get the destination and/or source MAC address from an Ethernet message.
* The MAC addresses are extracted from the message data bytes.
*
* @param[in] message The message to check.
* @param[out] dst_mac Pointer to a 6-byte buffer to copy the destination MAC into. If NULL, it's ignored.
* @param[out] src_mac Pointer to a 6-byte buffer to copy the source MAC into. If NULL, it's ignored.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_mac_get(icsneoc2_message_t* message, uint8_t* dst_mac, uint8_t* src_mac);
/**
* Helper function to get the EtherType field from an Ethernet message payload.
*
* EtherType is a two-octet field in an Ethernet frame (big-endian).
* It is used to indicate which protocol is encapsulated in the payload of the frame
* and is used at the receiving end by the data link layer to determine how the payload is processed.
* For example, an EtherType of 0x0800 indicates that the payload is an IPv4 packet, while 0x86DD indicates an IPv6 packet.
*
* @param[in] message The message to check.
* @param[out] ether_type Pointer to a uint16_t to copy the EtherType into.
*
* @note The EtherType is extracted from the message data bytes, so the message must have the data field and it must be
* large enough to contain the EtherType (at least 14 bytes). Returned value is host byte order.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters, icsneoc2_error_invalid_type, icsneoc2_error_invalid_data otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_ether_type_get(icsneoc2_message_t* message, uint16_t* ether_type);
/**
* Set the T1S specific properties of an Ethernet message
*
* @param[in] message The message to modify.
* @param[in] flags Pointer to a icsneoc2_message_eth_t1s_flags_t containing the T1S flags to set. If NULL, flags are not modified.
* @param[in] node_id Pointer to a uint8_t containing the T1S node ID. If NULL, it's ignored.
* @param[in] burst_count Pointer to a uint8_t containing the T1S burst count. If NULL, it's ignored.
* @param[in] symbol_type Pointer to a uint8_t containing the T1S symbol type. If NULL, it's ignored.
*
* @note If all four optional parameters are NULL, the T1S-specific state is cleared.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_t1s_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_t1s_flags_t* flags, const uint8_t* node_id, const uint8_t* burst_count, const uint8_t* symbol_type);
/**
* Get the T1S specific properties of an Ethernet message
*
* @param[in] message The message to check.
* @param[out] flags Pointer to a icsneoc2_message_eth_t1s_flags_t to copy the T1S flags into. If NULL, it's ignored.
* @param[out] node_id Pointer to a uint8_t to copy the T1S node ID into. If NULL, it's ignored.
* @param[out] burst_count Pointer to a uint8_t to copy the T1S burst count into. If NULL, it's ignored.
* @param[out] symbol_type Pointer to a uint8_t to copy the T1S symbol type into. If NULL, it's ignored.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_t1s_flags_t* flags, uint8_t* node_id, uint8_t* burst_count, uint8_t* symbol_type);
/**
* Check if a message is an Ethernet message
*
* @param[in] message The message to check.
* @param[out] is_ethernet 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(icsneoc2_message_t* message, bool* is_ethernet);
/** /**
* Check if a message is valid * Check if a message is valid
* *
@@ -171,6 +318,139 @@ icsneoc2_error_t icsneoc2_message_is_frame(icsneoc2_message_t* message, bool* is
*/ */
icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_can); icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_can);
/**
* Check if a message is a LIN message
*
* @param[in] message The message to check.
* @param[out] is_lin Pointer to a bool to copy the LIN 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_lin(icsneoc2_message_t* message, bool* is_lin);
// ---- LIN Message Types ----
typedef enum _icsneoc2_lin_msg_type_t {
icsneoc2_lin_msg_type_not_set = 0,
icsneoc2_lin_msg_type_commander_msg = 1,
icsneoc2_lin_msg_type_header_only = 2,
icsneoc2_lin_msg_type_break_only = 3,
icsneoc2_lin_msg_type_sync_only = 4,
icsneoc2_lin_msg_type_update_responder = 5,
icsneoc2_lin_msg_type_error = 6,
} _icsneoc2_lin_msg_type_t;
typedef uint8_t icsneoc2_lin_msg_type_t;
// LIN error flags bitmask
#define ICSNEOC2_LIN_ERR_RX_BREAK_ONLY 0x0001
#define ICSNEOC2_LIN_ERR_RX_BREAK_SYNC_ONLY 0x0002
#define ICSNEOC2_LIN_ERR_TX_RX_MISMATCH 0x0004
#define ICSNEOC2_LIN_ERR_RX_BREAK_NOT_ZERO 0x0008
#define ICSNEOC2_LIN_ERR_RX_BREAK_TOO_SHORT 0x0010
#define ICSNEOC2_LIN_ERR_RX_SYNC_NOT_55 0x0020
#define ICSNEOC2_LIN_ERR_RX_DATA_LEN_OVER_8 0x0040
#define ICSNEOC2_LIN_ERR_FRAME_SYNC 0x0080
#define ICSNEOC2_LIN_ERR_FRAME_MESSAGE_ID 0x0100
#define ICSNEOC2_LIN_ERR_FRAME_RESPONDER_DATA 0x0200
#define ICSNEOC2_LIN_ERR_CHECKSUM_MATCH 0x0400
typedef uint32_t icsneoc2_lin_err_flags_t;
// LIN status flags bitmask
#define ICSNEOC2_LIN_STATUS_TX_CHECKSUM_ENHANCED 0x01
#define ICSNEOC2_LIN_STATUS_TX_COMMANDER 0x02
#define ICSNEOC2_LIN_STATUS_TX_RESPONDER 0x04
#define ICSNEOC2_LIN_STATUS_TX_ABORTED 0x08
#define ICSNEOC2_LIN_STATUS_UPDATE_RESPONDER_ONCE 0x10
#define ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE 0x20
#define ICSNEOC2_LIN_STATUS_BUS_RECOVERED 0x40
#define ICSNEOC2_LIN_STATUS_BREAK_ONLY 0x80
typedef uint32_t icsneoc2_lin_status_flags_t;
/**
* Create a LIN message.
*
* @param[out] message Pointer to receive the new LIN message handle.
* @param[in] id The LIN frame ID (0-63). Bits above 0x3F are masked off.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful.
*
* @see icsneoc2_message_free
*/
icsneoc2_error_t icsneoc2_message_lin_create(icsneoc2_message_t** message, uint8_t id);
/**
* Get the LIN-specific properties of a message.
*
* Any output pointer may be NULL to skip that field.
*
* @param[in] message The message to query (must be a LIN message).
* @param[out] id Pointer to receive the LIN frame ID.
* @param[out] protected_id Pointer to receive the protected ID (ID with parity bits).
* @param[out] checksum Pointer to receive the checksum byte.
* @param[out] msg_type Pointer to receive the LIN message type.
* @param[out] is_enhanced_checksum Pointer to receive whether enhanced checksum is used.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
*/
icsneoc2_error_t icsneoc2_message_lin_props_get(const icsneoc2_message_t* message,
uint8_t* id, uint8_t* protected_id, uint8_t* checksum,
icsneoc2_lin_msg_type_t* msg_type, bool* is_enhanced_checksum);
/**
* Set the LIN-specific properties of a message.
*
* Any input pointer may be NULL to skip that field. Setting the ID also recalculates the protected ID.
*
* @param[in] message The message to modify (must be a LIN message).
* @param[in] id Pointer to the LIN frame ID to set (0-63). NULL to skip.
* @param[in] checksum Pointer to the checksum byte to set. NULL to skip.
* @param[in] msg_type Pointer to the LIN message type to set. NULL to skip.
* @param[in] is_enhanced_checksum Pointer to set enhanced checksum mode. NULL to skip.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
*/
icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
const uint8_t* id, const uint8_t* checksum,
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum);
/**
* Get the LIN error flags of a message.
*
* @param[in] message The message to query (must be a LIN message).
* @param[out] err_flags Pointer to receive the error flags bitmask.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
*
* @see ICSNEOC2_LIN_ERR_*
*/
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags);
/**
* Get the LIN status flags of a message.
*
* @param[in] message The message to query (must be a LIN message).
* @param[out] status_flags Pointer to receive the status flags bitmask.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
*
* @see ICSNEOC2_LIN_STATUS_*
*/
icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_status_flags_t* status_flags);
/**
* Calculate and set the checksum on a LIN message.
*
* Uses enhanced or classic checksum based on the isEnhancedChecksum property.
*
* @param[in] message The LIN message to calculate the checksum for.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if not a LIN message.
*/
icsneoc2_error_t icsneoc2_message_lin_calc_checksum(icsneoc2_message_t* message);
/** /**
* Get the network type of a message * Get the network type of a message
* *
@@ -183,6 +463,35 @@ icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_c
*/ */
icsneoc2_error_t icsneoc2_message_network_type_get(icsneoc2_message_t* message, icsneoc2_network_type_t* network_type); icsneoc2_error_t icsneoc2_message_network_type_get(icsneoc2_message_t* message, icsneoc2_network_type_t* network_type);
/**
* Check if a message is a CAN error message
*
* @param[in] message The message to check.
* @param[out] is_can_error Pointer to a bool to copy the CAN error 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_can_error(icsneoc2_message_t* message, bool* is_can_error);
/**
* Get the CAN error specific properties of a message
*
* @param[in] message The message to check.
* @param[out] tx_err_count Pointer to a uint8_t to copy the transmit error count into. If NULL, it's ignored.
* @param[out] rx_err_count Pointer to a uint8_t to copy the receive error count into. If NULL, it's ignored.
* @param[out] error_code Pointer to a icsneoc2_can_error_code_t to copy the error code into. If NULL, it's ignored.
* @param[out] data_error_code Pointer to a icsneoc2_can_error_code_t to copy the data phase error code into. If NULL, it's ignored.
* @param[out] flags Pointer to a icsneoc2_message_can_error_flags_t to copy the error flags into. If NULL, it's ignored.
* See ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_* for controller-error bits.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/
icsneoc2_error_t icsneoc2_message_can_error_props_get(
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
icsneoc2_can_error_code_t *error_code,
icsneoc2_can_error_code_t *data_error_code,
icsneoc2_message_can_error_flags_t *flags);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+156
View File
@@ -456,6 +456,28 @@ icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_get(icsneoc2_device_t* devic
*/ */
icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value); icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value);
/**
* Get the burst timer for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the burst timer value.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value);
/**
* Set the burst timer for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value The burst timer value to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value);
/** /**
* Get the Max burst timer for a network that supports 10BASE-T1S. * Get the Max burst timer for a network that supports 10BASE-T1S.
* *
@@ -478,6 +500,140 @@ icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_get(icsneoc2_device_t
*/ */
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value); icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value);
/**
* Get the alternate local ID for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the alternate local ID.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value);
/**
* Set the alternate local ID for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value The alternate local ID to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value);
/**
* Check if T1S termination is enabled for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the termination enable state.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_is_termination_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value);
/**
* Enable or disable T1S termination for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value True to enable termination, false to disable.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_termination_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value);
/**
* Check if T1S bus decoding beacons are enabled for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the bus decoding beacons enable state.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_beacons_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value);
/**
* Enable or disable T1S bus decoding beacons for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value True to enable bus decoding beacons, false to disable.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_beacons_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value);
/**
* Check if T1S bus decoding all is enabled for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the bus decoding all enable state.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_all_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value);
/**
* Enable or disable T1S bus decoding all for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value True to enable bus decoding all, false to disable.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_all_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value);
/**
* Get the multi-ID enable mask for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[out] value Pointer to store the multi-ID enable mask.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value);
/**
* Set the multi-ID enable mask for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] value The multi-ID enable mask to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value);
/**
* Get a multi-ID entry for a network that supports 10BASE-T1S.
*
* @param[in] device The device to check.
* @param[in] netid The network ID to check.
* @param[in] index The multi-ID index to get (0-6).
* @param[out] value Pointer to store the multi-ID value.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t* value);
/**
* Set a multi-ID entry for a network that supports 10BASE-T1S.
*
* @param[in] device The device to configure.
* @param[in] netid The network ID to configure.
* @param[in] index The multi-ID index to set (0-6).
* @param[in] value The multi-ID value to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t value);
/** /**
* Set the analog output enabled. * Set the analog output enabled.
* *
+44
View File
@@ -400,6 +400,50 @@ typedef enum _icsneoc2_memory_type_t {
typedef uint8_t icsneoc2_memory_type_t; typedef uint8_t icsneoc2_memory_type_t;
typedef enum _icsneoc2_can_error_code_t {
icsneoc2_can_error_code_no_error = 0, // No error
icsneoc2_can_error_code_stuff_error, // Stuff error
icsneoc2_can_error_code_form_error, // Form error
icsneoc2_can_error_code_ack_error, // Ack error
icsneoc2_can_error_code_bit1_error, // Bit1 error
icsneoc2_can_error_code_bit0_error, // Bit0 error
icsneoc2_can_error_code_crc_error, // CRC error
icsneoc2_can_error_code_no_change, // No change
// Must be last entry. Don't use as a CAN error code.
icsneoc2_can_error_code_maxsize
} _icsneoc2_can_error_code_t;
typedef uint8_t icsneoc2_can_error_code_t;
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF 0x01 // Bus off state
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE 0x02 // Error passive state
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN 0x04 // Error warning state
typedef uint64_t icsneoc2_message_can_error_flags_t;
typedef enum _icsneoc2_tc10_wake_status_t {
icsneoc2_tc10_wake_status_no_wake_received = 0, // No wake signal received
icsneoc2_tc10_wake_status_wake_received = 1, // Wake signal received
// Must be last entry. Don't use as a TC10 wake status.
icsneoc2_tc10_wake_status_maxsize
} _icsneoc2_tc10_wake_status_t;
typedef uint8_t icsneoc2_tc10_wake_status_t;
typedef enum _icsneoc2_tc10_sleep_status_t {
icsneoc2_tc10_sleep_status_no_sleep_received = 0, // No sleep signal received
icsneoc2_tc10_sleep_status_sleep_received = 1, // Sleep signal received
icsneoc2_tc10_sleep_status_sleep_failed = 2, // Sleep attempt failed
icsneoc2_tc10_sleep_status_sleep_aborted = 3, // Sleep attempt aborted
// Must be last entry. Don't use as a TC10 sleep status.
icsneoc2_tc10_sleep_status_maxsize
} _icsneoc2_tc10_sleep_status_t;
typedef uint8_t icsneoc2_tc10_sleep_status_t;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+5 -3
View File
@@ -20,7 +20,7 @@ bool Servd::Enabled() {
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
return enabled ? enabled[0] == '1' : false; return enabled ? enabled[0] == '1' : true;
} }
std::vector<std::string> split(const std::string_view& str, char delim = ' ') { std::vector<std::string> split(const std::string_view& str, char delim = ' ') {
@@ -52,7 +52,7 @@ void Servd::Find(std::vector<FoundDevice>& found) {
response.resize(512); response.resize(512);
const std::string version_request = SERVD_VERSION_STR + " version"; const std::string version_request = SERVD_VERSION_STR + " version";
if(!socket.transceive(version_request, response, std::chrono::milliseconds(5000))) { if(!socket.transceive(version_request, response, std::chrono::milliseconds(5000))) {
EventManager::GetInstance().add(APIEvent::Type::ServdTransceiveError, APIEvent::Severity::Error); EventManager::GetInstance().add(APIEvent::Type::ServdNotReachable, APIEvent::Severity::Error);
return; return;
} }
@@ -71,7 +71,9 @@ void Servd::Find(std::vector<FoundDevice>& found) {
for(auto&& line : lines) { for(auto&& line : lines) {
const auto cols = split(line, ' '); const auto cols = split(line, ' ');
if(cols.size() < 3) { if(cols.size() < 3) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error); if(!line.empty()) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
}
continue; continue;
} }
const auto& serial = cols[0]; const auto& serial = cols[0];
+665 -2
View File
@@ -2,7 +2,11 @@
#include <icsneo/icsneoc2.h> #include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2settings.h> #include <icsneo/icsneoc2settings.h>
#include <icsneo/icsneoc2messages.h> #include <icsneo/icsneoc2messages.h>
#include "../../api/icsneoc2/icsneoc2_internal.h"
#include <icsneo/device/devicetype.h> #include <icsneo/device/devicetype.h>
#include <icsneo/communication/message/linmessage.h>
#include <icsneo/communication/message/canmessage.h>
#include <icsneo/communication/message/canerrormessage.h>
#include <vector> #include <vector>
@@ -129,7 +133,19 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_network_type_get(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_network_type_get(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_transmit(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_transmit(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_error(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_valid(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_valid(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_can_error(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_can_error_props_get(NULL, NULL, NULL, NULL, NULL, NULL));
// LIN message NULL parameter checks
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_lin(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_create(NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_get(NULL, NULL, NULL, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_props_set(NULL, NULL, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_err_flags_get(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_status_flags_get(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_lin_calc_checksum(NULL));
// Test utility functions with NULL parameters // Test utility functions with NULL parameters
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_version_get(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_version_get(NULL, NULL));
@@ -143,7 +159,10 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_info_description_get(NULL, placeholderStr, &placeholderSizeT)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_info_description_get(NULL, placeholderStr, &placeholderSizeT));
// Test open/close with NULL parameters // Test open/close with NULL parameters
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open(NULL, 0, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_create(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_free(NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open(NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open_serial(NULL, 0, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open_serial(NULL, 0, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open_first(0, 0, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_open_first(0, 0, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_close(NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_close(NULL));
@@ -154,12 +173,22 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_online_supported(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_online_supported(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_open(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_open(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_disconnected(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_get(NULL, (int64_t *)&placeholderUnsignedInteger64)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_get(NULL, (int64_t *)&placeholderUnsignedInteger64));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_set(NULL, 0)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_set(NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_serial_get(NULL, placeholderStr, &placeholderSizeT)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_serial_get(NULL, placeholderStr, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_pcb_serial_get(NULL, &placeholderInteger8, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_mac_address_get(NULL, &placeholderInteger8, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_supports_tc10(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_supports_tc10(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_wake_request(NULL, icsneoc2_netid_dwcan_01));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_sleep_request(NULL, icsneoc2_netid_dwcan_01));
{
icsneoc2_tc10_sleep_status_t sleep_s = icsneoc2_tc10_sleep_status_no_sleep_received;
icsneoc2_tc10_wake_status_t wake_s = icsneoc2_tc10_wake_status_no_wake_received;
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, &sleep_s, &wake_s));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, NULL, NULL));
}
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_netid_network_type_get(icsneoc2_netid_dwcan_01, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_timestamp_resolution_get(NULL, &placeholderInteger32)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_timestamp_resolution_get(NULL, &placeholderInteger32));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_digital_io_get(NULL, 0, 0, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_digital_io_get(NULL, 0, 0, &placeholderBool));
@@ -212,6 +241,20 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_tx_opp_timer_set(NULL, 0, placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_tx_opp_timer_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_max_burst_timer_for_get(NULL, 0, &placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_max_burst_timer_for_get(NULL, 0, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_max_burst_timer_for_set(NULL, 0, placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_max_burst_timer_for_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_burst_timer_get(NULL, 0, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_burst_timer_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_local_id_alternate_get(NULL, 0, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_local_id_alternate_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_is_termination_enabled_for(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_termination_for_set(NULL, 0, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_is_bus_decoding_beacons_enabled_for(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_bus_decoding_beacons_for_set(NULL, 0, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_is_bus_decoding_all_enabled_for(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_bus_decoding_all_for_set(NULL, 0, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_multi_id_enable_mask_get(NULL, 0, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_multi_id_enable_mask_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_multi_id_get(NULL, 0, 0, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_t1s_multi_id_set(NULL, 0, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_misc_io_analog_output_enabled_set(NULL, 0, placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_misc_io_analog_output_enabled_set(NULL, 0, placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_misc_io_analog_output_set(NULL, 0, placeholderMiscIoAnalogVoltage)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_misc_io_analog_output_set(NULL, 0, placeholderMiscIoAnalogVoltage));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_disabled_get(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_disabled_get(NULL, &placeholderBool));
@@ -283,6 +326,16 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_diagnostic_error_code_get(NULL, &placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_diagnostic_error_code_get(NULL, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_diagnostic_error_code_count_get(NULL, &placeholderInteger8)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_diagnostic_error_code_count_get(NULL, &placeholderInteger8));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_max_coremini_size_kb_get(NULL, &placeholderInteger16)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_script_status_max_coremini_size_kb_get(NULL, &placeholderInteger16));
// Ethernet message functions
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_create(NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_props_set(NULL, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_props_get(NULL, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_mac_get(NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_ether_type_get(NULL, NULL));
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));
} }
TEST(icsneoc2, test_icsneoc2_devicetype_t) TEST(icsneoc2, test_icsneoc2_devicetype_t)
@@ -433,6 +486,60 @@ TEST(icsneoc2, icsneoc2_network_type_t)
ASSERT_EQ(sizeof(icsneoc2_network_type_t), sizeof(uint8_t)); ASSERT_EQ(sizeof(icsneoc2_network_type_t), sizeof(uint8_t));
} }
TEST(icsneoc2, test_icsneoc2_netid_network_type_get)
{
icsneoc2_network_type_t type = icsneoc2_network_type_invalid;
// CAN
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_dwcan_01, &type));
ASSERT_EQ(icsneoc2_network_type_can, type);
// LIN
type = icsneoc2_network_type_invalid;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_lin_01, &type));
ASSERT_EQ(icsneoc2_network_type_lin, type);
// Ethernet
type = icsneoc2_network_type_invalid;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_ethernet_01, &type));
ASSERT_EQ(icsneoc2_network_type_ethernet, type);
// Automotive Ethernet
type = icsneoc2_network_type_invalid;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_ae_01, &type));
ASSERT_EQ(icsneoc2_network_type_automotive_ethernet, type);
// SWCAN
type = icsneoc2_network_type_invalid;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_swcan_01, &type));
ASSERT_EQ(icsneoc2_network_type_swcan, type);
// LSFTCAN
type = icsneoc2_network_type_invalid;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_netid_network_type_get(icsneoc2_netid_lsftcan_01, &type));
ASSERT_EQ(icsneoc2_network_type_lsftcan, type);
}
TEST(icsneoc2, test_icsneoc2_tc10_wake_status_t)
{
ASSERT_EQ(icsneoc2_tc10_wake_status_no_wake_received, 0);
ASSERT_EQ(icsneoc2_tc10_wake_status_wake_received, 1);
ASSERT_EQ(icsneoc2_tc10_wake_status_maxsize, 2);
ASSERT_EQ(sizeof(icsneoc2_tc10_wake_status_t), sizeof(uint8_t));
}
TEST(icsneoc2, test_icsneoc2_tc10_sleep_status_t)
{
ASSERT_EQ(icsneoc2_tc10_sleep_status_no_sleep_received, 0);
ASSERT_EQ(icsneoc2_tc10_sleep_status_sleep_received, 1);
ASSERT_EQ(icsneoc2_tc10_sleep_status_sleep_failed, 2);
ASSERT_EQ(icsneoc2_tc10_sleep_status_sleep_aborted, 3);
ASSERT_EQ(icsneoc2_tc10_sleep_status_maxsize, 4);
ASSERT_EQ(sizeof(icsneoc2_tc10_sleep_status_t), sizeof(uint8_t));
}
TEST(icsneoc2, test_icsneoc2_io_type_t) TEST(icsneoc2, test_icsneoc2_io_type_t)
{ {
ASSERT_EQ(icsneoc2_io_type_eth_activation, 0); ASSERT_EQ(icsneoc2_io_type_eth_activation, 0);
@@ -612,6 +719,66 @@ TEST(icsneoc2, test_icsneoc2_open_options_default)
ASSERT_EQ(icsneoc2_open_options_default, expected); ASSERT_EQ(icsneoc2_open_options_default, expected);
} }
TEST(icsneoc2, test_icsneoc2_message_is_error)
{
icsneoc2_message_t message;
message.message = std::make_shared<CANMessage>();
bool value = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_error(&message, &value));
ASSERT_FALSE(value);
auto frame = std::dynamic_pointer_cast<Frame>(message.message);
ASSERT_NE(frame, nullptr);
frame->error = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_error(&message, &value));
ASSERT_TRUE(value);
icsneoc2_message_t raw_message;
raw_message.message = std::make_shared<CANErrorMessage>();
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_is_error(&raw_message, &value));
}
TEST(icsneoc2, test_icsneoc2_message_can_props_get_can_tx_flags)
{
icsneoc2_message_t message;
auto can_message = std::make_shared<CANMessage>();
message.message = can_message;
uint64_t arb_id = 0;
icsneoc2_message_can_flags_t flags = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_props_get(&message, &arb_id, &flags));
ASSERT_EQ(arb_id, 0u);
ASSERT_EQ(flags, 0u);
can_message->txAborted = true;
can_message->txLostArb = true;
can_message->txError = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_props_get(&message, &arb_id, &flags));
ASSERT_EQ(flags,
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED |
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB |
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR);
}
TEST(icsneoc2, test_icsneoc2_message_can_error_props_get_invalid_type_for_can_message)
{
icsneoc2_message_t message;
message.message = std::make_shared<CANMessage>();
uint8_t tx_err_count = 0;
uint8_t rx_err_count = 0;
icsneoc2_can_error_code_t error_code = icsneoc2_can_error_code_no_error;
icsneoc2_can_error_code_t data_error_code = icsneoc2_can_error_code_no_error;
icsneoc2_message_can_error_flags_t flags = 0;
ASSERT_EQ(icsneoc2_error_invalid_type,
icsneoc2_message_can_error_props_get(&message, &tx_err_count, &rx_err_count, &error_code, &data_error_code, &flags));
}
TEST(icsneoc2, test_icsneoc2_disk_format_enums) TEST(icsneoc2, test_icsneoc2_disk_format_enums)
{ {
// Disk layout enum values // Disk layout enum values
@@ -657,6 +824,53 @@ TEST(icsneoc2, test_icsneoc2_memory_type_enums)
ASSERT_EQ(1, icsneoc2_memory_type_sd); ASSERT_EQ(1, icsneoc2_memory_type_sd);
} }
TEST(icsneoc2, test_icsneoc2_can_error_code_t)
{
// CAN error code enum values
ASSERT_EQ(icsneoc2_can_error_code_no_error, 0);
ASSERT_EQ(icsneoc2_can_error_code_stuff_error, 1);
ASSERT_EQ(icsneoc2_can_error_code_form_error, 2);
ASSERT_EQ(icsneoc2_can_error_code_ack_error, 3);
ASSERT_EQ(icsneoc2_can_error_code_bit1_error, 4);
ASSERT_EQ(icsneoc2_can_error_code_bit0_error, 5);
ASSERT_EQ(icsneoc2_can_error_code_crc_error, 6);
ASSERT_EQ(icsneoc2_can_error_code_no_change, 7);
ASSERT_EQ(icsneoc2_can_error_code_maxsize, 8);
using _T = icsneo::CANErrorCode;
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::NoError), icsneoc2_can_error_code_no_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::StuffError), icsneoc2_can_error_code_stuff_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::FormError), icsneoc2_can_error_code_form_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::AckError), icsneoc2_can_error_code_ack_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::Bit1Error), icsneoc2_can_error_code_bit1_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::Bit0Error), icsneoc2_can_error_code_bit0_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::CRCError), icsneoc2_can_error_code_crc_error);
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::NoChange), icsneoc2_can_error_code_no_change);
ASSERT_EQ(sizeof(icsneoc2_can_error_code_t), sizeof(uint8_t));
// CAN error flag bitmask values
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF, 0x01);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE, 0x02);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN, 0x04);
ASSERT_EQ(sizeof(icsneoc2_message_can_error_flags_t), sizeof(uint64_t));
}
TEST(icsneoc2, test_icsneoc2_message_can_flags_t)
{
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_RTR, 0x01);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_IDE, 0x02);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_FDF, 0x04);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_BRS, 0x08);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_ESI, 0x10);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED, 0x20);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB, 0x40);
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR, 0x80);
ASSERT_EQ(sizeof(icsneoc2_message_can_flags_t), sizeof(uint64_t));
}
TEST(icsneoc2, test_icsneoc2_script_error_codes) TEST(icsneoc2, test_icsneoc2_script_error_codes)
{ {
// Verify script error codes exist and have distinct string representations // Verify script error codes exist and have distinct string representations
@@ -684,4 +898,453 @@ TEST(icsneoc2, test_icsneoc2_script_error_codes)
ASSERT_GT(len, 0u); ASSERT_GT(len, 0u);
} }
TEST(icsneoc2, test_lin_message_create_and_props)
{
// Create a LIN message with ID 0x15
icsneoc2_message_t* msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x15));
ASSERT_NE(msg, nullptr);
// Verify it reports as LIN
bool is_lin = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_lin(msg, &is_lin));
ASSERT_TRUE(is_lin);
// Verify it does NOT report as CAN
bool is_can = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_can(msg, &is_can));
ASSERT_FALSE(is_can);
// CAN props should fail on a LIN message
uint64_t arb_id = 0;
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_can_props_get(msg, &arb_id, NULL));
// Read back default props
uint8_t id = 0xFF, protected_id = 0, checksum = 0xFF;
icsneoc2_lin_msg_type_t msg_type = 0xFF;
bool enhanced = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, &id, &protected_id, &checksum, &msg_type, &enhanced));
ASSERT_EQ(id, 0x15);
ASSERT_NE(protected_id, 0); // Should have parity bits
ASSERT_EQ(checksum, 0);
ASSERT_EQ(msg_type, icsneoc2_lin_msg_type_not_set);
ASSERT_FALSE(enhanced);
// ID should be masked to 6 bits
icsneoc2_message_t* msg_masked = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg_masked, 0xFF));
uint8_t masked_id = 0xFF;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg_masked, &masked_id, NULL, NULL, NULL, NULL));
ASSERT_EQ(masked_id, 0x3F); // 0xFF & 0x3F
icsneoc2_message_free(msg_masked);
icsneoc2_message_free(msg);
}
TEST(icsneoc2, test_lin_message_props_set)
{
icsneoc2_message_t* msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x00));
// Set individual properties using NULL to skip others
uint8_t new_id = 0x2A;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_set(msg, &new_id, NULL, NULL, NULL));
uint8_t read_id = 0, read_pid = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, &read_id, &read_pid, NULL, NULL, NULL));
ASSERT_EQ(read_id, 0x2A);
ASSERT_NE(read_pid, 0x2A); // Protected ID should differ (has parity bits)
// Set checksum
uint8_t new_checksum = 0xAB;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_set(msg, NULL, &new_checksum, NULL, NULL));
uint8_t read_checksum = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, NULL, NULL, &read_checksum, NULL, NULL));
ASSERT_EQ(read_checksum, 0xAB);
// Set msg type
icsneoc2_lin_msg_type_t new_type = icsneoc2_lin_msg_type_commander_msg;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_set(msg, NULL, NULL, &new_type, NULL));
icsneoc2_lin_msg_type_t read_type = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, NULL, NULL, NULL, &read_type, NULL));
ASSERT_EQ(read_type, icsneoc2_lin_msg_type_commander_msg);
// Set enhanced checksum
bool new_enhanced = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_set(msg, NULL, NULL, NULL, &new_enhanced));
bool read_enhanced = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, NULL, NULL, NULL, NULL, &read_enhanced));
ASSERT_TRUE(read_enhanced);
// LIN props set on a CAN message should fail
icsneoc2_message_t* can_msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&can_msg));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_props_set(can_msg, &new_id, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_props_get(can_msg, &read_id, NULL, NULL, NULL, NULL));
icsneoc2_message_free(can_msg);
icsneoc2_message_free(msg);
}
TEST(icsneoc2, test_lin_message_data_and_netid)
{
icsneoc2_message_t* msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x10));
// Set data
uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_set(msg, data, sizeof(data)));
// Read data back
uint8_t read_data[8] = {0};
size_t read_len = sizeof(read_data);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_get(msg, read_data, &read_len));
ASSERT_EQ(read_len, sizeof(data));
ASSERT_EQ(memcmp(data, read_data, sizeof(data)), 0);
// Set and verify netid
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_01));
icsneoc2_netid_t netid = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_netid_get(msg, &netid));
ASSERT_EQ(netid, icsneoc2_netid_lin_01);
// Verify is_frame and is_raw
bool is_frame = false, is_raw = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_frame(msg, &is_frame));
ASSERT_TRUE(is_frame);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_raw(msg, &is_raw));
ASSERT_TRUE(is_raw);
icsneoc2_message_free(msg);
}
TEST(icsneoc2, test_lin_message_flags)
{
// Create a LIN message and verify default flags are clear
icsneoc2_message_t* msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x01));
icsneoc2_lin_err_flags_t err_flags = 0xFFFFFFFF;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_err_flags_get(msg, &err_flags));
ASSERT_EQ(err_flags, 0u);
icsneoc2_lin_status_flags_t status_flags = 0xFFFFFFFF;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_status_flags_get(msg, &status_flags));
ASSERT_EQ(status_flags, 0u);
// Error/status flags on CAN message should fail
icsneoc2_message_t* can_msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&can_msg));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_err_flags_get(can_msg, &err_flags));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_status_flags_get(can_msg, &status_flags));
icsneoc2_message_free(can_msg);
icsneoc2_message_free(msg);
}
TEST(icsneoc2, test_lin_message_calc_checksum)
{
icsneoc2_message_t* msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_create(&msg, 0x01));
// Set some data and calculate checksum (classic)
uint8_t data[] = {0x01, 0x02, 0x03};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_set(msg, data, sizeof(data)));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_calc_checksum(msg));
uint8_t checksum = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, NULL, NULL, &checksum, NULL, NULL));
ASSERT_NE(checksum, 0); // Checksum should be non-zero for this data
// Now set enhanced checksum and recalculate — should give a different value
uint8_t classic_checksum = checksum;
bool enhanced = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_set(msg, NULL, NULL, NULL, &enhanced));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_calc_checksum(msg));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_lin_props_get(msg, NULL, NULL, &checksum, NULL, NULL));
ASSERT_NE(checksum, classic_checksum); // Enhanced and classic should differ
// calc_checksum on a CAN message should fail
icsneoc2_message_t* can_msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&can_msg));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_lin_calc_checksum(can_msg));
icsneoc2_message_free(can_msg);
icsneoc2_message_free(msg);
}
TEST(icsneoc2, test_lin_msg_type_enum_values)
{
ASSERT_EQ(icsneoc2_lin_msg_type_not_set, 0);
ASSERT_EQ(icsneoc2_lin_msg_type_commander_msg, 1);
ASSERT_EQ(icsneoc2_lin_msg_type_header_only, 2);
ASSERT_EQ(icsneoc2_lin_msg_type_break_only, 3);
ASSERT_EQ(icsneoc2_lin_msg_type_sync_only, 4);
ASSERT_EQ(icsneoc2_lin_msg_type_update_responder, 5);
ASSERT_EQ(icsneoc2_lin_msg_type_error, 6);
ASSERT_EQ(sizeof(icsneoc2_lin_msg_type_t), sizeof(uint8_t));
}
TEST(icsneoc2, test_lin_msg_type_cpp_enum_sync)
{
using T = icsneo::LINMessage::Type;
ASSERT_EQ(static_cast<uint8_t>(T::NOT_SET), icsneoc2_lin_msg_type_not_set);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_COMMANDER_MSG), icsneoc2_lin_msg_type_commander_msg);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_HEADER_ONLY), icsneoc2_lin_msg_type_header_only);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_BREAK_ONLY), icsneoc2_lin_msg_type_break_only);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_SYNC_ONLY), icsneoc2_lin_msg_type_sync_only);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_UPDATE_RESPONDER), icsneoc2_lin_msg_type_update_responder);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_ERROR), icsneoc2_lin_msg_type_error);
}
TEST(icsneoc2, test_lin_flag_bitmask_values)
{
// Error flags should be distinct bits
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_BREAK_ONLY, 0x0001);
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_BREAK_SYNC_ONLY, 0x0002);
ASSERT_EQ(ICSNEOC2_LIN_ERR_TX_RX_MISMATCH, 0x0004);
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_BREAK_NOT_ZERO, 0x0008);
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_BREAK_TOO_SHORT, 0x0010);
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_SYNC_NOT_55, 0x0020);
ASSERT_EQ(ICSNEOC2_LIN_ERR_RX_DATA_LEN_OVER_8, 0x0040);
ASSERT_EQ(ICSNEOC2_LIN_ERR_FRAME_SYNC, 0x0080);
ASSERT_EQ(ICSNEOC2_LIN_ERR_FRAME_MESSAGE_ID, 0x0100);
ASSERT_EQ(ICSNEOC2_LIN_ERR_FRAME_RESPONDER_DATA, 0x0200);
ASSERT_EQ(ICSNEOC2_LIN_ERR_CHECKSUM_MATCH, 0x0400);
// Status flags should be distinct bits
ASSERT_EQ(ICSNEOC2_LIN_STATUS_TX_CHECKSUM_ENHANCED, 0x01);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_TX_COMMANDER, 0x02);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_TX_RESPONDER, 0x04);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_TX_ABORTED, 0x08);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_UPDATE_RESPONDER_ONCE, 0x10);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE, 0x20);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_BUS_RECOVERED, 0x40);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_BREAK_ONLY, 0x80);
}
TEST(icsneoc2, test_icsneoc2_eth_create)
{
// NULL parameter should fail
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_eth_create(NULL));
// Create an Ethernet message
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
ASSERT_NE(message, nullptr);
// Verify it is an Ethernet message
bool is_ethernet = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_ethernet(message, &is_ethernet));
ASSERT_TRUE(is_ethernet);
// Verify it is NOT a CAN message
bool is_can = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_can(message, &is_can));
ASSERT_FALSE(is_can);
// Verify it is a frame and raw message
bool is_frame = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_frame(message, &is_frame));
ASSERT_TRUE(is_frame);
bool is_raw = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_raw(message, &is_raw));
ASSERT_TRUE(is_raw);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_props_roundtrip)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
// Set several flags
icsneoc2_message_eth_flags_t flags_in =
ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING |
ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED |
ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_set(message, &flags_in, NULL, NULL));
// Get them back
icsneoc2_message_eth_flags_t flags_out = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_get(message, &flags_out, NULL, NULL));
ASSERT_EQ(flags_in, flags_out);
// Clear all flags
icsneoc2_message_eth_flags_t flags_zero = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_set(message, &flags_zero, NULL, NULL));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_get(message, &flags_out, NULL, NULL));
ASSERT_EQ(0u, flags_out);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_mac_and_ethertype)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
// Set frame data: dst MAC + src MAC + EtherType
uint8_t frame_data[] = {
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, /* Destination MAC */
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, /* Source MAC */
0x08, 0x00, /* EtherType (IPv4) */
0x01, 0x02, 0x03, 0x04 /* Payload */
};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_set(message, frame_data, sizeof(frame_data)));
// Get MAC addresses
uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_mac_get(message, dst_mac, src_mac));
ASSERT_EQ(0, memcmp(dst_mac, frame_data, 6));
ASSERT_EQ(0, memcmp(src_mac, frame_data + 6, 6));
// Get just one MAC at a time (NULL-safe)
uint8_t dst_only[6] = {0};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_mac_get(message, dst_only, NULL));
ASSERT_EQ(0, memcmp(dst_only, frame_data, 6));
uint8_t src_only[6] = {0};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_mac_get(message, NULL, src_only));
ASSERT_EQ(0, memcmp(src_only, frame_data + 6, 6));
// Get EtherType
uint16_t ether_type = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_ether_type_get(message, &ether_type));
ASSERT_EQ(0x0800, ether_type);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_mac_too_short)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
// Set data too short for MAC extraction (< 14 bytes)
uint8_t short_data[] = {0x01, 0x02, 0x03};
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_data_set(message, short_data, sizeof(short_data)));
uint8_t dst_mac[6] = {0};
ASSERT_EQ(icsneoc2_error_invalid_data, icsneoc2_message_eth_mac_get(message, dst_mac, NULL));
uint8_t src_mac[6] = {0};
ASSERT_EQ(icsneoc2_error_invalid_data, icsneoc2_message_eth_mac_get(message, NULL, src_mac));
uint16_t ether_type = 0;
ASSERT_EQ(icsneoc2_error_invalid_data, icsneoc2_message_eth_ether_type_get(message, &ether_type));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_t1s_props_roundtrip)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
// Set T1S properties
icsneoc2_message_eth_t1s_flags_t flags_in =
ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL |
ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION;
uint8_t node_id = 42;
uint8_t burst_count = 7;
uint8_t symbol_type = 3;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_set(message, &flags_in, &node_id, &burst_count, &symbol_type));
// Get them back
icsneoc2_message_eth_t1s_flags_t flags_out = 0;
uint8_t node_id_out = 0, burst_count_out = 0, symbol_type_out = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_get(message, &flags_out, &node_id_out, &burst_count_out, &symbol_type_out));
ASSERT_EQ(flags_in, flags_out);
ASSERT_EQ(42, node_id_out);
ASSERT_EQ(7, burst_count_out);
ASSERT_EQ(3, symbol_type_out);
// Set just one at a time (NULL-safe)
uint8_t new_node_id = 99;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_set(message, NULL, &new_node_id, NULL, NULL));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_get(message, &flags_out, &node_id_out, &burst_count_out, &symbol_type_out));
ASSERT_EQ(flags_in, flags_out);
ASSERT_EQ(99, node_id_out);
ASSERT_EQ(7, burst_count_out); // Unchanged
ASSERT_EQ(3, symbol_type_out); // Unchanged
// Passing all NULL parameters clears the optional T1S state.
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_set(message, NULL, NULL, NULL, NULL));
flags_out = 0xFF;
node_id_out = 0xFF;
burst_count_out = 0xFF;
symbol_type_out = 0xFF;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_t1s_props_get(message, &flags_out, &node_id_out, &burst_count_out, &symbol_type_out));
ASSERT_EQ(0, flags_out);
ASSERT_EQ(0, node_id_out);
ASSERT_EQ(0, burst_count_out);
ASSERT_EQ(0, symbol_type_out);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_fcs_roundtrip)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_create(&message));
// Initially, FCS should not be set
bool has_fcs = true;
uint32_t fcs = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_get(message, NULL, &has_fcs, &fcs));
ASSERT_FALSE(has_fcs);
// Set an FCS value via eth_props_set
uint32_t fcs_value = 0xDEADBEEF;
has_fcs = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_set(message, NULL, &has_fcs, &fcs_value));
// Get it back
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_get(message, NULL, &has_fcs, &fcs));
ASSERT_TRUE(has_fcs);
ASSERT_EQ(0xDEADBEEF, fcs);
// Clear FCS
has_fcs = false;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_set(message, NULL, &has_fcs, NULL));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_eth_props_get(message, NULL, &has_fcs, &fcs));
ASSERT_FALSE(has_fcs);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(message));
}
TEST(icsneoc2, test_icsneoc2_eth_invalid_type)
{
// Create a CAN message and try to use Ethernet functions on it
icsneoc2_message_t* can_msg = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&can_msg));
bool is_ethernet = true;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_ethernet(can_msg, &is_ethernet));
ASSERT_FALSE(is_ethernet);
icsneoc2_message_eth_flags_t flags = 0;
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_props_get(can_msg, &flags, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_props_set(can_msg, &flags, NULL, NULL));
uint8_t mac[6] = {0};
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_mac_get(can_msg, mac, NULL));
uint16_t ether_type = 0;
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_ether_type_get(can_msg, &ether_type));
uint8_t val = 0;
icsneoc2_message_eth_t1s_flags_t t1s_flags = 0;
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_t1s_props_get(can_msg, &t1s_flags, &val, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_t1s_props_set(can_msg, &t1s_flags, &val, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_eth_props_set(can_msg, NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_free(can_msg));
}