Compare commits

...

9 Commits

Author SHA1 Message Date
David Rebbe 63fd8c2f3a fixed messages 2024-12-03 21:39:47 -05:00
David Rebbe fde2f670b5 fixed sleep on linux 2024-12-03 20:39:54 -05:00
David Rebbe 802be13e74 add timestamp resolution to example. 2024-12-03 18:11:44 -05:00
David Rebbe 7dee139217 added icsneo_message_get_type. Not done. 2024-12-03 18:06:09 -05:00
David Rebbe fbeea2f79d added timeout to get messages and copied messages over. 2024-12-03 17:34:09 -05:00
David Rebbe a97f3bf297 re-order how we open the device 2024-12-03 16:02:28 -05:00
David Rebbe fc72d87c76 updated example 2024-12-03 16:02:07 -05:00
David Rebbe 76afcb410d updated cmakelists with some options disabled for now. 2024-12-03 15:40:52 -05:00
David Rebbe 29486df894 update c23 warning 2024-12-03 15:38:34 -05:00
7 changed files with 167 additions and 51 deletions

View File

@ -12,10 +12,10 @@ option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." O
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEO "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEO_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C legacy library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C legacy library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C legacy library" OFF)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C legacy library" OFF)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" OFF)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" OFF)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
# Device Drivers
@ -437,7 +437,6 @@ endif(LIBICSNEO_ENABLE_RAW_ETHERNET)
if(LIBICSNEO_BUILD_ICSNEO)
add_library(icsneo SHARED api/icsneo/icsneo.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneo/version.rc)
target_include_directories(icsneo
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
@ -446,7 +445,14 @@ if(LIBICSNEO_BUILD_ICSNEO)
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneo PRIVATE icsneocpp)
target_compile_definitions(icsneo PRIVATE ICSNEO_EXPORTS)
target_compile_definitions(icsneo
PRIVATE
ICSNEO_EXPORTS _CRT_SECURE_NO_WARNINGS
PUBLIC
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
INTERFACE
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
)
target_compile_features(icsneo PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
@ -461,8 +467,7 @@ if(LIBICSNEO_BUILD_ICSNEO_STATIC)
)
target_link_libraries(icsneo-static PUBLIC icsneocpp)
target_compile_features(icsneo-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneo PRIVATE ICSNEO_EXPORTS)
target_compile_definitions(icsneo-static PUBLIC ICSNEOC_BUILD_STATIC)
target_compile_definitions(icsneo-static PUBLIC ICSNEO_BUILD_STATIC)
endif()

View File

