Return completion status when receiving CAN frames.

This commit is contained in:
Christopher Peplin 2013-12-31 16:29:07 -05:00
parent 6bbc83bd1d
commit 03c3696d34
6 changed files with 101 additions and 21 deletions

View File

@ -3,14 +3,85 @@ ISO-TP (ISO 15765-2) Support Library in C
## API ## API
IspTpHandler handler = isotp_init(42, NULL, NULL, NULL); First, set up some shim functions to your lower level system:
isotp_send(const uint8_t* payload, uint16_t payload_size);
while(true) {
isotp_handle_can_frame(42, data, 8);
}
isotp_destroy(&handler);
// TODO should handlers take a context? depends on how we want to use this void debug(const char* format, ...) {
...
}
void send_can(const uint16_t arbitration_id, const uint8_t* data,
const uint8_t size) {
...
}
void set_timer(uint16_t time_ms, void (*callback)) {
...
}
Then, set up a callback and send an ISO-TP message:
// this is your callback for when the message is completely sent - it's
// optional
void message_sent(const IsoTpMessage* message, const bool success) {
// You received the message! Do something with it.
}
IsoTpShim shims = isotp_init_shims(debug, send_can, set_timer);
IsoTpHandle handle = isotp_send(&shims, 0x100, NULL, 0, message_sent);
if(handle.completed) {
if(!handle.success) {
// something happened and it already failed - possibly we aren't able to
// send CAN messages
return;
} else {
// If the message fit in a single frame, it's already been sent and
you're done
}
} else {
while(true) {
// Continue to read from CAN, passing off each message to the handle
bool complete = isotp_receive_can_frame(&shims, &handle, 0x100, data, size);
if(complete && handle.completed) {
if(handle.success) {
// All frames of the message have now been sent, following
// whatever flow control feedback it got from the receiver
} else {
// the message was unable to be sent and we bailed - fatal
// error!
}
}
}
}
Finally, receive an ISO-TP message:
// This is your callback for when a complete ISO-TP message is received at
// the arbitration ID you specify
void message_received(const IsoTpMessage* message) {
}
IsoTpHandle handle = isotp_receive(&shims, 0x100, message_received);
if(!handle.success) {
// something happened and it already failed - possibly we aren't able to
// send CAN messages
} else {
while(true) {
// Continue to read from CAN, passing off each message to the handle
bool complete = isotp_receive_can_frame(&shims, &handle, 0x100, data, size);
if(complete && handle.completed) {
if(handle.success) {
// A message has been received successfully
} else {
// Fatal error - we weren't able to receive a message and
// gave up trying. A message using flow control may have
// timed out.
}
}
}
}
// TODO add an optional dispatcher to handle multiple open requests // TODO add an optional dispatcher to handle multiple open requests

View File

@ -33,23 +33,26 @@ void isotp_message_to_string(const IsoTpMessage* message, char* destination,
message->arbitration_id, message->payload); message->arbitration_id, message->payload);
} }
void isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle, bool isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle,
const uint16_t arbitration_id, const uint8_t data[], const uint16_t arbitration_id, const uint8_t data[],
const uint8_t data_length) { const uint8_t data_length) {
bool message_completed = false;
if(data_length < 1) { if(data_length < 1) {
return; return message_completed;
} }
if(handle->type == ISOTP_HANDLE_RECEIVING) { if(handle->type == ISOTP_HANDLE_RECEIVING) {
if(handle->receive_handle.arbitration_id != arbitration_id) { if(handle->receive_handle.arbitration_id != arbitration_id) {
return; return message_completed;
} }
} else if(handle->type == ISOTP_HANDLE_SENDING) { } else if(handle->type == ISOTP_HANDLE_SENDING) {
if(handle->send_handle.receiving_arbitration_id != arbitration_id) { if(handle->send_handle.receiving_arbitration_id != arbitration_id) {
return; return message_completed;
} }
} else { } else {
shims->log("The ISO-TP handle is corrupt"); shims->log("The ISO-TP handle is corrupt");
return message_completed;
} }
IsoTpProtocolControlInformation pci = (IsoTpProtocolControlInformation) IsoTpProtocolControlInformation pci = (IsoTpProtocolControlInformation)
@ -73,11 +76,12 @@ void isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle,
size: payload_length size: payload_length
}; };
isotp_handle_single_frame(handle, &message); message_completed = isotp_handle_single_frame(handle, &message);
break; break;
} }
default: default:
shims->log("Only single frame messages are supported"); shims->log("Only single frame messages are supported");
break; break;
} }
return message_completed;
} }

