C2: CAN error message support
parent
f5f6d0828b
commit
9c4323987f
|
|
@ -6,6 +6,7 @@
|
|||
#include "icsneo/icsneocpp.h"
|
||||
#include "icsneo/communication/message/message.h"
|
||||
#include "icsneo/communication/message/canmessage.h"
|
||||
#include "icsneo/communication/message/canerrormessage.h"
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
#include "icsneo/communication/message/ethernetmessage.h"
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
|
|
@ -34,6 +35,19 @@ icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool*
|
|||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value) {
|
||||
if(!message || !value) {
|
||||
return icsneoc2_error_invalid_parameters;
|
||||
}
|
||||
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
|
||||
if(!frame) {
|
||||
return icsneoc2_error_invalid_type;
|
||||
}
|
||||
*value = frame->error;
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc2_netid_t* netid) {
|
||||
if(!message || !netid) {
|
||||
return icsneoc2_error_invalid_parameters;
|
||||
|
|
@ -176,6 +190,15 @@ icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uin
|
|||
if(can_msg->errorStateIndicator) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_ESI;
|
||||
}
|
||||
if(can_msg->txAborted) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED;
|
||||
}
|
||||
if(can_msg->txLostArb) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB;
|
||||
}
|
||||
if(can_msg->txError) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR;
|
||||
}
|
||||
}
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
|
@ -214,7 +237,53 @@ icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_c
|
|||
}
|
||||
*is_can = std::dynamic_pointer_cast<CANMessage>(message->message) != nullptr;
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
icsneoc2_error_t icsneoc2_message_is_can_error(icsneoc2_message_t* message, bool* is_can_error) {
|
||||
if(!message || !is_can_error) {
|
||||
return icsneoc2_error_invalid_parameters;
|
||||
}
|
||||
*is_can_error = std::dynamic_pointer_cast<CANErrorMessage>(message->message) != nullptr;
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
icsneoc2_error_t icsneoc2_message_can_error_props_get(
|
||||
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
|
||||
icsneoc2_can_error_code_t *error_code,
|
||||
icsneoc2_can_error_code_t *data_error_code,
|
||||
icsneoc2_message_can_error_flags_t *flags) {
|
||||
if(!message) {
|
||||
return icsneoc2_error_invalid_parameters;
|
||||
}
|
||||
auto can_err = std::dynamic_pointer_cast<CANErrorMessage>(message->message);
|
||||
if(!can_err) {
|
||||
return icsneoc2_error_invalid_type;
|
||||
}
|
||||
if(tx_err_count) {
|
||||
*tx_err_count = can_err->transmitErrorCount;
|
||||
}
|
||||
if(rx_err_count) {
|
||||
*rx_err_count = can_err->receiveErrorCount;
|
||||
}
|
||||
if(error_code) {
|
||||
*error_code = static_cast<icsneoc2_can_error_code_t>(can_err->errorCode);
|
||||
}
|
||||
if(data_error_code) {
|
||||
*data_error_code = static_cast<icsneoc2_can_error_code_t>(can_err->dataErrorCode);
|
||||
}
|
||||
if(flags) {
|
||||
*flags = 0;
|
||||
if(can_err->busOff) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF;
|
||||
}
|
||||
if(can_err->errorPassive) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE;
|
||||
}
|
||||
if(can_err->errorWarn) {
|
||||
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN;
|
||||
}
|
||||
}
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ void init_canmessage(pybind11::module_& m) {
|
|||
.def_readwrite("isExtended", &CANMessage::isExtended)
|
||||
.def_readwrite("isCANFD", &CANMessage::isCANFD)
|
||||
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
|
||||
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator);
|
||||
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator)
|
||||
.def_readwrite("txAborted", &CANMessage::txAborted)
|
||||
.def_readwrite("txLostArb", &CANMessage::txLostArb)
|
||||
.def_readwrite("txError", &CANMessage::txError);
|
||||
}
|
||||
|
||||
} // namespace icsneo
|
||||
|
|
|
|||
|
|
@ -119,7 +119,12 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
|
|||
}
|
||||
|
||||
msg->transmitted = data->eid.TXMSG;
|
||||
// Set the generic frame error state
|
||||
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
|
||||
// Set specific error states for CANError
|
||||
msg->txAborted = data->eid.TXAborted;
|
||||
msg->txLostArb = data->eid.TXLostArb;
|
||||
msg->txError = data->eid.TXError;
|
||||
msg->description = data->stats;
|
||||
|
||||
return msg;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ int print_error_code(const char* message, icsneoc2_error_t error) {
|
|||
*/
|
||||
int process_message(icsneoc2_message_t** messages, size_t messages_count);
|
||||
|
||||
int transmit_can_messages(icsneoc2_device_t* device);
|
||||
|
||||
int main() {
|
||||
// Open the first available device with default options
|
||||
printf("Opening first available device...\n");
|
||||
|
|
@ -88,6 +90,10 @@ int main() {
|
|||
};
|
||||
printf("\tOpened device: %s\n", description);
|
||||
|
||||
// Transmit messages for debugging purposes
|
||||
// transmit_can_messages(open_device);
|
||||
// sleep_ms(1000);
|
||||
|
||||
// Get the messages
|
||||
icsneoc2_message_t* messages[20000] = {0};
|
||||
size_t message_count = 20000;
|
||||
|
|
@ -169,10 +175,49 @@ void print_events(const char* device_description) {
|
|||
int process_message(icsneoc2_message_t** messages, size_t messages_count) {
|
||||
// Print the type and bus type of each message
|
||||
size_t tx_count = 0;
|
||||
size_t can_error_count = 0;
|
||||
icsneoc2_error_t res = icsneoc2_error_success;
|
||||
for(size_t i = 0; i < messages_count; i++) {
|
||||
icsneoc2_message_t* message = messages[i];
|
||||
|
||||
bool is_can_error = false;
|
||||
res = icsneoc2_message_is_can_error(message, &is_can_error);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to check if message is a CAN error", res);
|
||||
}
|
||||
if(is_can_error) {
|
||||
icsneoc2_network_type_t network_type;
|
||||
uint8_t tec = 0;
|
||||
uint8_t rec = 0;
|
||||
icsneoc2_can_error_code_t error_code = 0;
|
||||
icsneoc2_can_error_code_t data_error_code = 0;
|
||||
icsneoc2_message_can_error_flags_t error_flags = 0;
|
||||
icsneoc2_netid_t netid = 0;
|
||||
char network_type_name[128] = {0};
|
||||
size_t network_type_name_length = 128;
|
||||
char netid_name[128] = {0};
|
||||
size_t netid_name_length = 128;
|
||||
|
||||
res = icsneoc2_message_network_type_get(message, &network_type);
|
||||
res += icsneoc2_network_type_name_get(network_type, network_type_name, &network_type_name_length);
|
||||
res += icsneoc2_message_netid_get(message, &netid);
|
||||
res += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
|
||||
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get CAN error properties", res);
|
||||
}
|
||||
|
||||
printf("\t%zd) CAN Error on %s [%s] (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
|
||||
i, netid_name, network_type_name, netid, tec, rec, error_code, data_error_code,
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
|
||||
can_error_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_frame = false;
|
||||
icsneoc2_error_t res = icsneoc2_message_is_frame(message, &is_frame);
|
||||
res = icsneoc2_message_is_frame(message, &is_frame);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to check if message is a frame", res);
|
||||
}
|
||||
|
|
@ -192,37 +237,55 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
|
|||
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(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%zd) network type: %s (%u)\n", i, network_type_name, network_type);
|
||||
|
||||
if(network_type == icsneoc2_network_type_can) {
|
||||
uint32_t arbid = 0;
|
||||
uint64_t arbid = 0;
|
||||
int32_t dlc = 0;
|
||||
icsneoc2_netid_t netid = 0;
|
||||
bool is_remote = false;
|
||||
bool is_canfd = false;
|
||||
bool is_extended = false;
|
||||
icsneoc2_message_can_flags_t can_flags = 0;
|
||||
uint8_t data[64] = {0};
|
||||
size_t data_length = 64;
|
||||
char netid_name[128] = {0};
|
||||
size_t netid_name_length = 128;
|
||||
bool is_error = false;
|
||||
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_can_props_get(message, &arbid, &can_flags);
|
||||
result += icsneoc2_message_data_get(message, data, &data_length);
|
||||
result += icsneoc2_message_is_transmit(message, &is_tx);
|
||||
result += icsneoc2_message_is_error(message, &is_error);
|
||||
if(result != icsneoc2_error_success) {
|
||||
printf("\tFailed get get CAN parameters (error: %u) for index %zu\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: %zu\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
|
||||
tx_count += is_tx ? 1 : 0;
|
||||
bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
|
||||
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
|
||||
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
|
||||
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
|
||||
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
|
||||
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
|
||||
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
|
||||
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
|
||||
dlc = (int32_t)data_length;
|
||||
|
||||
printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : "");
|
||||
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
|
||||
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
|
||||
is_remote ? " RTR" : "",
|
||||
is_extended ? " IDE" : "",
|
||||
is_canfd ? " FDF" : "",
|
||||
is_brs ? " BRS" : "",
|
||||
is_esi ? " ESI" : "",
|
||||
tx_aborted ? " TX_ABORTED" : "",
|
||||
tx_lost_arb ? " TX_LOST_ARB" : "",
|
||||
tx_error ? " TX_ERROR" : "");
|
||||
printf("\t Data: [");
|
||||
for(size_t x = 0; x < data_length; x++) {
|
||||
printf(" 0x%x", data[x]);
|
||||
|
|
@ -230,14 +293,14 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
|
|||
printf(" ]\n");
|
||||
}
|
||||
}
|
||||
printf("\tReceived %zu messages total, %zu were TX messages\n", messages_count, tx_count);
|
||||
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
||||
int transmit_can_messages(icsneoc2_device_t* device) {
|
||||
uint64_t counter = 0;
|
||||
const size_t msg_count = 100;
|
||||
const size_t msg_count = 10;
|
||||
printf("\tTransmitting %zd messages...\n", msg_count);
|
||||
for(size_t i = 0; i < msg_count; i++) {
|
||||
// Create the message
|
||||
|
|
@ -248,8 +311,12 @@ int transmit_can_messages(icsneoc2_device_t* device) {
|
|||
}
|
||||
// Set the message attributes
|
||||
res = icsneoc2_message_netid_set(message, icsneoc2_netid_dwcan_01);
|
||||
uint64_t arb_id = 0x10;
|
||||
uint64_t flags = 0;
|
||||
res += icsneoc2_message_can_props_set(message, &arb_id, &flags);
|
||||
res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter));
|
||||
if(res != icsneoc2_error_success) {
|
||||
icsneoc2_message_free(message);
|
||||
return print_error_code("\tFailed to modify message", res);
|
||||
}
|
||||
res = icsneoc2_device_message_transmit(device, message);
|
||||
|
|
|
|||
|
|
@ -358,10 +358,42 @@ void print_events(const char* device_description) {
|
|||
int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
|
||||
// Print the type and bus type of each message
|
||||
size_t tx_count = 0;
|
||||
size_t can_error_count = 0;
|
||||
for(size_t i = 0; i < messages_count; i++) {
|
||||
icsneoc2_message_t* message = messages[i];
|
||||
|
||||
// Check for CAN error messages
|
||||
bool is_can_error = false;
|
||||
icsneoc2_error_t res = icsneoc2_message_is_can_error(message, &is_can_error);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to check if message is a CAN error", res);
|
||||
}
|
||||
if(is_can_error) {
|
||||
uint8_t tec = 0;
|
||||
uint8_t rec = 0;
|
||||
icsneoc2_can_error_code_t error_code = 0;
|
||||
icsneoc2_can_error_code_t data_error_code = 0;
|
||||
icsneoc2_message_can_error_flags_t error_flags = 0;
|
||||
icsneoc2_netid_t netid = 0;
|
||||
res = icsneoc2_message_netid_get(message, &netid);
|
||||
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to get CAN error properties", res);
|
||||
}
|
||||
char netid_name[128] = {0};
|
||||
size_t netid_name_length = 128;
|
||||
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
|
||||
printf("\t%zd) CAN Error on %s (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
|
||||
i, netid_name, netid, tec, rec, error_code, data_error_code,
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
|
||||
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
|
||||
can_error_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_frame = false;
|
||||
icsneoc2_error_t res = icsneoc2_message_is_frame(message, &is_frame);
|
||||
res = icsneoc2_message_is_frame(message, &is_frame);
|
||||
if(res != icsneoc2_error_success) {
|
||||
return print_error_code("\tFailed to check if message is a frame", res);
|
||||
}
|
||||
|
|
@ -394,24 +426,42 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
|
|||
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
|
||||
|
||||
if(network_type == icsneoc2_network_type_can) {
|
||||
uint32_t arbid = 0;
|
||||
uint64_t arbid = 0;
|
||||
int32_t dlc = 0;
|
||||
icsneoc2_netid_t netid = 0;
|
||||
bool is_remote = false;
|
||||
bool is_canfd = false;
|
||||
bool is_extended = false;
|
||||
icsneoc2_message_can_flags_t can_flags = 0;
|
||||
uint8_t data[64] = {0};
|
||||
size_t data_length = 64;
|
||||
char netid_name[128] = {0};
|
||||
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_can_props_get(message, &arbid, &can_flags);
|
||||
result += icsneoc2_message_data_get(message, data, &data_length);
|
||||
if(result != icsneoc2_error_success) {
|
||||
printf("\tFailed get get CAN parameters (error: %u) for index %zu\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: %zu\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
|
||||
bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
|
||||
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
|
||||
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
|
||||
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
|
||||
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
|
||||
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
|
||||
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
|
||||
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
|
||||
dlc = (int32_t)data_length;
|
||||
|
||||
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
|
||||
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
|
||||
is_remote ? " RTR" : "",
|
||||
is_extended ? " IDE" : "",
|
||||
is_canfd ? " FDF" : "",
|
||||
is_brs ? " BRS" : "",
|
||||
is_esi ? " ESI" : "",
|
||||
tx_aborted ? " TX_ABORTED" : "",
|
||||
tx_lost_arb ? " TX_LOST_ARB" : "",
|
||||
tx_error ? " TX_ERROR" : "");
|
||||
printf("\t Data: [");
|
||||
for(size_t x = 0; x < data_length; x++) {
|
||||
printf(" 0x%x", data[x]);
|
||||
|
|
@ -419,7 +469,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
|
|||
printf(" ]\n");
|
||||
}
|
||||
}
|
||||
printf("\tReceived %zu messages total, %zu were TX messages\n", messages_count, tx_count);
|
||||
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
|
||||
|
||||
return icsneoc2_error_success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,24 +4,24 @@
|
|||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/communication/message/message.h"
|
||||
#include "icsneo/icsneoc2types.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
enum class CANErrorCode : uint8_t
|
||||
enum class CANErrorCode : icsneoc2_can_error_code_t
|
||||
{
|
||||
NoError = 0,
|
||||
StuffError = 1,
|
||||
FormError = 2,
|
||||
AckError = 3,
|
||||
Bit1Error = 4,
|
||||
Bit0Error = 5,
|
||||
CRCError = 6,
|
||||
NoChange = 7
|
||||
NoError = icsneoc2_can_error_code_no_error,
|
||||
StuffError = icsneoc2_can_error_code_stuff_error,
|
||||
FormError = icsneoc2_can_error_code_form_error,
|
||||
AckError = icsneoc2_can_error_code_ack_error,
|
||||
Bit1Error = icsneoc2_can_error_code_bit1_error,
|
||||
Bit0Error = icsneoc2_can_error_code_bit0_error,
|
||||
CRCError = icsneoc2_can_error_code_crc_error,
|
||||
NoChange = icsneoc2_can_error_code_no_change
|
||||
};
|
||||
class CANErrorMessage : public Message {
|
||||
class CANErrorMessage : public RawMessage {
|
||||
public:
|
||||
CANErrorMessage() : Message(Type::CANError) {}
|
||||
Network network;
|
||||
CANErrorMessage() : RawMessage(Type::CANError) {}
|
||||
uint8_t transmitErrorCount;
|
||||
uint8_t receiveErrorCount;
|
||||
bool busOff;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ public:
|
|||
bool isCANFD = false;
|
||||
bool baudrateSwitch = false; // CAN FD only
|
||||
bool errorStateIndicator = false; // CAN FD only
|
||||
bool txAborted = false;
|
||||
bool txLostArb = false;
|
||||
bool txError = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,17 @@ icsneoc2_error_t icsneoc2_message_free(icsneoc2_message_t* message);
|
|||
*/
|
||||
icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool* value);
|
||||
|
||||
/**
|
||||
* Get the frame error status of a message.
|
||||
*
|
||||
* @param[in] message The message to check.
|
||||
* @param[out] value Pointer to a bool to copy the frame error status into.
|
||||
*
|
||||
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or
|
||||
* icsneoc2_error_invalid_type otherwise.
|
||||
*/
|
||||
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value);
|
||||
|
||||
/**
|
||||
* Get the Network ID (netid) of a bus message
|
||||
*
|
||||
|
|
@ -97,11 +108,14 @@ icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_message_t* message, uint8_t*
|
|||
*/
|
||||
icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length);
|
||||
|
||||
#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)
|
||||
#define ICSNEOC2_MESSAGE_CAN_FLAGS_ESI 0x10 // Error State Indicator (FD only)
|
||||
#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)
|
||||
#define ICSNEOC2_MESSAGE_CAN_FLAGS_ESI 0x10 // Error State Indicator (FD only)
|
||||
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED 0x20 // CAN transmit was aborted
|
||||
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB 0x40 // CAN transmit lost arbitration
|
||||
#define ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR 0x80 // CAN transmit reported an error
|
||||
|
||||
typedef uint64_t icsneoc2_message_can_flags_t;
|
||||
|
||||
|
|
@ -122,6 +136,7 @@ icsneoc2_error_t icsneoc2_message_can_props_set(icsneoc2_message_t* message, con
|
|||
* @param[in] message The message to check.
|
||||
* @param[out] arb_id Pointer to a uint64_t to copy the arbitration ID into. If NULL, it's ignored.
|
||||
* @param[out] flags Pointer to a series of flags. If NULL, it's ignored. See icsneoc2_message_can_flags_t for details.
|
||||
* TX status flags are read-only and are only reported for CAN frames received back from the device.
|
||||
*
|
||||
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
|
||||
*/
|
||||
|
|
@ -316,6 +331,35 @@ icsneoc2_error_t icsneoc2_message_lin_calc_checksum(icsneoc2_message_t* message)
|
|||
*/
|
||||
icsneoc2_error_t icsneoc2_message_network_type_get(icsneoc2_message_t* message, icsneoc2_network_type_t* network_type);
|
||||
|
||||
/**
|
||||
* Check if a message is a CAN error message
|
||||
*
|
||||
* @param[in] message The message to check.
|
||||
* @param[out] is_can_error Pointer to a bool to copy the CAN error status of the message into.
|
||||
*
|
||||
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
|
||||
*/
|
||||
icsneoc2_error_t icsneoc2_message_is_can_error(icsneoc2_message_t* message, bool* is_can_error);
|
||||
|
||||
/**
|
||||
* Get the CAN error specific properties of a message
|
||||
*
|
||||
* @param[in] message The message to check.
|
||||
* @param[out] tx_err_count Pointer to a uint8_t to copy the transmit error count into. If NULL, it's ignored.
|
||||
* @param[out] rx_err_count Pointer to a uint8_t to copy the receive error count into. If NULL, it's ignored.
|
||||
* @param[out] error_code Pointer to a icsneoc2_can_error_code_t to copy the error code into. If NULL, it's ignored.
|
||||
* @param[out] data_error_code Pointer to a icsneoc2_can_error_code_t to copy the data phase error code into. If NULL, it's ignored.
|
||||
* @param[out] flags Pointer to a icsneoc2_message_can_error_flags_t to copy the error flags into. If NULL, it's ignored.
|
||||
* See ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_* for controller-error bits.
|
||||
*
|
||||
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
|
||||
*/
|
||||
icsneoc2_error_t icsneoc2_message_can_error_props_get(
|
||||
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
|
||||
icsneoc2_can_error_code_t *error_code,
|
||||
icsneoc2_can_error_code_t *data_error_code,
|
||||
icsneoc2_message_can_error_flags_t *flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -400,6 +400,28 @@ typedef enum _icsneoc2_memory_type_t {
|
|||
|
||||
typedef uint8_t icsneoc2_memory_type_t;
|
||||
|
||||
typedef enum _icsneoc2_can_error_code_t {
|
||||
icsneoc2_can_error_code_no_error = 0, // No error
|
||||
icsneoc2_can_error_code_stuff_error, // Stuff error
|
||||
icsneoc2_can_error_code_form_error, // Form error
|
||||
icsneoc2_can_error_code_ack_error, // Ack error
|
||||
icsneoc2_can_error_code_bit1_error, // Bit1 error
|
||||
icsneoc2_can_error_code_bit0_error, // Bit0 error
|
||||
icsneoc2_can_error_code_crc_error, // CRC error
|
||||
icsneoc2_can_error_code_no_change, // No change
|
||||
|
||||
// Must be last entry. Don't use as a CAN error code.
|
||||
icsneoc2_can_error_code_maxsize
|
||||
} _icsneoc2_can_error_code_t;
|
||||
|
||||
typedef uint8_t icsneoc2_can_error_code_t;
|
||||
|
||||
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF 0x01 // Bus off state
|
||||
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE 0x02 // Error passive state
|
||||
#define ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN 0x04 // Error warning state
|
||||
|
||||
typedef uint64_t icsneoc2_message_can_error_flags_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@
|
|||
#include <icsneo/icsneoc2.h>
|
||||
#include <icsneo/icsneoc2settings.h>
|
||||
#include <icsneo/icsneoc2messages.h>
|
||||
#include "../../api/icsneoc2/icsneoc2_internal.h"
|
||||
#include <icsneo/device/devicetype.h>
|
||||
#include <icsneo/communication/message/linmessage.h>
|
||||
#include <icsneo/communication/message/canmessage.h>
|
||||
#include <icsneo/communication/message/canerrormessage.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -130,7 +133,10 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
|
|||
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_network_type_get(NULL, NULL));
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_transmit(NULL, NULL));
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_error(NULL, NULL));
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_valid(NULL, NULL));
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_can_error(NULL, NULL));
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_can_error_props_get(NULL, NULL, NULL, NULL, NULL, NULL));
|
||||
|
||||
// LIN message NULL parameter checks
|
||||
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_is_lin(NULL, NULL));
|
||||
|
|
@ -626,6 +632,66 @@ TEST(icsneoc2, test_icsneoc2_open_options_default)
|
|||
ASSERT_EQ(icsneoc2_open_options_default, expected);
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_message_is_error)
|
||||
{
|
||||
icsneoc2_message_t message;
|
||||
message.message = std::make_shared<CANMessage>();
|
||||
|
||||
bool value = false;
|
||||
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_error(&message, &value));
|
||||
ASSERT_FALSE(value);
|
||||
|
||||
auto frame = std::dynamic_pointer_cast<Frame>(message.message);
|
||||
ASSERT_NE(frame, nullptr);
|
||||
frame->error = true;
|
||||
|
||||
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_is_error(&message, &value));
|
||||
ASSERT_TRUE(value);
|
||||
|
||||
icsneoc2_message_t raw_message;
|
||||
raw_message.message = std::make_shared<CANErrorMessage>();
|
||||
ASSERT_EQ(icsneoc2_error_invalid_type, icsneoc2_message_is_error(&raw_message, &value));
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_message_can_props_get_can_tx_flags)
|
||||
{
|
||||
icsneoc2_message_t message;
|
||||
auto can_message = std::make_shared<CANMessage>();
|
||||
message.message = can_message;
|
||||
|
||||
uint64_t arb_id = 0;
|
||||
icsneoc2_message_can_flags_t flags = 0;
|
||||
|
||||
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_props_get(&message, &arb_id, &flags));
|
||||
ASSERT_EQ(arb_id, 0u);
|
||||
ASSERT_EQ(flags, 0u);
|
||||
|
||||
can_message->txAborted = true;
|
||||
can_message->txLostArb = true;
|
||||
can_message->txError = true;
|
||||
|
||||
ASSERT_EQ(icsneoc2_error_success, icsneoc2_message_can_props_get(&message, &arb_id, &flags));
|
||||
ASSERT_EQ(flags,
|
||||
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED |
|
||||
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB |
|
||||
ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR);
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_message_can_error_props_get_invalid_type_for_can_message)
|
||||
{
|
||||
icsneoc2_message_t message;
|
||||
message.message = std::make_shared<CANMessage>();
|
||||
|
||||
uint8_t tx_err_count = 0;
|
||||
uint8_t rx_err_count = 0;
|
||||
icsneoc2_can_error_code_t error_code = icsneoc2_can_error_code_no_error;
|
||||
icsneoc2_can_error_code_t data_error_code = icsneoc2_can_error_code_no_error;
|
||||
icsneoc2_message_can_error_flags_t flags = 0;
|
||||
|
||||
ASSERT_EQ(icsneoc2_error_invalid_type,
|
||||
icsneoc2_message_can_error_props_get(&message, &tx_err_count, &rx_err_count, &error_code, &data_error_code, &flags));
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_disk_format_enums)
|
||||
{
|
||||
// Disk layout enum values
|
||||
|
|
@ -671,6 +737,53 @@ TEST(icsneoc2, test_icsneoc2_memory_type_enums)
|
|||
ASSERT_EQ(1, icsneoc2_memory_type_sd);
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_can_error_code_t)
|
||||
{
|
||||
// CAN error code enum values
|
||||
ASSERT_EQ(icsneoc2_can_error_code_no_error, 0);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_stuff_error, 1);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_form_error, 2);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_ack_error, 3);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_bit1_error, 4);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_bit0_error, 5);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_crc_error, 6);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_no_change, 7);
|
||||
ASSERT_EQ(icsneoc2_can_error_code_maxsize, 8);
|
||||
|
||||
using _T = icsneo::CANErrorCode;
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::NoError), icsneoc2_can_error_code_no_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::StuffError), icsneoc2_can_error_code_stuff_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::FormError), icsneoc2_can_error_code_form_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::AckError), icsneoc2_can_error_code_ack_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::Bit1Error), icsneoc2_can_error_code_bit1_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::Bit0Error), icsneoc2_can_error_code_bit0_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::CRCError), icsneoc2_can_error_code_crc_error);
|
||||
ASSERT_EQ(static_cast<icsneoc2_can_error_code_t>(_T::NoChange), icsneoc2_can_error_code_no_change);
|
||||
|
||||
ASSERT_EQ(sizeof(icsneoc2_can_error_code_t), sizeof(uint8_t));
|
||||
|
||||
// CAN error flag bitmask values
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF, 0x01);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE, 0x02);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN, 0x04);
|
||||
|
||||
ASSERT_EQ(sizeof(icsneoc2_message_can_error_flags_t), sizeof(uint64_t));
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_message_can_flags_t)
|
||||
{
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_RTR, 0x01);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_IDE, 0x02);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_FDF, 0x04);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_BRS, 0x08);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_ESI, 0x10);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED, 0x20);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB, 0x40);
|
||||
ASSERT_EQ(ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR, 0x80);
|
||||
|
||||
ASSERT_EQ(sizeof(icsneoc2_message_can_flags_t), sizeof(uint64_t));
|
||||
}
|
||||
|
||||
TEST(icsneoc2, test_icsneoc2_script_error_codes)
|
||||
{
|
||||
// Verify script error codes exist and have distinct string representations
|
||||
|
|
|
|||
Loading…
Reference in New Issue