@ -2,14 +2,20 @@
#include <icsneo/device/device.h>
#include "icsneo/device/devicefinder.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include <string>
#include <deque>
#include <vector>
#include <algorithm>
using namespace icsneo;
typedef struct icsneo_device_t {
std::shared_ptr<Device> device;
std::vector<std::shared_ptr<icsneo_message_t>> messages;
icsneo_open_options_t options;
} icsneo_device_t;
@ -19,8 +25,7 @@ typedef struct icsneo_message_t {
} icsneo_message_t;
static std::deque<std::shared_ptr<icsneo_device_t>> g_devices;
static std::deque<std::shared_ptr<icsneo_message_t>> g_messages;
static std::vector<std::shared_ptr<icsneo_device_t>> g_devices;
ICSNEO_API icsneo_error_t icsneo_error_code(icsneo_error_t error_code, const char* value, uint32_t* value_length) {
if (!value || !value_length) {
@ -153,20 +158,20 @@ ICSNEO_API icsneo_error_t icsneo_open(icsneo_device_t* device) {
if (!dev->open()) {
return icsneo_error_open_failed;
}
// Go online
if ((device->options & icsneo_open_options_go_online) == icsneo_open_options_go_online && !dev->goOnline()) {
// Sync RTC
if ((device->options & icsneo_open_options_sync_rtc) == icsneo_open_options_sync_rtc && !dev->setRTC(std::chrono::system_clock::now())) {
dev->close();
return icsneo_error_go_online_failed;
return icsneo_error_sync_rtc_failed;
}
// Enable message polling
if ((device->options & icsneo_open_options_enable_message_polling) == icsneo_open_options_enable_message_polling && !dev->enableMessagePolling()) {
dev->close();
return icsneo_error_enable_message_polling_failed;
}
// Sync RTC
if ((device->options & icsneo_open_options_sync_rtc) == icsneo_open_options_sync_rtc && !dev->setRTC(std::chrono::system_clock::now())) {
// Go online
if ((device->options & icsneo_open_options_go_online) == icsneo_open_options_go_online && !dev->goOnline()) {
dev->close();
return icsneo_error_sync_rtc_failed;
return icsneo_error_go_online_failed;
}
return icsneo_error_success;
}
@ -180,6 +185,8 @@ ICSNEO_API icsneo_error_t icsneo_close(icsneo_device_t* device) {
return icsneo_error_success;
}
dev->close();
// Clear out old messages
device->messages.clear();
return icsneo_error_success;
}
@ -316,11 +323,21 @@ ICSNEO_API icsneo_error_t icsneo_get_timestamp_resolution(icsneo_device_t* devic
return icsneo_error_success;
}
ICSNEO_API icsneo_error_t icsneo_get_messages(icsneo_device_t* device, icsneo_message_t** messages, uint32_t* messages_count) {
ICSNEO_API icsneo_error_t icsneo_get_messages(icsneo_device_t* device, icsneo_message_t** messages, uint32_t* messages_count, uint32_t timeout_ms) {
if (!device || !messages || !messages_count) {
return icsneo_error_invalid_parameters;
}
auto dev = device->device;
// Wait for messages
auto start_time = std::chrono::steady_clock::now();
while (timeout_ms && std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start_time)
.count() < timeout_ms &&
dev->getCurrentMessageCount() == 0) {
// Lets make sure we don't busy loop, we don't have any messages yet
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
// Get the messages
auto results = dev->getMessages();
auto& queried_messages = results.first;
@ -329,27 +346,50 @@ ICSNEO_API icsneo_error_t icsneo_get_messages(icsneo_device_t* device, icsneo_me
return icsneo_error_get_messages_failed;
}
// Find the minimum number of messages
uint32_t message_size = std::minmax(static_cast<uint32_t>(queried_messages.size()), *messages_count).first;
*messages_count = message_size;
uint32_t min_size = std::minmax(static_cast<uint32_t>(queried_messages.size()), *messages_count).first;
*messages_count = min_size;
// Copy the messages into our global message container
g_messages.clear();
device->messages.clear();
for (auto& message : queried_messages) {
auto message_t = std::make_shared<icsneo_message_t>();
message_t->message = message;
g_messages.push_back(message_t);
device->messages.push_back(message_t);
}
// Copy the messages into the output array
for (uint32_t i = 0; i < min_size; i++) {
messages[i] = device->messages[i].get();
}
return icsneo_error_success;
}
ICSNEO_API icsneo_error_t icsneo_is_message_valid(icsneo_message_t* message, bool* is_valid) {
ICSNEO_API icsneo_error_t icsneo_is_message_valid(icsneo_device_t* device, icsneo_message_t* message, bool* is_valid) {
if (!message || !is_valid) {
return icsneo_error_invalid_parameters;
}
*is_valid = std::find_if(g_messages.begin(), g_messages.end(), [&](const auto& msg) {
*is_valid = std::find_if(device->messages.begin(), device->messages.end(), [&](const auto& msg) {
return msg->message == message->message;
}) == g_messages.end();
}) == device->messages.end();
return icsneo_error_success;
}
}
ICSNEO_API icsneo_error_t icsneo_message_get_type(icsneo_device_t* device, icsneo_message_t* message, uint32_t* type) {
if (!message || !type) {
return icsneo_error_invalid_parameters;
}
// TODO: Fix this in the core so we actually get the message type from the message
if (dynamic_cast<CANMessage*>(message->message.get())) {
return 100;
} else if (dynamic_cast<LINMessage*>(message->message.get())) {
return 200;
} else if (dynamic_cast<EthernetMessage*>(message->message.get())) {
return 300;
} else {
return 999;
}
return icsneo_error_success;
}

View File

@ -1,7 +1,7 @@
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." OFF)
option(LIBICSNEO_BUILD_C_LEGACY_SIMPLE_EXAMPLE "Build the command-line simple C example." OFF)
option(LIBICSNEO_BUILD_C_LEGACY_LEGACY_EXAMPLE "Build the command-line simple C example." OFF)
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_A2B_EXAMPLE "Build the A2B example." ON)

View File

@ -1,5 +1,2 @@
add_executable(libicsneo-simple-example src/main.c)
if(UNIX)
target_link_libraries(libicsneo-simple-example ${CMAKE_DL_LIBS})
endif()
target_link_libraries(libicsneo-simple-example icsneo)
target_link_libraries(libicsneo-simple-example icsneo)

View File

@ -2,6 +2,49 @@
#include <stdio.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <unistd.h>
#endif
/**
* @brief Sleeps for a specified number of milliseconds.
*
* Sleeps for a specified number of milliseconds using Sleep() on Windows and sleep() on *nix.
*
* @param ms The number of milliseconds to sleep.
*/
void sleep_ms(uint32_t ms) {
#if defined(_WIN32) || defined(_WIN64)
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
/**
* @brief Prints an error message with the given string and error code.
*
* If the error code is not icsneo_error_success, prints the error string for the given error code
* and returns the error code.
*
* @param message The message to print.
* @param error The error code to print.
* @return error as int
*/
int print_error_code(const char* message, icsneo_error_t error) {
char error_str[256] = {0};
uint32_t error_length = 256;
icsneo_error_t res = icsneo_error_code(error, error_str, &error_length);
if (res != icsneo_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\n", message, error_str);
return (int)error;
}
int main(int argc, char* argv[]) {
(void)argc;
@ -10,9 +53,9 @@ int main(int argc, char* argv[]) {
icsneo_device_t* devices[255] = {0};
uint32_t devices_count = 255;
if (icsneo_find(devices, &devices_count, NULL) != icsneo_error_success) {
printf("Failed to find devices\n");
return 1;
icsneo_error_t res = icsneo_find(devices, &devices_count, NULL);
if (res != icsneo_error_success) {
return print_error_code("Failed to find devices", res);
};
printf("Found %u devices\n", devices_count);
@ -22,38 +65,61 @@ int main(int argc, char* argv[]) {
const char description[255] = {0};
uint32_t description_length = 255;
icsneo_error_t res = icsneo_device_describe(device, description, &description_length);
res = icsneo_device_describe(device, description, &description_length);
if (res != icsneo_error_success) {
printf("Failed to get device description %d\n", res);
return 1;
return print_error_code("Failed to get device description", res);
};
// Get timestamp resolution of the device
uint32_t timestamp_resolution = 0;
res = icsneo_get_timestamp_resolution(device, &timestamp_resolution);
if (res != icsneo_error_success) {
return print_error_code("Failed to get timestamp resolution", res);
}
printf("%s timestamp resolution: %uns\n", description, timestamp_resolution);
icsneo_open_options_t options = icsneo_open_options_none;
res = icsneo_get_open_options(device, &options);
if (res != icsneo_error_success) {
printf("Failed to get open options %d\n", res);
return 1;
return print_error_code("Failed to get open options", res);
}
// Disable Syncing RTC
options &= ~icsneo_open_options_sync_rtc;
res = icsneo_set_open_options(device, options);
if (res != icsneo_error_success) {
printf("Failed to set open options %d\n", res);
return 1;
return print_error_code("Failed to set open options", res);
}
printf("Opening device: %s...\n", description);
res = icsneo_open(device);
if (res != icsneo_error_success) {
printf("Failed to open device %d\n", res);
return 1;
return print_error_code("Failed to open device", res);
};
printf("Waiting 1 second for messages...\n");
sleep_ms(1000);
icsneo_message_t* messages[20000] = {0};
uint32_t message_count = 20000;
printf("Getting messages from device with timeout of 3000ms on %s...\n", description);
res = icsneo_get_messages(device, messages, &message_count, 3000);
if (res != icsneo_error_success) {
return print_error_code("Failed to get messages from device", res);
};
printf("Received %u messages\n", message_count);
for (uint32_t i = 0; i < message_count; i++) {
icsneo_message_t* message = messages[i];
uint32_t type = 0;
res = icsneo_message_get_type(device, message, &type);
if (res != icsneo_error_success) {
return print_error_code("Failed to get message type", res);
}
printf("%d Message type: %u\n", i, type);
}
printf("Closing device: %s...\n", description);
res = icsneo_close(device);
if (res != icsneo_error_success) {
printf("Failed to close device %d\n", res);
return 1;
return print_error_code("Failed to close device", res);
};
}

View File

@ -24,11 +24,15 @@ extern "C" {
#pragma warning Unknown dynamic link import/export semantics.
#endif
#ifdef ICSNEO_BUILD_STATIC
#define ICSNEO_API
#else
#ifdef ICSNEO_EXPORTS
#define ICSNEO_API EXPORT
#else
#define ICSNEO_API IMPORT
#endif
#endif // ICSNEO_EXPORTS
#endif // ICSNEO_BUILD_STATIC
/** @brief icsneo_device_t opaque struct definition
*
@ -266,19 +270,23 @@ ICSNEO_API icsneo_error_t icsneo_get_timestamp_resolution(icsneo_device_t* devic
* @param[out] icsneo_message_t** messages Pointer to an array of icsneo_message_t to copy the messages into.
* Undefined behaviour if index is out of range of messages_count.
* @param[in,out] uint32_t* messages_count Size of the messages array. Modified with the number of messages found.
* @param[in] uint32_t timeout_ms The timeout in milliseconds to wait for messages. A value of 0 indicates a non-blocking call.
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters otherwise.
*/
ICSNEO_API icsneo_error_t icsneo_get_messages(icsneo_device_t* device, icsneo_message_t** messages, uint32_t* messages_count);
ICSNEO_API icsneo_error_t icsneo_get_messages(icsneo_device_t* device, icsneo_message_t** messages, uint32_t* messages_count, uint32_t timeout_ms);
/** @brief Check if a message is valid
*
* @param[in] icsneo_device_t* device The device to check against.
* @param[in] icsneo_message_t* message The message to check.
* @param[out] bool* is_valid Pointer to a bool to copy the validity of the message into.
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters otherwise.
*/
ICSNEO_API icsneo_error_t icsneo_is_message_valid(icsneo_message_t* message, bool* is_valid);
ICSNEO_API icsneo_error_t icsneo_is_message_valid(icsneo_device_t* device, icsneo_message_t* message, bool* is_valid);
ICSNEO_API icsneo_error_t icsneo_message_get_type(icsneo_device_t* device, icsneo_message_t* message, uint32_t* type);
#ifdef __cplusplus
}

View File

@ -160,7 +160,7 @@ typedef uint32_t icsneo_devicetype_t;
// Make sure icsneo_devicetype_t is never smaller than the actual enum
#if __STDC_VERSION__ < 202311L && !defined(__cplusplus)
_Static_assert(sizeof(_icsneo_devicetype_t) <= sizeof(icsneo_devicetype_t));
_Static_assert(sizeof(_icsneo_devicetype_t) <= sizeof(icsneo_devicetype_t), "icsneo_devicetype_t is too small");
#else // C++ or C23
static_assert(sizeof(_icsneo_devicetype_t) <= sizeof(icsneo_devicetype_t));
#endif