C2: Add message timestamp support

pull/86/head
David Rebbe 2026-05-15 02:16:41 +00:00 committed by Kyle Schwarz
parent 00b7b4a6de
commit eded388b83
8 changed files with 94 additions and 4 deletions

View File

@ -126,6 +126,28 @@ icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t*
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_message_timestamp_set(icsneoc2_message_t* message, uint64_t timestamp) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
if(!message->message) {
return icsneoc2_error_invalid_message;
}
message->message->timestamp = timestamp;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_timestamp_get(icsneoc2_message_t* message, uint64_t* timestamp) {
if(!message || !timestamp) {
return icsneoc2_error_invalid_parameters;
}
if(!message->message) {
return icsneoc2_error_invalid_message;
}
*timestamp = message->message->timestamp;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) { icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) {
if(!message) { if(!message) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;

View File

@ -68,6 +68,7 @@ void print_mac(const char* label, const uint8_t* mac) {
int process_ethernet_message(icsneoc2_message_t* message, size_t index) { int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
uint64_t timestamp = 0;
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
@ -79,6 +80,10 @@ int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get netid name", res); return print_error_code("\tFailed to get netid name", res);
} }
res = icsneoc2_message_timestamp_get(message, &timestamp);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get timestamp", res);
}
/* Get data length first */ /* Get data length first */
size_t data_length = 0; size_t data_length = 0;
@ -88,6 +93,7 @@ int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
} }
printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length); printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length);
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
/* Get MAC addresses and EtherType if we have enough data */ /* Get MAC addresses and EtherType if we have enough data */
uint8_t dst_mac[6] = {0}; uint8_t dst_mac[6] = {0};

View File

@ -86,6 +86,8 @@ void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
icsneoc2_message_netid_get(messages[i], &netid); icsneoc2_message_netid_get(messages[i], &netid);
uint64_t timestamp = 0;
icsneoc2_message_timestamp_get(messages[i], &timestamp);
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
@ -98,6 +100,7 @@ void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
icsneoc2_message_lin_err_flags_get(messages[i], &err_flags); 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("\t%s RX | ID: 0x%02x | Protected ID: 0x%02x\n", netid_name, id, protected_id);
printf("\tTimestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
printf("\tData: ["); printf("\tData: [");
for(size_t x = 0; x < data_length; x++) { for(size_t x = 0; x < data_length; x++) {
printf(" 0x%02x", data[x]); printf(" 0x%02x", data[x]);

View File

@ -244,6 +244,7 @@ int process_message(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) {
uint64_t timestamp = 0;
uint64_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;
@ -256,6 +257,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
bool is_tx = 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_timestamp_get(message, &timestamp);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); 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_transmit(message, &is_tx);
@ -276,6 +278,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
dlc = (int32_t)data_length; dlc = (int32_t)data_length;
printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : ""); printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : "");
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
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 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", printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "", is_remote ? " RTR" : "",

View File

@ -426,6 +426,7 @@ 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) {
uint64_t timestamp = 0;
uint64_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;
@ -436,6 +437,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
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_timestamp_get(message, &timestamp);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); 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) {
@ -452,6 +454,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0; bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length; dlc = (int32_t)data_length;
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
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 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", printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "", is_remote ? " RTR" : "",

View File

@ -468,6 +468,7 @@ static int message_matches_loopback_frame(icsneoc2_message_t* message, const uin
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) { static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
uint64_t timestamp = 0;
char netid_name[64] = {0}; char netid_name[64] = {0};
uint8_t dst_mac[6] = {0}; uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0}; uint8_t src_mac[6] = {0};
@ -483,11 +484,14 @@ static int print_ethernet_message(icsneoc2_message_t* message, const char* direc
res = icsneoc2_message_netid_get(message, &netid); res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message netid", res); 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; if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) return 1;
res = icsneoc2_message_timestamp_get(message, &timestamp);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message timestamp", res);
res = icsneoc2_message_data_get(message, data, &data_length); res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) return print_error_code("Failed to get Ethernet data", res); 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); printf("%s on %s: %zu bytes\n", direction_label, netid_name, data_length);
printf(" Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac); res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) { if(res == icsneoc2_error_success) {
@ -640,4 +644,4 @@ static int poll_for_loopback_messages(icsneoc2_device_t* device,
printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name); printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name);
return 0; return 0;
} }

View File

@ -118,9 +118,33 @@ icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_message_t* message, uint8_t*
* *
* @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 otherwise.
*/ */
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 /**
* Set the timestamp of a message.
*
* Timestamps are in nanoseconds since 2007-01-01 UTC.
*
* @param[in] message The message to modify.
* @param[in] timestamp The timestamp value to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_message otherwise.
*/
icsneoc2_error_t icsneoc2_message_timestamp_set(icsneoc2_message_t* message, uint64_t timestamp);
/**
* Get the timestamp of a message.
*
* Timestamps are in nanoseconds since 2007-01-01 UTC.
*
* @param[in] message The message to check.
* @param[out] timestamp Pointer to a uint64_t to copy the timestamp into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_message otherwise.
*/
icsneoc2_error_t icsneoc2_message_timestamp_get(icsneoc2_message_t* message, uint64_t* timestamp);
#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)

View File

@ -161,6 +161,8 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_data_get(NULL, NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_data_get(NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_data_set(NULL, NULL, 0)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_data_set(NULL, NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_timestamp_get(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_timestamp_set(NULL, 0));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_netid_get(NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_netid_get(NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_netid_set(NULL, 0)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_netid_set(NULL, 0));
@ -1152,6 +1154,29 @@ TEST(icsneoc2, test_icsneoc2_message_can_props_get_can_tx_flags)
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR); ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR);
} }
TEST(icsneoc2, test_icsneoc2_message_timestamp_accessors)
{
icsneoc2_message_t* message = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_create(&message));
uint64_t timestamp = 1;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_timestamp_get(message, &timestamp));
ASSERT_EQ(0u, timestamp);
const uint64_t expected_timestamp = 1234567890123ULL;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_timestamp_set(message, expected_timestamp));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_timestamp_get(message, &timestamp));
ASSERT_EQ(expected_timestamp, timestamp);
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_timestamp_get(message, nullptr));
icsneoc2_message_free(message);
icsneoc2_message_t invalid_message;
ASSERT_EQ(icsneoc2_error_invalid_message, icsneoc2_message_timestamp_set(&invalid_message, expected_timestamp));
ASSERT_EQ(icsneoc2_error_invalid_message, icsneoc2_message_timestamp_get(&invalid_message, &timestamp));
}
TEST(icsneoc2, test_icsneoc2_message_can_error_props_get_invalid_type_for_can_message) TEST(icsneoc2, test_icsneoc2_message_can_error_props_get_invalid_type_for_can_message)
{ {
icsneoc2_message_t message; icsneoc2_message_t message;