Return completion status when receiving CAN frames.
authorChristopher Peplin <chris.peplin@rhubarbtech.com>
Tue, 31 Dec 2013 21:29:07 +0000 (16:29 -0500)
committerChristopher Peplin <chris.peplin@rhubarbtech.com>
Tue, 31 Dec 2013 21:29:07 +0000 (16:29 -0500)
README.mkd
src/isotp/isotp.c
src/isotp/isotp.h
src/isotp/receive.c
src/isotp/receive.h
tests/test_receive.c

index 2371561..ba09d28 100644 (file)
@@ -3,14 +3,85 @@ ISO-TP (ISO 15765-2) Support Library in C
 
 ## API
 
-    IspTpHandler handler = isotp_init(42, NULL, NULL, NULL);
-    isotp_send(const uint8_t* payload, uint16_t payload_size);
-    while(true) {
-        isotp_handle_can_frame(42, data, 8);
+First, set up some shim functions to your lower level system:
+
+    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)) {
+        ...
     }
-    isotp_destroy(&handler);
 
-// TODO should handlers take a context? depends on how we want to use this
+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
 
index f5b2079..5824312 100644 (file)
@@ -33,23 +33,26 @@ void isotp_message_to_string(const IsoTpMessage* message, char* destination,
             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 uint8_t data_length) {
+    bool message_completed = false;
+
     if(data_length < 1) {
-        return;
+        return message_completed;
     }
 
     if(handle->type == ISOTP_HANDLE_RECEIVING) {
         if(handle->receive_handle.arbitration_id != arbitration_id) {
-            return;
+            return message_completed;
         }
     } else if(handle->type == ISOTP_HANDLE_SENDING) {
         if(handle->send_handle.receiving_arbitration_id != arbitration_id) {
-            return;
+            return message_completed;
         }
     } else {
         shims->log("The ISO-TP handle is corrupt");
+        return message_completed;
     }
 
     IsoTpProtocolControlInformation pci = (IsoTpProtocolControlInformation)
@@ -73,11 +76,12 @@ void isotp_receive_can_frame(IsoTpShims* shims, IsoTpHandle* handle,
                 size: payload_length
             };
 
-            isotp_handle_single_frame(handle, &message);
+            message_completed = isotp_handle_single_frame(handle, &message);
             break;
          }
         default:
             shims->log("Only single frame messages are supported");
             break;
     }
+    return message_completed;
 }
index e3ec588..4f58dac 100644 (file)
@@ -93,7 +93,13 @@ IsoTpShims isotp_init_shims(LogShim log,
         SendCanMessageShim send_can_message,
         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 uint8_t size);
 
index 1d62338..e69c59b 100644 (file)
@@ -1,8 +1,8 @@
 #include <isotp/receive.h>
 
-void isotp_handle_single_frame(IsoTpHandle* handle,
-        IsoTpMessage* message) {
+bool isotp_handle_single_frame(IsoTpHandle* handle, IsoTpMessage* message) {
     isotp_complete_receive(handle, message);
+    return true;
 }
 
 void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message) {
index b7c1796..b01e12d 100644 (file)
@@ -11,8 +11,7 @@ extern "C" {
 
 void isotp_complete_receive(IsoTpHandle* handle, IsoTpMessage* message);
 
-void isotp_handle_single_frame(IsoTpHandle* handle,
-        IsoTpMessage* message);
+bool isotp_handle_single_frame(IsoTpHandle* handle, IsoTpMessage* message);
 
 #ifdef __cplusplus
 }
index 17df904..0559c06 100644 (file)
@@ -28,7 +28,7 @@ extern void setup();
 START_TEST (test_receive_wrong_id)
 {
     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);
 }
 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
     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);
 }
 END_TEST
@@ -45,7 +45,7 @@ END_TEST
 START_TEST (test_receive_single_frame_empty_payload)
 {
     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);
     ck_assert_int_eq(last_message_received_arb_id, 0x2a);
     ck_assert_int_eq(last_message_received_payload_size, 0);
@@ -55,7 +55,7 @@ END_TEST
 START_TEST (test_receive_single_frame)
 {
     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);
     ck_assert_int_eq(last_message_received_arb_id, 0x2a);
     ck_assert_int_eq(last_message_received_payload_size, 2);