View File

@ -93,7 +93,13 @@ IsoTpShims isotp_init_shims(LogShim log,
SendCanMessageShim send_can_message, SendCanMessageShim send_can_message,
SetTimerShim set_timer); SetTimerShim set_timer);
void isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle, /* Public:
*
* Returns true if a complete ISO-TP message was sent or received as of
* processing this CAN frame. Check the 'success' and 'completed' flag on the
* handle to make sure.
*/
bool isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle,
const uint16_t arbitration_id, const uint8_t data[], const uint16_t arbitration_id, const uint8_t data[],
const uint8_t size); const uint8_t size);

View File

@ -1,8 +1,8 @@
#include <isotp/receive.h> #include <isotp/receive.h>
void isotp_handle_single_frame(IsoTpHandle* handle, bool isotp_handle_single_frame(IsoTpHandle* handle, IsoTpMessage* message) {
IsoTpMessage* message) {
isotp_complete_receive(handle, message); isotp_complete_receive(handle, message);
return true;
} }
void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message) { void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message) {

View File

@ -11,8 +11,7 @@ extern "C" {
void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message); void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message);
void isotp_handle_single_frame(IsoTpHandle* handle, bool isotp_handle_single_frame(IsoTpHandle* handle, IsoTpMessage* message);
IsoTpMessage* message);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -28,7 +28,7 @@ extern void setup();
START_TEST (test_receive_wrong_id) START_TEST (test_receive_wrong_id)
{ {
const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0}; const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0};
isotp_receive_can_frame(&SHIMS, &HANDLE, 0x100, data, 1); fail_if(isotp_receive_can_frame(&SHIMS, &HANDLE, 0x100, data, 1));
fail_if(message_was_received); fail_if(message_was_received);
} }
END_TEST END_TEST
@ -37,7 +37,7 @@ START_TEST (test_receive_bad_pci)
{ {
// 4 is a reserved number for the PCI field - only 0-3 are allowed // 4 is a reserved number for the PCI field - only 0-3 are allowed
const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x40}; const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x40};
isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 1); fail_if(isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 1));
fail_if(message_was_received); fail_if(message_was_received);
} }
END_TEST END_TEST
@ -45,7 +45,7 @@ END_TEST
START_TEST (test_receive_single_frame_empty_payload) START_TEST (test_receive_single_frame_empty_payload)
{ {
const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x00, 0x12, 0x34}; const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x00, 0x12, 0x34};
isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 3); fail_unless(isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 3));
fail_unless(message_was_received); fail_unless(message_was_received);
ck_assert_int_eq(last_message_received_arb_id, 0x2a); ck_assert_int_eq(last_message_received_arb_id, 0x2a);
ck_assert_int_eq(last_message_received_payload_size, 0); ck_assert_int_eq(last_message_received_payload_size, 0);
@ -55,7 +55,7 @@ END_TEST
START_TEST (test_receive_single_frame) START_TEST (test_receive_single_frame)
{ {
const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x02, 0x12, 0x34}; const uint8_t data[CAN_MESSAGE_BYTE_SIZE] = {0x02, 0x12, 0x34};
isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 3); fail_unless(isotp_receive_can_frame(&SHIMS, &HANDLE, 0x2a, data, 3));
fail_unless(message_was_received); fail_unless(message_was_received);
ck_assert_int_eq(last_message_received_arb_id, 0x2a); ck_assert_int_eq(last_message_received_arb_id, 0x2a);
ck_assert_int_eq(last_message_received_payload_size, 2); ck_assert_int_eq(last_message_received_payload_size, 2);