diff --git a/api/icsneoc2/icsneoc2messages.cpp b/api/icsneoc2/icsneoc2messages.cpp index fed73a84..d05e63a6 100644 --- a/api/icsneoc2/icsneoc2messages.cpp +++ b/api/icsneoc2/icsneoc2messages.cpp @@ -126,6 +126,28 @@ icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* 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) { if(!message) { return icsneoc2_error_invalid_parameters; diff --git a/examples/c2/ethernet_receive/src/main.c b/examples/c2/ethernet_receive/src/main.c index ffb2f6eb..0527dedd 100644 --- a/examples/c2/ethernet_receive/src/main.c +++ b/examples/c2/ethernet_receive/src/main.c @@ -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) { icsneoc2_netid_t netid = 0; + uint64_t timestamp = 0; char netid_name[128] = {0}; 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) { return print_error_code("\tFailed to get netid name", res); } + res = icsneoc2_message_timestamp_get(message, ×tamp); + if(res != icsneoc2_error_success) { + return print_error_code("\tFailed to get timestamp", res); + } /* Get data length first */ 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 Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp); /* Get MAC addresses and EtherType if we have enough data */ uint8_t dst_mac[6] = {0}; diff --git a/examples/c2/lin/src/main.c b/examples/c2/lin/src/main.c index 94f30a6c..83d51db9 100644 --- a/examples/c2/lin/src/main.c +++ b/examples/c2/lin/src/main.c @@ -86,6 +86,8 @@ void process_lin_messages(icsneoc2_message_t** messages, size_t count) { icsneoc2_netid_t netid = 0; icsneoc2_message_netid_get(messages[i], &netid); + uint64_t timestamp = 0; + icsneoc2_message_timestamp_get(messages[i], ×tamp); char netid_name[128] = {0}; size_t netid_name_length = 128; 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); 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: ["); for(size_t x = 0; x < data_length; x++) { printf(" 0x%02x", data[x]); diff --git a/examples/c2/read_messages/src/main.c b/examples/c2/read_messages/src/main.c index 4fdba3a1..6ef63e01 100644 --- a/examples/c2/read_messages/src/main.c +++ b/examples/c2/read_messages/src/main.c @@ -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); if(network_type == icsneoc2_network_type_can) { + uint64_t timestamp = 0; uint64_t arbid = 0; int32_t dlc = 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; icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); + result += icsneoc2_message_timestamp_get(message, ×tamp); result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); result += icsneoc2_message_data_get(message, data, &data_length); 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; 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 Flags:%s%s%s%s%s%s%s%s\n", is_remote ? " RTR" : "", diff --git a/examples/c2/simple/src/main.c b/examples/c2/simple/src/main.c index abe4e005..7d18ea01 100644 --- a/examples/c2/simple/src/main.c +++ b/examples/c2/simple/src/main.c @@ -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); if(network_type == icsneoc2_network_type_can) { + uint64_t timestamp = 0; uint64_t arbid = 0; int32_t dlc = 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; icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); + result += icsneoc2_message_timestamp_get(message, ×tamp); result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); result += icsneoc2_message_data_get(message, data, &data_length); 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; 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 Flags:%s%s%s%s%s%s%s%s\n", is_remote ? " RTR" : "", diff --git a/examples/c2/t1s_loopback/src/main.c b/examples/c2/t1s_loopback/src/main.c index 39a0fc68..d06ff995 100644 --- a/examples/c2/t1s_loopback/src/main.c +++ b/examples/c2/t1s_loopback/src/main.c @@ -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) { icsneoc2_netid_t netid = 0; + uint64_t timestamp = 0; char netid_name[64] = {0}; uint8_t dst_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); if(res != icsneoc2_error_success) return print_error_code("Failed to get message netid", res); if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) return 1; + res = icsneoc2_message_timestamp_get(message, ×tamp); + if(res != icsneoc2_error_success) return print_error_code("Failed to get message timestamp", res); res = icsneoc2_message_data_get(message, data, &data_length); if(res != icsneoc2_error_success) return print_error_code("Failed to get Ethernet data", res); printf("%s on %s: %zu bytes\n", direction_label, netid_name, data_length); + printf(" Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp); res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac); 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); return 0; -} \ No newline at end of file +} diff --git a/include/icsneo/icsneoc2messages.h b/include/icsneo/icsneoc2messages.h index 4db502b4..8dc6f967 100644 --- a/include/icsneo/icsneoc2messages.h +++ b/include/icsneo/icsneoc2messages.h @@ -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. */ -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 +icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length); + +/** + * 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_FDF 0x04 // FD Format Indicator #define ICSNEOC2_MESSAGE_CAN_FLAGS_BRS 0x08 // Bit Rate Switch (FD only) diff --git a/test/unit/icsneoc2.cpp b/test/unit/icsneoc2.cpp index ed3610eb..fbc4e600 100644 --- a/test/unit/icsneoc2.cpp +++ b/test/unit/icsneoc2.cpp @@ -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_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_set(NULL, 0)); @@ -1152,6 +1154,29 @@ TEST(icsneoc2, test_icsneoc2_message_can_props_get_can_tx_flags) 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, ×tamp)); + 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, ×tamp)); + 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, ×tamp)); +} + TEST(icsneoc2, test_icsneoc2_message_can_error_props_get_invalid_type_for_can_message) { icsneoc2_message_t message;