mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 09:28:40 +02:00
API: Added icsneoc2.
Signed-off-by: David Rebbe <drebbe@intrepidcs.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON)
|
||||
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
|
||||
option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
|
||||
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the command-line 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_A2B_EXAMPLE "Build the A2B example." ON)
|
||||
@@ -27,6 +28,10 @@ if(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE)
|
||||
add_subdirectory(c/legacy)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE)
|
||||
add_subdirectory(c2/simple)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
|
||||
add_subdirectory(cpp/simple)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_executable(libicsneo-simple-example src/main.c)
|
||||
target_link_libraries(libicsneo-simple-example icsneoc2)
|
||||
@@ -0,0 +1,454 @@
|
||||
#include <icsneo/icsneoc2.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.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 icsneoc2_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, icsneoc2_error_t error) {
|
||||
char error_str[256] = {0};
|
||||
uint32_t error_length = 256;
|
||||
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_length);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a list of messages from a device.
|
||||
*
|
||||
* This function iterates over a given array of messages received from a specified device.
|
||||
* For each message in the array, it retrieves and prints the message type and bus type.
|
||||
* If an error occurs while retrieving these details, an error message is printed.
|
||||
*
|
||||
* @param device A pointer to the icsneoc2_device_t structure representing the device.
|
||||
* @param messages An array of pointers to icsneoc2_message_t structures containing the messages to process.
|
||||
* @param messages_count The number of messages in the messages array.
|
||||
*
|
||||
* @return An icsneoc2_error_t value indicating success or failure of the message processing.
|
||||
*/
|
||||
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count);
|
||||
|
||||
/**
|
||||
* @brief Prints device and global events for a given device.
|
||||
*
|
||||
* This function retrieves and prints all current events associated with the specified device,
|
||||
* as well as any global events not tied to a specific device. For each event, it retrieves
|
||||
* and prints a description. If retrieving events or their descriptions fails, an error
|
||||
* message is printed. The function also prints a summary of the count of device-specific
|
||||
* and global events processed.
|
||||
*
|
||||
* @param device A pointer to the icsneoc2_device_t structure representing the device to get events from.
|
||||
* @param device_description A description of the device used in the output.
|
||||
*/
|
||||
void print_device_events(icsneoc2_device_t* device, const char* device_description);
|
||||
|
||||
/**
|
||||
* @brief Transmits a series of CAN messages from a device.
|
||||
*
|
||||
* This function creates and transmits 100 CAN messages with incrementing payload data.
|
||||
* Each message is configured with specific attributes such as network ID, arbitration
|
||||
* ID, CANFD status, extended status, and baudrate switch. After successfully transmitting
|
||||
* each message, it is freed from memory.
|
||||
*
|
||||
* @param device A pointer to the icsneoc2_device_t structure representing the device to transmit messages from.
|
||||
*
|
||||
* @return An icsneoc2_error_t value indicating success or failure of the message transmission process.
|
||||
*/
|
||||
int transmit_can_messages(icsneoc2_device_t* device);
|
||||
|
||||
/**
|
||||
* @brief Get the RTC (Real time clock) of a device and print it.
|
||||
*
|
||||
* @param[in] device The device to get the RTC of.
|
||||
* @param[in] description A description of the device for printing purpose.
|
||||
*
|
||||
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
|
||||
*/
|
||||
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
icsneoc2_device_t* devices[255] = {0};
|
||||
uint32_t devices_count = 255;
|
||||
|
||||
printf("Finding devices...\n");
|
||||
icsneoc2_error_t res = icsneoc2_device_find_all(devices, &devices_count, NULL);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to find devices", res);
|
||||
};
|
||||
printf("OK, %u device%s found\n", devices_count, devices_count == 1 ? "" : "s");
|
||||
// List off the devices
|
||||
for (uint32_t i = 0; i < devices_count; i++) {
|
||||
icsneoc2_device_t* device = devices[i];
|
||||
// Get description of the device
|
||||
const char description[255] = {0};
|
||||
uint32_t description_length = 255;
|
||||
res = icsneoc2_device_description_get(device, description, &description_length);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get device description", res);
|
||||
};
|
||||
printf("%.*s @ Handle %p\n", description_length, description, device);
|
||||
// Get/Set open options
|
||||
icsneoc2_open_options_t options = icsneoc2_open_options_none;
|
||||
res = icsneoc2_device_open_options_get(device, &options);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get open options", res);
|
||||
}
|
||||
// Disable Syncing RTC and going online
|
||||
options &= ~icsneoc2_open_options_sync_rtc;
|
||||
options &= ~icsneoc2_open_options_go_online;
|
||||
printf("\tDevice open options: 0x%x\n", options);
|
||||
res = icsneoc2_device_open_options_set(device, options);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to set open options", res);
|
||||
}
|
||||
// Open the device
|
||||
printf("\tOpening device: %s...\n", description);
|
||||
res = icsneoc2_device_open(device);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to open device", res);
|
||||
};
|
||||
// Get timestamp resolution of the device
|
||||
printf("\tGetting timestamp resolution... ");
|
||||
uint32_t timestamp_resolution = 0;
|
||||
res = icsneoc2_device_timestamp_resolution_get(device, ×tamp_resolution);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get timestamp resolution", res);
|
||||
}
|
||||
printf("%uns\n", timestamp_resolution);
|
||||
// Get baudrates for HSCAN
|
||||
printf("\tGetting HSCAN Baudrate... ");
|
||||
uint64_t baudrate = 0;
|
||||
res = icsneoc2_device_baudrate_get(device, icsneoc2_netid_hscan, &baudrate);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get baudrate", res);
|
||||
};
|
||||
printf("%llumbit/s\n", baudrate);
|
||||
// Get FDbaudrates for HSCAN
|
||||
printf("\tGetting FD HSCAN Baudrate... ");
|
||||
uint64_t fd_baudrate = 0;
|
||||
res = icsneoc2_device_canfd_baudrate_get(device, icsneoc2_netid_hscan, &fd_baudrate);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get FD baudrate", res);
|
||||
};
|
||||
printf("%llumbit/s\n", fd_baudrate);
|
||||
// Set baudrates for HSCAN
|
||||
// save_to_device: If this is set to true, the baudrate will be saved on the device
|
||||
// and will persist through a power cycle
|
||||
bool save_to_device = false;
|
||||
printf("\tSetting HSCAN Baudrate... ");
|
||||
res = icsneoc2_device_baudrate_set(device, icsneoc2_netid_hscan, baudrate, save_to_device);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to set baudrate", res);
|
||||
};
|
||||
printf("Ok\n");
|
||||
// Set FDbaudrates for HSCAN
|
||||
printf("\tSetting FD HSCAN Baudrate... ");
|
||||
res = icsneoc2_device_canfd_baudrate_set(device, icsneoc2_netid_hscan, fd_baudrate, save_to_device);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to set FD baudrate", res);
|
||||
};
|
||||
printf("Ok\n");
|
||||
// Get RTC
|
||||
printf("\tGetting RTC... ");
|
||||
res = get_and_print_rtc(device, description);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get RTC", res);
|
||||
}
|
||||
// Set RTC
|
||||
printf("\tSetting RTC to current time... ");
|
||||
time_t current_time = time(NULL);
|
||||
res = icsneoc2_device_rtc_set(device, current_time);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to set RTC", res);
|
||||
}
|
||||
printf("Ok\n");
|
||||
// Get RTC
|
||||
printf("\tGetting RTC... ");
|
||||
res = get_and_print_rtc(device, description);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get RTC", res);
|
||||
}
|
||||
// Go online, start acking traffic
|
||||
printf("\tGoing online... ");
|
||||
res = icsneoc2_device_go_online(device, true);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to go online", res);
|
||||
}
|
||||
// Redundant check to show how to check if the device is online, if the previous
|
||||
// icsneoc2_device_go_online call was successful we can assume we are online already
|
||||
bool is_online = false;
|
||||
res = icsneoc2_device_is_online(device, &is_online);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to check if online", res);
|
||||
}
|
||||
printf("%s\n", is_online ? "Online" : "Offline");
|
||||
// Transmit CAN messages
|
||||
res = transmit_can_messages(device);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
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
|
||||
printf("\tWaiting 1 second for messages...\n");
|
||||
sleep_ms(1000);
|
||||
// Get the messages
|
||||
icsneoc2_message_t* messages[20000] = {0};
|
||||
uint32_t message_count = 20000;
|
||||
printf("\tGetting messages from device with timeout of 3000ms on %s...\n", description);
|
||||
res = icsneoc2_device_messages_get(device, messages, &message_count, 3000);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to get messages from device", res);
|
||||
};
|
||||
// Process the messages
|
||||
res = process_messages(device, messages, message_count);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to process messages", res);
|
||||
}
|
||||
// Finally, close the device.
|
||||
printf("\tClosing device: %s...\n", description);
|
||||
res = icsneoc2_device_close(device);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_device_events(device, description);
|
||||
return print_error_code("\tFailed to close device", res);
|
||||
};
|
||||
// Print device events
|
||||
print_device_events(device, description);
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description) {
|
||||
time_t unix_epoch = 0;
|
||||
icsneoc2_error_t res = icsneoc2_device_rtc_get(device, &unix_epoch);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return res;
|
||||
}
|
||||
char rtc_time[32] = {0};
|
||||
strftime(rtc_time, sizeof(rtc_time), "%Y-%m-%d %H:%M:%S", localtime(&unix_epoch));
|
||||
printf("RTC: %lld %s\n", unix_epoch, rtc_time);
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
void print_device_events(icsneoc2_device_t* device, const char* device_description) {
|
||||
// Get device events
|
||||
icsneoc2_event_t* events[1024] = {0};
|
||||
uint32_t events_count = 1024;
|
||||
icsneoc2_error_t res = icsneoc2_device_events_get(device, events, &events_count);
|
||||
if (res != icsneoc2_error_success) {
|
||||
(void)print_error_code("\tFailed to get device events", res);
|
||||
return;
|
||||
}
|
||||
// Loop over each event and describe it.
|
||||
for (uint32_t i = 0; i < events_count; i++) {
|
||||
const char event_description[255] = {0};
|
||||
uint32_t event_description_length = 255;
|
||||
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 %u: %s\n", device_description, i, event_description);
|
||||
}
|
||||
|
||||
// Get global events
|
||||
icsneoc2_event_t* global_events[1024] = {0};
|
||||
uint32_t global_events_count = 1024;
|
||||
res = icsneoc2_events_get(global_events, &global_events_count);
|
||||
if (res != icsneoc2_error_success) {
|
||||
(void)print_error_code("\tFailed to get global events", res);
|
||||
return;
|
||||
}
|
||||
// Loop over each event and describe it.
|
||||
for (uint32_t i = 0; i < global_events_count; i++) {
|
||||
const char event_description[255] = {0};
|
||||
uint32_t event_description_length = 255;
|
||||
res = icsneoc2_event_description_get(global_events[i], event_description, &event_description_length);
|
||||
if (res != icsneoc2_error_success) {
|
||||
print_error_code("\tFailed to get global event description", res);
|
||||
continue;
|
||||
}
|
||||
printf("\t%s: Global Event %u: %s\n", device_description, i, event_description);
|
||||
}
|
||||
printf("\t%s: Received %u events and %u global events\n", device_description, events_count, global_events_count);
|
||||
}
|
||||
|
||||
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count) {
|
||||
// Print the type and bus type of each message
|
||||
uint32_t tx_count = 0;
|
||||
for (uint32_t i = 0; i < messages_count; i++) {
|
||||
icsneoc2_message_t* message = messages[i];
|
||||
// Get the message type
|
||||
icsneoc2_msg_type_t msg_type = 0;
|
||||
icsneoc2_error_t res = icsneoc2_message_type_get(device, message, &msg_type);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get message type", res);
|
||||
}
|
||||
// Get the message type name
|
||||
char msg_type_name[128] = {0};
|
||||
uint32_t msg_type_name_length = 128;
|
||||
res = icsneoc2_message_type_name_get(msg_type, msg_type_name, &msg_type_name_length);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get message type name", res);
|
||||
}
|
||||
// Check if the message is a bus message, ignore otherwise
|
||||
if (msg_type != icsneoc2_msg_type_bus) {
|
||||
printf("Ignoring message type: %u (%s)\n", msg_type, msg_type_name);
|
||||
continue;
|
||||
}
|
||||
icsneoc2_msg_bus_type_t bus_type = 0;
|
||||
res = icsneoc2_message_bus_type_get(device, message, &bus_type);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get message bus type", res);
|
||||
}
|
||||
const char bus_name[128] = {0};
|
||||
uint32_t bus_name_length = 128;
|
||||
res = icsneoc2_bus_type_name_get(bus_type, bus_name, &bus_name_length);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get message bus type name", res);
|
||||
}
|
||||
bool is_tx = false;
|
||||
res = icsneoc2_message_is_transmit(device, message, &is_tx);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get message is transmit", res);
|
||||
}
|
||||
if (is_tx) {
|
||||
tx_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("\t%d) Message type: %u bus type: %s (%u)\n", i, msg_type, bus_name, bus_type);
|
||||
if (bus_type == icsneoc2_msg_bus_type_can) {
|
||||
uint32_t arbid = 0;
|
||||
int32_t dlc = 0;
|
||||
icsneoc2_netid_t netid = 0;
|
||||
bool is_remote = false;
|
||||
bool is_canfd = false;
|
||||
bool is_extended = false;
|
||||
uint8_t data[64] = {0};
|
||||
uint32_t data_length = 64;
|
||||
const char netid_name[128] = {0};
|
||||
uint32_t netid_name_length = 128;
|
||||
uint32_t result = icsneoc2_message_netid_get(device, message, &netid);
|
||||
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
|
||||
result += icsneoc2_message_can_arbid_get(device, message, &arbid);
|
||||
result += icsneoc2_message_can_dlc_get(device, message, &dlc);
|
||||
result += icsneoc2_message_can_is_remote(device, message, &is_remote);
|
||||
result += icsneoc2_message_can_is_canfd(device, message, &is_canfd);
|
||||
result += icsneoc2_message_can_is_extended(device, message, &is_extended);
|
||||
result += icsneoc2_message_data_get(device, message, data, &data_length);
|
||||
if (result != icsneoc2_error_success) {
|
||||
printf("\tFailed get get CAN parameters (error: %u) for index %u\n", result, i);
|
||||
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: %u\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
|
||||
printf("\t Data: [");
|
||||
for (uint32_t x = 0; x < data_length; x++) {
|
||||
printf(" 0x%x", data[x]);
|
||||
}
|
||||
printf(" ]\n");
|
||||
}
|
||||
}
|
||||
printf("\tReceived %u messages total, %u were TX messages\n", messages_count, tx_count);
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
int transmit_can_messages(icsneoc2_device_t* device) {
|
||||
uint64_t counter = 0;
|
||||
const uint32_t msg_count = 100;
|
||||
printf("\tTransmitting %d messages...\n", msg_count);
|
||||
for (uint32_t i = 0; i < msg_count; i++) {
|
||||
// Create the message
|
||||
icsneoc2_message_t* message = NULL;
|
||||
uint32_t message_count = 1;
|
||||
icsneoc2_error_t res = icsneoc2_message_can_create(device, &message, message_count);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to create messages", res);
|
||||
}
|
||||
// Set the message attributes
|
||||
res = icsneoc2_message_netid_set(device, message, icsneoc2_netid_hscan);
|
||||
res += icsneoc2_message_can_arbid_set(device, message, 0x10);
|
||||
res += icsneoc2_message_can_canfd_set(device, message, true);
|
||||
res += icsneoc2_message_can_extended_set(device, message, true);
|
||||
res += icsneoc2_message_can_baudrate_switch_set(device, message, true);
|
||||
// Create the payload
|
||||
uint8_t data[8] = {0};
|
||||
data[0] = (uint8_t)(counter >> 56);
|
||||
data[1] = (uint8_t)(counter >> 48);
|
||||
data[2] = (uint8_t)(counter >> 40);
|
||||
data[3] = (uint8_t)(counter >> 32);
|
||||
data[4] = (uint8_t)(counter >> 24);
|
||||
data[5] = (uint8_t)(counter >> 16);
|
||||
data[6] = (uint8_t)(counter >> 8);
|
||||
data[7] = (uint8_t)(counter >> 0);
|
||||
res += icsneoc2_message_data_set(device, message, data, sizeof(data));
|
||||
res += icsneoc2_message_can_dlc_set(device, message, -1);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to modify message", res);
|
||||
}
|
||||
res = icsneoc2_device_messages_transmit(device, &message, &message_count);
|
||||
res += icsneoc2_message_can_free(device, message);
|
||||
if (res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to transmit messages", res);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
@@ -259,8 +259,8 @@ void example4(const std::shared_ptr<icsneo::Device>& rada2b) {
|
||||
auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::MessageCallback>(
|
||||
[] (std::shared_ptr<icsneo::Message> newMsg) {
|
||||
|
||||
if(newMsg->type == icsneo::Message::Type::Frame) {
|
||||
const auto& frame = std::dynamic_pointer_cast<icsneo::Frame>(newMsg);
|
||||
if(newMsg->type == icsneo::Message::Type::BusMessage) {
|
||||
const auto& frame = std::dynamic_pointer_cast<icsneo::BusMessage>(newMsg);
|
||||
if(frame && frame->network.getNetID() == icsneo::Network::NetID::I2C2) {
|
||||
const auto& i2cMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(frame);
|
||||
|
||||
|
||||
@@ -184,9 +184,9 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
|
||||
|
||||
void printMessage(const std::shared_ptr<icsneo::Message>& message) {
|
||||
switch(message->type) {
|
||||
case icsneo::Message::Type::Frame: {
|
||||
case icsneo::Message::Type::BusMessage: {
|
||||
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
|
||||
switch(frame->network.getType()) {
|
||||
case icsneo::Network::Type::CAN: {
|
||||
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
||||
@@ -264,7 +264,7 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} // end of icsneo::Message::Type::Frame
|
||||
} // end of icsneo::Message::Type::BusMessage
|
||||
case icsneo::Message::Type::CANErrorCount: {
|
||||
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
|
||||
auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
|
||||
|
||||
@@ -96,8 +96,8 @@ int main() {
|
||||
std::cout << "OK" << std::endl << std::endl;
|
||||
|
||||
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) {
|
||||
if(icsneo::Message::Type::Frame == message->type) {
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||
if(icsneo::Message::Type::BusMessage == message->type) {
|
||||
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
|
||||
if(icsneo::Network::Type::LIN == frame->network.getType()) {
|
||||
auto msg = std::static_pointer_cast<icsneo::LINMessage>(message);
|
||||
std::cout << msg->network << " RX frame | ID: 0x" << std::hex << static_cast<int>(msg->ID) << " | ";
|
||||
|
||||
@@ -92,8 +92,8 @@ int main()
|
||||
|
||||
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message)
|
||||
{
|
||||
if(icsneo::Message::Type::Frame == message->type) {
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||
if(icsneo::Message::Type::BusMessage == message->type) {
|
||||
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
|
||||
if(icsneo::Network::Type::MDIO == frame->network.getType()) {
|
||||
auto msg = std::static_pointer_cast<icsneo::MDIOMessage>(message);
|
||||
std::cout << msg->network << " " << ((msg->isTXMsg)? "TX" : "RX") << " frame\n";
|
||||
|
||||
@@ -169,9 +169,9 @@ int main() {
|
||||
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
|
||||
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([](std::shared_ptr<icsneo::Message> message) {
|
||||
switch(message->type) {
|
||||
case icsneo::Message::Type::Frame: {
|
||||
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||
case icsneo::Message::Type::BusMessage: {
|
||||
// A message of type BusMessage is guaranteed to be a BusMessage, so we can static cast safely
|
||||
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
|
||||
switch(frame->network.getType()) {
|
||||
case icsneo::Network::Type::CAN: {
|
||||
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
||||
@@ -202,7 +202,7 @@ int main() {
|
||||
case icsneo::Network::Type::Ethernet: {
|
||||
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
|
||||
|
||||
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
|
||||
std::cout << "\t\t" << ethMessage->network << " BusMessage - " << std::dec
|
||||
<< ethMessage->data.size() << " bytes on wire\n";
|
||||
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
|
||||
|
||||
@@ -249,7 +249,7 @@ int main() {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} // end of icsneo::Message::Type::Frame
|
||||
} // end of icsneo::Message::Type::BusMessage
|
||||
case icsneo::Message::Type::CANErrorCount: {
|
||||
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
|
||||
auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
|
||||
|
||||
@@ -16,13 +16,13 @@ void onEvent(std::shared_ptr<icsneo::APIEvent> event) {
|
||||
std::cout << event->describe() << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> constructRandomFrames(size_t frameCount, MessageType frameType) {
|
||||
std::vector<std::shared_ptr<icsneo::BusMessage>> constructRandomFrames(size_t frameCount, MessageType frameType) {
|
||||
static constexpr size_t ClassicCANSize = 8;
|
||||
static constexpr size_t CANFDSize = 64;
|
||||
static constexpr size_t ShortEthSize = 500;
|
||||
static constexpr size_t LongEthSize = 1500;
|
||||
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> frames;
|
||||
std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
|
||||
std::random_device randDev;
|
||||
std::mt19937 randEngine(randDev());
|
||||
std::uniform_int_distribution randByteDist(0,255);
|
||||
@@ -166,10 +166,10 @@ int main(int argc, char* argv[]) {
|
||||
uint64_t canFrameCount = 0;
|
||||
uint64_t ethFrameCount = 0;
|
||||
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
|
||||
if(msg->type != icsneo::Message::Type::Frame) {
|
||||
if(msg->type != icsneo::Message::Type::BusMessage) {
|
||||
return;
|
||||
}
|
||||
const auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
|
||||
const auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
|
||||
if(frame->network.getType() == icsneo::Network::Type::CAN) {
|
||||
++canFrameCount;
|
||||
} else if(frame->network.getType() == icsneo::Network::Type::Ethernet) {
|
||||
@@ -200,7 +200,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
const uint8_t NumFrameTypes = 4;
|
||||
const size_t FrameCountPerType = 2500;
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> frames;
|
||||
std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
|
||||
for(uint8_t i = 0; i < NumFrameTypes; i++) {
|
||||
std::cout << "info: transmitting " << FrameCountPerType << " random " << MessageTypeLabels[i] << " frames" << std::endl;
|
||||
auto tempFrames = constructRandomFrames(FrameCountPerType, static_cast<MessageType>(i));
|
||||
@@ -216,10 +216,10 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
size_t currentMessage = 0;
|
||||
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
|
||||
if(msg->type != icsneo::Message::Type::Frame) {
|
||||
if(msg->type != icsneo::Message::Type::BusMessage) {
|
||||
return;
|
||||
}
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
|
||||
auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
|
||||
if(frames[currentMessage]->data == frame->data) {
|
||||
currentMessage++;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
libicsneoc2 simple Go example
|
||||
====
|
||||
|
||||
This is a mirror of the icsneoc2 C simple example, written in Go.
|
||||
|
||||
Windows
|
||||
====
|
||||
|
||||
- Install [msys64](https://www.msys2.org/) with gcc (`pacman -S mingw-w64-ucrt-x86_64-gcc`)
|
||||
- Setup environment variables:
|
||||
- add `C:\msys64\ucrt64\bin` to `PATH`
|
||||
- Powershell: `$env:PATH += ";C:\msys64\ucrt64\bin"`
|
||||
- `gcc --version` should return a version now
|
||||
- enable cgo: `CGO_ENABLED = 1`
|
||||
- Powershell: `$env:CGO_ENABLED=1`
|
||||
- Set compiler to gcc
|
||||
- Powershell: `$env:CC="gcc"`
|
||||
- `icsneoc2.dll` should be in path (or inside this directory)
|
||||
- `go run simple`
|
||||
@@ -0,0 +1,3 @@
|
||||
module simple
|
||||
|
||||
go 1.23.4
|
||||
@@ -0,0 +1,354 @@
|
||||
package main
|
||||
|
||||
// #cgo CFLAGS: -I../../../include
|
||||
// #cgo LDFLAGS: -L../../../build -licsneoc2
|
||||
// #include "icsneo/icsneoc2.h"
|
||||
// #include "stdint.h"
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Find devices connected to host.
|
||||
devices := [255]*C.icsneoc2_device_t{nil}
|
||||
devicesCount := 255
|
||||
print("Finding devices... ")
|
||||
if res := C.icsneoc2_device_find_all(&devices[0], (*C.uint)(unsafe.Pointer(&devicesCount)), nil); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("OK, %d device(s) found\n", devicesCount)
|
||||
// List off the devices
|
||||
for _, device := range devices[:devicesCount] {
|
||||
// Get description of the device
|
||||
description := make([]byte, 255)
|
||||
descriptionLength := 255
|
||||
if res := C.icsneoc2_device_description_get(device, (*C.char)(unsafe.Pointer(&description[0])), (*C.uint)(unsafe.Pointer(&descriptionLength))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%s @ Handle %p\n", description, device)
|
||||
// Get/Set open options
|
||||
options := C.icsneoc2_open_options_none
|
||||
if res := C.icsneoc2_device_open_options_get(device, (*C.icsneoc2_open_options_t)(unsafe.Pointer(&options))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
options &= ^C.icsneoc2_open_options_sync_rtc
|
||||
options &= ^C.icsneoc2_open_options_go_online
|
||||
fmt.Printf("\tDevice open options: 0x%X\n", options)
|
||||
if res := C.icsneoc2_device_open_options_set(device, (C.icsneoc2_open_options_t)(options)); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
// Open the device
|
||||
fmt.Printf("\tOpening device: %s...\n", description)
|
||||
if res := C.icsneoc2_device_open(device); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
defer func() {
|
||||
if !printDeviceEvents(device, string(description)) {
|
||||
println("\tFailed to print events...")
|
||||
}
|
||||
fmt.Printf("\tClosing device: %s...\n", description)
|
||||
if res := C.icsneoc2_device_close(device); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
}()
|
||||
// Get timestamp resolution of the device
|
||||
fmt.Printf("\tGetting timestamp resolution... ")
|
||||
var timestampResolution C.uint = 0
|
||||
if res := C.icsneoc2_device_timestamp_resolution_get(device, ×tampResolution); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%dns\n", timestampResolution)
|
||||
// Get baudrates for HSCAN
|
||||
fmt.Printf("\tGetting HSCAN Baudrate... ")
|
||||
var baudrate uint64 = 0
|
||||
if res := C.icsneoc2_device_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&baudrate))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%dmbit/s\n", baudrate)
|
||||
// Get FD baudrates for HSCAN
|
||||
fmt.Printf("\tGetting FD HSCAN Baudrate... ")
|
||||
var fdBaudrate uint64 = 0
|
||||
if res := C.icsneoc2_device_canfd_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&fdBaudrate))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%dmbit/s\n", fdBaudrate)
|
||||
// Set baudrates for HSCAN
|
||||
// saveToDevice: If this is set to true, the baudrate will be saved on the device
|
||||
// and will persist through a power cycle
|
||||
var saveToDevice C.bool = false
|
||||
fmt.Printf("\tSetting HSCAN Baudrate... ")
|
||||
if res := C.icsneoc2_device_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(baudrate), saveToDevice); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("OK\n")
|
||||
// Set FD baudrates for HSCAN
|
||||
fmt.Printf("\tSetting FD HSCAN Baudrate... ")
|
||||
if res := C.icsneoc2_device_canfd_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(fdBaudrate), saveToDevice); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("OK\n")
|
||||
// Get RTC
|
||||
fmt.Printf("\tGetting RTC... ")
|
||||
var unix_epoch C.int64_t = 0
|
||||
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
currentRTC := time.Unix(int64(unix_epoch), 0)
|
||||
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
|
||||
// Set RTC
|
||||
fmt.Printf("\tSetting RTC... ")
|
||||
unix_epoch = (C.int64_t)(time.Now().Unix())
|
||||
if res := C.icsneoc2_device_rtc_set(device, unix_epoch); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
fmt.Printf("OK\n")
|
||||
// Get RTC
|
||||
fmt.Printf("\tGetting RTC... ")
|
||||
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
currentRTC = time.Unix(int64(unix_epoch), 0)
|
||||
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
|
||||
// Go online, start acking traffic
|
||||
fmt.Printf("\tGoing online... ")
|
||||
if res := C.icsneoc2_device_go_online(device, true); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
// Redundant check to show how to check if the device is online, if the previous
|
||||
// icsneoc2_device_go_online call was successful we can assume we are online already
|
||||
var isOnline C.bool = false
|
||||
if res := C.icsneoc2_device_is_online(device, &isOnline); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
if isOnline {
|
||||
println("Online")
|
||||
} else {
|
||||
println("Offline")
|
||||
}
|
||||
// Transmit CAN messages
|
||||
if !transmitCANMessages(device) {
|
||||
return
|
||||
}
|
||||
// Wait for the bus to collect some messages, requires an active bus to get messages
|
||||
println("\tWaiting 1 second for messages...")
|
||||
time.Sleep(1 * time.Second)
|
||||
// Get the messages
|
||||
messages := [20000]*C.icsneoc2_message_t{nil}
|
||||
var messagesCount C.uint32_t = 20000
|
||||
if res := C.icsneoc2_device_messages_get(device, &messages[0], &messagesCount, 3000); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return
|
||||
}
|
||||
// Process the messages
|
||||
if !processMessages(device, messages[0:messagesCount]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printError(err C.icsneoc2_error_t) C.icsneoc2_error_t {
|
||||
buffer := make([]byte, 255)
|
||||
bufferLength := 255
|
||||
res := C.icsneoc2_error_code_get(err, (*C.char)(unsafe.Pointer(&buffer[0])), (*C.uint)(unsafe.Pointer(&bufferLength)))
|
||||
if res != C.icsneoc2_error_success {
|
||||
println("\ticsneoc2_get_error_code failed, original error:", err)
|
||||
return res
|
||||
}
|
||||
println("\tError:", string(buffer[:bufferLength]))
|
||||
return res
|
||||
}
|
||||
|
||||
func printDeviceEvents(device *C.icsneoc2_device_t, deviceDescription string) bool {
|
||||
// Get device events
|
||||
events := [1024]*C.icsneoc2_event_t{nil}
|
||||
var eventsCount C.uint32_t = 1024
|
||||
if res := C.icsneoc2_device_events_get(device, &events[0], &eventsCount); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
for i, event := range events[:eventsCount] {
|
||||
eventDescription := make([]byte, 255)
|
||||
var eventDescriptionLength C.uint32_t = 255
|
||||
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&eventDescription[0])), &eventDescriptionLength); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("\t%s: Event %d: %s\n", deviceDescription, i, eventDescription)
|
||||
}
|
||||
// Get global events
|
||||
globalEvents := [1024]*C.icsneoc2_event_t{nil}
|
||||
var globalEventsCount C.uint32_t = 1024
|
||||
if res := C.icsneoc2_events_get(&globalEvents[0], &globalEventsCount); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
for i, event := range globalEvents[:globalEventsCount] {
|
||||
globalEventsDescription := make([]byte, 255)
|
||||
var globalEventsDescriptionLength C.uint32_t = 255
|
||||
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&globalEventsDescription[0])), &globalEventsDescriptionLength); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("\t%s: Global Event %d: %s\n", deviceDescription, i, globalEventsDescription)
|
||||
}
|
||||
fmt.Printf("\t%s: Received %d events and %d global events\n", deviceDescription, eventsCount, globalEventsCount)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func transmitCANMessages(device *C.icsneoc2_device_t) bool {
|
||||
var counter uint32 = 0
|
||||
const msgCount int = 100
|
||||
fmt.Printf("\tTransmitting %d messages...\n", msgCount)
|
||||
for range msgCount {
|
||||
// Create the message
|
||||
var message *C.icsneoc2_message_t = nil
|
||||
if res := C.icsneoc2_message_can_create(device, &message, 1); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
defer func() {
|
||||
if res := C.icsneoc2_message_can_free(device, message); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
}
|
||||
}()
|
||||
// Set the message attributes
|
||||
res := C.icsneoc2_message_netid_set(device, message, C.icsneoc2_netid_hscan)
|
||||
res += C.icsneoc2_message_can_arbid_set(device, message, 0x10)
|
||||
res += C.icsneoc2_message_can_canfd_set(device, message, true)
|
||||
res += C.icsneoc2_message_can_extended_set(device, message, true)
|
||||
res += C.icsneoc2_message_can_baudrate_switch_set(device, message, true)
|
||||
// Create the payload
|
||||
data := [...]C.uint8_t{
|
||||
(C.uint8_t)(counter >> 56),
|
||||
(C.uint8_t)(counter >> 48),
|
||||
(C.uint8_t)(counter >> 40),
|
||||
(C.uint8_t)(counter >> 32),
|
||||
(C.uint8_t)(counter >> 24),
|
||||
(C.uint8_t)(counter >> 16),
|
||||
(C.uint8_t)(counter >> 8),
|
||||
(C.uint8_t)(counter >> 0),
|
||||
}
|
||||
res += C.icsneoc2_message_data_set(device, message, &data[0], (C.uint32_t)(len(data)))
|
||||
res += C.icsneoc2_message_can_dlc_set(device, message, -1)
|
||||
if res != C.icsneoc2_error_success {
|
||||
fmt.Printf("\tFailed to modify message: %d\n", res)
|
||||
return false
|
||||
}
|
||||
var messageCount C.uint32_t = 1
|
||||
if res := C.icsneoc2_device_messages_transmit(device, &message, &messageCount); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
counter += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func processMessages(device *C.icsneoc2_device_t, messages []*C.icsneoc2_message_t) bool {
|
||||
txCount := 0
|
||||
for i, message := range messages {
|
||||
// Get the message type
|
||||
var msgType C.icsneoc2_msg_type_t = 0
|
||||
if res := C.icsneoc2_message_type_get(device, message, &msgType); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
// Get the message type name
|
||||
msgTypeName := make([]byte, 128)
|
||||
var msgTypeNameLength C.uint32_t = 128
|
||||
if res := C.icsneoc2_message_type_name_get(msgType, (*C.char)(unsafe.Pointer(&msgTypeName[0])), &msgTypeNameLength); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
// Check if the message is a bus message, ignore otherwise
|
||||
if msgType != C.icsneoc2_msg_type_bus {
|
||||
fmt.Print("\tIgnoring message type: %d (%s)\n", msgType, msgTypeName)
|
||||
continue
|
||||
}
|
||||
// Get the message bus type
|
||||
var msgBusType C.icsneoc2_msg_bus_type_t = 0
|
||||
if res := C.icsneoc2_message_bus_type_get(device, message, &msgBusType); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
// Get the bus message type name
|
||||
msgBusTypeName := make([]byte, 128)
|
||||
var msgBusTypeNameLength C.uint32_t = 128
|
||||
if res := C.icsneoc2_bus_type_name_get(msgBusType, (*C.char)(unsafe.Pointer(&msgBusTypeName[0])), &msgBusTypeNameLength); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
// Check if the message is a transmit message
|
||||
var isTransmit C.bool = false
|
||||
if res := C.icsneoc2_message_is_transmit(device, message, &isTransmit); res != C.icsneoc2_error_success {
|
||||
printError(res)
|
||||
return false
|
||||
}
|
||||
if isTransmit {
|
||||
txCount += 1
|
||||
continue
|
||||
}
|
||||
fmt.Printf("\t%d) Message type: %d bus type: %s (%d)\n", i, msgType, msgBusTypeName, msgBusType)
|
||||
if msgBusType == C.icsneoc2_msg_bus_type_can {
|
||||
var arbid C.uint32_t = 0
|
||||
var dlc C.int32_t = 0
|
||||
var netid C.icsneoc2_netid_t = 0
|
||||
var isRemote C.bool = false
|
||||
var isCanfd C.bool = false
|
||||
var isExtended C.bool = false
|
||||
data := make([]byte, 64)
|
||||
var dataLength C.uint32_t = 64
|
||||
netidName := make([]byte, 128)
|
||||
var netidNameLength C.uint32_t = 128
|
||||
var res C.icsneoc2_error_t = C.icsneoc2_error_success
|
||||
res = C.icsneoc2_message_netid_get(device, message, &netid)
|
||||
res += C.icsneoc2_netid_name_get(netid, (*C.char)(unsafe.Pointer(&netidName)), &netidNameLength)
|
||||
res += C.icsneoc2_message_can_arbid_get(device, message, &arbid)
|
||||
res += C.icsneoc2_message_can_dlc_get(device, message, &dlc)
|
||||
res += C.icsneoc2_message_can_is_remote(device, message, &isRemote)
|
||||
res += C.icsneoc2_message_can_is_canfd(device, message, &isCanfd)
|
||||
res += C.icsneoc2_message_can_is_extended(device, message, &isExtended)
|
||||
res += C.icsneoc2_message_data_get(device, message, (*C.uint8_t)(unsafe.Pointer(&data[0])), &dataLength)
|
||||
// We really should check the error message for all of these since we can't tell the exact error if something
|
||||
// bad happens but for an example this should be okay.
|
||||
if res != C.icsneoc2_error_success {
|
||||
fmt.Printf("\tFailed to get CAN parameters (error: %d) for index %d\n", res, i)
|
||||
continue
|
||||
}
|
||||
// Finally lets print the RX message
|
||||
fmt.Printf("\t NetID: %s (0x%X)\tArbID: 0x%X\t DLC: %d\t Remote: %t\t CANFD: %t\t Extended: %t\t Data length: %d\n", netidName, netid, arbid, dlc, isRemote, isCanfd, isExtended, dataLength)
|
||||
fmt.Printf("\t Data: [")
|
||||
for _, d := range data[:dataLength] {
|
||||
fmt.Printf(" 0x%X", d)
|
||||
}
|
||||
println(" ]")
|
||||
continue
|
||||
} else {
|
||||
fmt.Printf("\tIgnoring bus message type: %d (%s)\n", msgBusType, msgBusTypeName)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
fmt.Printf("\tReceived %d messages total, %d were TX messages\n", len(messages), txCount)
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# This file is for zig-specific build artifacts.
|
||||
# If you have OS-specific or editor-specific files to ignore,
|
||||
# such as *.swp or .DS_Store, put those in your global
|
||||
# ~/.gitignore and put this in your ~/.gitconfig:
|
||||
#
|
||||
# [core]
|
||||
# excludesfile = ~/.gitignore
|
||||
#
|
||||
# Cheers!
|
||||
# -andrewrk
|
||||
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
/release/
|
||||
/debug/
|
||||
/build/
|
||||
/build-*/
|
||||
/docgen_tmp/
|
||||
|
||||
# Although this was renamed to .zig-cache, let's leave it here for a few
|
||||
# releases to make it less annoying to work with multiple branches.
|
||||
zig-cache/
|
||||
@@ -0,0 +1,72 @@
|
||||
const std = @import("std");
|
||||
|
||||
// Although this function looks imperative, note that its job is to
|
||||
// declaratively construct a build graph that will be executed by an external
|
||||
// runner.
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{ .default_target = .{ .abi = .msvc } });
|
||||
|
||||
// Standard optimization options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "simple",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.linkLibC();
|
||||
// Add support for icsneoc2
|
||||
exe.addIncludePath(b.path("../../../include"));
|
||||
exe.addLibraryPath(b.path("../../../build"));
|
||||
exe.linkSystemLibrary("icsneoc2");
|
||||
|
||||
// This declares intent for the executable to be installed into the
|
||||
// standard location when the user invokes the "install" step (the default
|
||||
// step when running `zig build`).
|
||||
b.installArtifact(exe);
|
||||
|
||||
// This *creates* a Run step in the build graph, to be executed when another
|
||||
// step is evaluated that depends on it. The next line below will establish
|
||||
// such a dependency.
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
||||
// By making the run step depend on the install step, it will be run from the
|
||||
// installation directory rather than directly from within the cache directory.
|
||||
// This is not necessary, however, if the application depends on other installed
|
||||
// files, this ensures they will be present and in the expected location.
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
// This allows the user to pass arguments to the application in the build
|
||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
// This creates a build step. It will be visible in the `zig build --help` menu,
|
||||
// and can be selected like this: `zig build run`
|
||||
// This will evaluate the `run` step rather than the default, which is "install".
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
const exe_unit_tests = b.addTest(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||
|
||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||
// the `zig build --help` menu, providing a way for the user to request
|
||||
// running the unit tests.
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&run_exe_unit_tests.step);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
.{
|
||||
// This is the default name used by packages depending on this one. For
|
||||
// example, when a user runs `zig fetch --save <url>`, this field is used
|
||||
// as the key in the `dependencies` table. Although the user can choose a
|
||||
// different name, most users will stick with this provided value.
|
||||
//
|
||||
// It is redundant to include "zig" in this name because it is already
|
||||
// within the Zig package namespace.
|
||||
.name = "simple",
|
||||
|
||||
// This is a [Semantic Version](https://semver.org/).
|
||||
// In a future version of Zig it will be used for package deduplication.
|
||||
.version = "0.0.0",
|
||||
|
||||
// This field is optional.
|
||||
// This is currently advisory only; Zig does not yet do anything
|
||||
// with this value.
|
||||
//.minimum_zig_version = "0.11.0",
|
||||
|
||||
// This field is optional.
|
||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||
// Once all dependencies are fetched, `zig build` no longer requires
|
||||
// internet connectivity.
|
||||
.dependencies = .{
|
||||
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
||||
//.example = .{
|
||||
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||
// // the new URL.
|
||||
// .url = "https://example.com/foo.tar.gz",
|
||||
//
|
||||
// // This is computed from the file contents of the directory of files that is
|
||||
// // obtained after fetching `url` and applying the inclusion rules given by
|
||||
// // `paths`.
|
||||
// //
|
||||
// // This field is the source of truth; packages do not come from a `url`; they
|
||||
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
||||
// // obtain a package matching this `hash`.
|
||||
// //
|
||||
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
||||
// .hash = "...",
|
||||
//
|
||||
// // When this is provided, the package is found in a directory relative to the
|
||||
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||
// // computed. This field and `url` are mutually exclusive.
|
||||
// .path = "foo",
|
||||
//
|
||||
// // When this is set to `true`, a package is declared to be lazily
|
||||
// // fetched. This makes the dependency only get fetched if it is
|
||||
// // actually used.
|
||||
// .lazy = false,
|
||||
//},
|
||||
},
|
||||
|
||||
// Specifies the set of files and directories that are included in this package.
|
||||
// Only files and directories listed here are included in the `hash` that
|
||||
// is computed for this package. Only files listed here will remain on disk
|
||||
// when using the zig package manager. As a rule of thumb, one should list
|
||||
// files required for compilation plus any license(s).
|
||||
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
||||
// the build root itself.
|
||||
// A directory listed here means that all files within, recursively, are included.
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// For example...
|
||||
//"LICENSE",
|
||||
//"README.md",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
|
||||
const ics = @cImport({
|
||||
@cInclude("icsneo/icsneoc2.h");
|
||||
@cInclude("icsneo/icsneoc2types.h");
|
||||
});
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("time.h");
|
||||
});
|
||||
|
||||
pub fn main() !void {
|
||||
// Find devices connected to host.
|
||||
const MAX_DEVICE_COUNT: u32 = 255;
|
||||
var device_buffer: [MAX_DEVICE_COUNT]?*ics.icsneoc2_device_t = undefined;
|
||||
var devices_count: u32 = MAX_DEVICE_COUNT;
|
||||
print("Finding devices... ", .{});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_find_all(&device_buffer, &devices_count, null),
|
||||
"Failed to find device",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("OK, {d} device{s} found\n", .{ devices_count, if (devices_count == 1) "" else "s" });
|
||||
// Lets just take a slice of the entire device buffer
|
||||
const devices = device_buffer[0..devices_count];
|
||||
// List off the devices
|
||||
for (devices) |device| {
|
||||
// Get description of the device
|
||||
var description: [255]u8 = [_:0]u8{0} ** 255;
|
||||
var description_length: u32 = 255;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_description_get(device, &description, &description_length),
|
||||
"\tFailed to get device description",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("{s}. {*}\n", .{ description, device.? });
|
||||
// Get/Set open options
|
||||
var options: ics.icsneoc2_open_options_t = ics.icsneoc2_open_options_none;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_open_options_get(device, &options),
|
||||
"\tFailed to get device open options",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
// Disable Syncing RTC and going online
|
||||
options &= ~@as(ics.icsneoc2_open_options_t, ics.icsneoc2_open_options_sync_rtc);
|
||||
options &= ~@as(ics.icsneoc2_open_options_t, ics.icsneoc2_open_options_go_online);
|
||||
print("\tDevice open options: 0x{X}\n", .{options});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_open_options_set(device, options),
|
||||
"\tFailed to set device open options",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
// Open the device
|
||||
print("\tOpening device: {s}...\n", .{description});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_open(device),
|
||||
"\tFailed to open device",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
defer {
|
||||
// Finally, close the device.
|
||||
if (!print_device_events(device)) {
|
||||
print("\tFailed to print events...\n", .{});
|
||||
}
|
||||
print("\tClosing device: {s}... ", .{description});
|
||||
if (check_error(
|
||||
ics.icsneoc2_device_close(device),
|
||||
"\tFailed to close device",
|
||||
)) {
|
||||
print("OK\n", .{});
|
||||
}
|
||||
}
|
||||
// Get timestamp resolution of the device
|
||||
print("\tGetting timestamp resolution... ", .{});
|
||||
var timestamp_resolution: u32 = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_timestamp_resolution_get(device, ×tamp_resolution),
|
||||
"\tFailed to get timestamp resolution",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("{d}ns\n", .{timestamp_resolution});
|
||||
// Get baudrates for HSCAN
|
||||
print("\tGetting HSCAN baudrate... ", .{});
|
||||
var baudrate: u64 = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_baudrate_get(device, ics.icsneoc2_netid_hscan, &baudrate),
|
||||
"\tFailed to get baudrate",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("{d}mbit/s\n", .{baudrate});
|
||||
// Get FDbaudrates for HSCAN
|
||||
print("\tGetting FD HSCAN baudrate... ", .{});
|
||||
var fd_baudrate: u64 = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_canfd_baudrate_get(device, ics.icsneoc2_netid_hscan, &fd_baudrate),
|
||||
"\tFailed to get FD baudrate",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("{d}mbit/s\n", .{fd_baudrate});
|
||||
// Set baudrates for HSCAN
|
||||
// save_to_device: If this is set to true, the baudrate will be saved on the device
|
||||
// and will persist through a power cycle
|
||||
print("\tSetting HSCAN Baudrate... ", .{});
|
||||
const save_to_device: bool = false;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_baudrate_set(device, ics.icsneoc2_netid_hscan, baudrate, save_to_device),
|
||||
"\tFailed to set baudrate",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("OK\n", .{});
|
||||
// Set FDbaudrates for HSCAN
|
||||
print("\tSetting FD HSCAN Baudrate... ", .{});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_canfd_baudrate_set(device, ics.icsneoc2_netid_hscan, baudrate, save_to_device),
|
||||
"\tFailed to set FD baudrate",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("OK\n", .{});
|
||||
// Get RTC
|
||||
print("\tGetting RTC... ", .{});
|
||||
var unix_epoch: c.time_t = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_rtc_get(device, &unix_epoch),
|
||||
"\tFailed to get RTC",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print_rtc(unix_epoch);
|
||||
// Set RTC
|
||||
print("\tSetting RTC to current time... ", .{});
|
||||
const current_time: i64 = c.time(0);
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_rtc_set(device, current_time),
|
||||
"\tFailed to set RTC",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("OK\n", .{});
|
||||
// Get RTC
|
||||
print("\tGetting RTC... ", .{});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_rtc_get(device, &unix_epoch),
|
||||
"\tFailed to get RTC",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print_rtc(unix_epoch);
|
||||
// Go online, start acking traffic
|
||||
print("\tGoing online... ", .{});
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_go_online(device, true),
|
||||
"\tFailed to go online",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
// Redundant check to show how to check if the device is online, if the previous
|
||||
// icsneoc2_device_go_online call was successful we can assume we are online already
|
||||
var is_online: bool = false;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_is_online(device, &is_online),
|
||||
"\tFailed to check if online",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
print("{s}\n", .{if (is_online) "Online" else "Offline"});
|
||||
// Transmit CAN messages
|
||||
if (!transmit_can_messages(device)) {
|
||||
return;
|
||||
}
|
||||
// Wait for the bus to collect some messages, requires an active bus to get messages
|
||||
print("\tWaiting 1 second for messages...\n", .{});
|
||||
std.time.sleep(std.time.ns_per_s);
|
||||
// Get the messages
|
||||
var messages: [20000]?*ics.icsneoc2_message_t = [_]?*ics.icsneoc2_message_t{null} ** 20000;
|
||||
var messages_count: u32 = 20000;
|
||||
const res = ics.icsneoc2_device_messages_get(device, &messages, &messages_count, 3000);
|
||||
if (!check_error(
|
||||
res,
|
||||
"\tFailed to get messages on device",
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
// Process the messages
|
||||
if (!process_messages(device, messages[0..messages_count])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_error(error_code: ics.icsneoc2_error_t, error_msg: []const u8) bool {
|
||||
if (error_code == ics.icsneoc2_error_success) {
|
||||
return true;
|
||||
}
|
||||
var error_str: [256]u8 = [_:0]u8{0} ** 256;
|
||||
var error_length: u32 = 256;
|
||||
const res: ics.icsneoc2_error_t = ics.icsneoc2_error_code_get(
|
||||
error_code,
|
||||
&error_str,
|
||||
&error_length,
|
||||
);
|
||||
if (res != ics.icsneoc2_error_success) {
|
||||
print(
|
||||
"{s}: Failed to get string for error code {d} with error code {d}\n",
|
||||
.{ error_msg, error_code, res },
|
||||
);
|
||||
return false;
|
||||
}
|
||||
print(
|
||||
"{s}: \"{s}\" ({d})\n",
|
||||
.{ error_msg, error_str, error_code },
|
||||
);
|
||||
return error_code == ics.icsneoc2_error_success;
|
||||
}
|
||||
|
||||
pub fn print_rtc(unix_epoch: c.time_t) void {
|
||||
var rtc_time: [32]u8 = [_:0]u8{0} ** 32;
|
||||
_ = c.strftime(&rtc_time, rtc_time.len, "%Y-%m-%d %H:%M:%S", c.localtime(&unix_epoch));
|
||||
print("{d} {s}\n", .{ unix_epoch, rtc_time });
|
||||
}
|
||||
|
||||
pub fn transmit_can_messages(device: ?*ics.icsneoc2_device_t) bool {
|
||||
const msg_count: usize = 100;
|
||||
print("\tTransmitting {} messages...\n", .{msg_count});
|
||||
for (0..msg_count) |counter| {
|
||||
// Create the message
|
||||
var message: ?*ics.icsneoc2_message_t = null;
|
||||
var message_count: u32 = 1;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_message_can_create(device, &message, message_count),
|
||||
"\tFailed to create CAN message",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
defer {
|
||||
_ = check_error(
|
||||
ics.icsneoc2_message_can_free(device, message),
|
||||
"\tFailed to free CAN message",
|
||||
);
|
||||
}
|
||||
// Set the message attributes
|
||||
var res: ics.icsneoc2_error_t = ics.icsneoc2_message_netid_set(device, message, ics.icsneoc2_netid_hscan);
|
||||
res += ics.icsneoc2_message_can_arbid_set(device, message, 0x10);
|
||||
res += ics.icsneoc2_message_can_canfd_set(device, message, true);
|
||||
res += ics.icsneoc2_message_can_extended_set(device, message, true);
|
||||
res += ics.icsneoc2_message_can_baudrate_switch_set(device, message, true);
|
||||
// Create the payload
|
||||
var data: [8]u8 = .{
|
||||
@intCast(counter >> 56),
|
||||
@intCast(counter >> 48),
|
||||
@intCast(counter >> 40),
|
||||
@intCast(counter >> 32),
|
||||
@intCast(counter >> 24),
|
||||
@intCast(counter >> 16),
|
||||
@intCast(counter >> 8),
|
||||
@intCast(counter >> 0),
|
||||
};
|
||||
res += ics.icsneoc2_message_data_set(device, message, &data, data.len);
|
||||
res += ics.icsneoc2_message_can_dlc_set(device, message, -1);
|
||||
if (!check_error(res, "\tFailed to set CAN Message attributes!")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_messages_transmit(device, &message, &message_count),
|
||||
"\tFailed to transmit message",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn process_messages(device: ?*ics.icsneoc2_device_t, messages: []const ?*ics.icsneoc2_message_t) bool {
|
||||
var tx_count: usize = 0;
|
||||
for (messages, 0..) |message, i| {
|
||||
// Get the message type
|
||||
var msg_type: ics.icsneoc2_msg_type_t = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_message_type_get(device, message.?, &msg_type),
|
||||
"\tFailed to get message type",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
// Get the message type name
|
||||
var msg_type_name: [128]u8 = [_:0]u8{0} ** 128;
|
||||
var msg_type_name_length: u32 = 128;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_message_type_name_get(msg_type, &msg_type_name, &msg_type_name_length),
|
||||
"\tFailed to get message type name",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
// Check if the message is a bus message, ignore otherwise
|
||||
if (msg_type != ics.icsneoc2_msg_type_bus) {
|
||||
print("\tIgnoring message type: {d} ({s})\n", .{ msg_type, msg_type_name });
|
||||
continue;
|
||||
}
|
||||
// Get the message bus type
|
||||
var msg_bus_type: ics.icsneoc2_msg_bus_type_t = 0;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_message_bus_type_get(device, message, &msg_bus_type),
|
||||
"\tFailed to get message bus type",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
// Get the message type name
|
||||
var msg_bus_type_name: [128]u8 = [_:0]u8{0} ** 128;
|
||||
var msg_bus_type_name_length: u32 = 128;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_bus_type_name_get(msg_bus_type, &msg_bus_type_name, &msg_bus_type_name_length),
|
||||
"\tFailed to get message bus type name",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
// Check if message is a transmit message
|
||||
var is_tx: bool = false;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_message_is_transmit(device, message, &is_tx),
|
||||
"\tFailed to get message is transmit",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
if (is_tx) {
|
||||
tx_count += 1;
|
||||
continue;
|
||||
}
|
||||
print("\t{d} Message type: {d} bus type: {s} ({d})\n", .{ i, msg_type, msg_bus_type_name, msg_bus_type });
|
||||
// Check if the message is a CAN message, ignore otherwise
|
||||
if (msg_bus_type == ics.icsneoc2_msg_bus_type_can) {
|
||||
var arbid: u32 = 0;
|
||||
var dlc: i32 = 0;
|
||||
var netid: ics.icsneoc2_netid_t = 0;
|
||||
var is_remote: bool = false;
|
||||
var is_canfd: bool = false;
|
||||
var is_extended: bool = false;
|
||||
var data: [64]u8 = [_]u8{0} ** 64;
|
||||
var data_length: u32 = 64;
|
||||
var netid_name: [128]u8 = [_:0]u8{0} ** 128;
|
||||
var netid_name_length: u32 = 128;
|
||||
var res: ics.icsneoc2_error_t = ics.icsneoc2_error_success;
|
||||
res = ics.icsneoc2_message_netid_get(device, message, &netid);
|
||||
res += ics.icsneoc2_netid_name_get(netid, &netid_name, &netid_name_length);
|
||||
res += ics.icsneoc2_message_can_arbid_get(device, message, &arbid);
|
||||
res += ics.icsneoc2_message_can_dlc_get(device, message, &dlc);
|
||||
res += ics.icsneoc2_message_can_is_remote(device, message, &is_remote);
|
||||
res += ics.icsneoc2_message_can_is_canfd(device, message, &is_canfd);
|
||||
res += ics.icsneoc2_message_can_is_extended(device, message, &is_extended);
|
||||
res += ics.icsneoc2_message_data_get(device, message, &data, &data_length);
|
||||
// We really should check the error message for all of these since we can't tell the exact error if something
|
||||
// bad happens but for an example this should be okay.
|
||||
if (res != ics.icsneoc2_error_success) {
|
||||
print("\tFailed to get CAN parameters (error: {d}) for index {d}\n", .{ res, i });
|
||||
continue;
|
||||
}
|
||||
// Finally lets print the RX message
|
||||
print("\t NetID: {s} (0x{X})\tArbID: 0x{X}\t DLC: {d}\t Remote: {}\t CANFD: {}\t Extended: {}\t Data length: {d}\n", .{ netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length });
|
||||
print("\t Data: {any}\n", .{data[0..data_length]});
|
||||
} else {
|
||||
print("\tIgnoring bus message type: {d} ({s})\n", .{ msg_bus_type, msg_bus_type_name });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
print("\tReceived {d} messages total, {d} were TX messages\n", .{ messages.len, tx_count });
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn print_device_events(device: ?*ics.icsneoc2_device_t) bool {
|
||||
// Get device events
|
||||
var events: [1024]?*ics.icsneoc2_event_t = [_]?*ics.icsneoc2_event_t{null} ** 1024;
|
||||
var events_count: u32 = 1024;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_device_events_get(device, &events, &events_count),
|
||||
"\tFailed to get device events",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
for (events[0..events_count], 0..) |event, i| {
|
||||
var event_description: [256]u8 = [_:0]u8{0} ** 256;
|
||||
var event_description_length: u32 = 256;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_event_description_get(event, &event_description, &event_description_length),
|
||||
"\tFailed to get event description",
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
print("\tEvent {d}: {s}\n", .{ i, event_description });
|
||||
}
|
||||
// Get global events
|
||||
var global_events: [1024]?*ics.icsneoc2_event_t = [_]?*ics.icsneoc2_event_t{null} ** 1024;
|
||||
var global_events_count: u32 = 1024;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_events_get(&global_events, &global_events_count),
|
||||
"\tFailed to get device global events",
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
for (global_events[0..global_events_count], 0..) |event, i| {
|
||||
var event_description: [256]u8 = [_:0]u8{0} ** 256;
|
||||
var event_description_length: u32 = 256;
|
||||
if (!check_error(
|
||||
ics.icsneoc2_event_description_get(event, &event_description, &event_description_length),
|
||||
"\tFailed to get event description",
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
print("\tGlobal event {d}: {s}\n", .{ i, event_description });
|
||||
}
|
||||
print("\tReceived {d} events and {d} global events\n", .{ events_count, global_events_count });
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user