ISO-TP (ISO 15765-2) Support Library in C ================================ This is a platform agnostic C library that implements the ISO 15765-2 (also known as ISO-TP) protocol, which runs over a CAN bus. Quoting Wikipedia: >ISO 15765-2, or ISO-TP, is an international standard for sending data packets >over a CAN-Bus. The protocol allows for the transport of messages that exceed >the eight byte maximum payload of CAN frames. ISO-TP segments longer messages >into multiple frames, adding metadata that allows the interpretation of >individual frames and reassembly into a complete message packet by the >recipient. It can carry up to 4095 bytes of payload per message packet. This library doesn't assume anything about the source of the ISO-TP messages or the underlying interface to CAN. It uses dependency injection to give you complete control. The current version supports *only single frame ISO-TP messages*. This is fine for OBD-II diagnostic messages, for example, but this library needs some additional work before it can support sending larger messages. ## Usage First, create some shim functions to let this library use your lower level system: // required, this must send a single CAN message with the given arbitration // ID (i.e. the CAN message ID) and data. The size will never be more than 8 // bytes. void send_can(const uint16_t arbitration_id, const uint8_t* data, const uint8_t size) { ... } // optional, provide to receive debugging log messages void debug(const char* format, ...) { ... } // not used in the current version void set_timer(uint16_t time_ms, void (*callback)) { ... } With your shims in place, create an IsoTpShims object to pass them around: IsoTpShims shims = isotp_init_shims(debug, send_can, set_timer); ### API With your shims in hand, send an ISO-TP message: // Optional: This is your callback that will be called when the message is // completely sent. If it was single frame (the only type supported right // now), this will be called immediately. void message_sent(const IsoTpMessage* message, const bool success) { // You received the message! Do something with it. } IsoTpSendHandle message = isotp_new_send_message(0x100, data, size); IsoTpSendHandle handle = isotp_send(&shims, &message, 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 // this will return true when the message is completely sent (which // may take more than one call if it was multi frame and we're waiting // on flow control responses from the receiver) if(can_get_frame(&af, &data, &size)) { if(!isotp_receive_flowcontrol(&shims, &handle, af, data, size)) { // Process error } while(handle.to_send != 0) { if(!isotp_continue_send(&shims, &handle)) { // Process error } if(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: // Optional: This is your callback for when a complete ISO-TP message is // received at the arbitration ID you specify. The completed message is // also returned by isotp_continue_receive, which can sometimes be more // useful since you have more context. void message_received(const IsoTpMessage* message) { } IsoTpReceiveHandle 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 IsoTpMessage message = isotp_continue_receive(&shims, &handle, 0x100, data, size); if(message.completed && 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. } } } } ## Testing The library includes a test suite that uses the `check` C unit test library. $ make test You can also see the test coverage if you have `lcov` installed and the `BROWSER` environment variable set to your choice of web browsers: $ BROWSER=google-chrome-stable make coverage ## Authors * Chris Peplin cpeplin@ford.com * David Boll dboll2@ford.com (the inspiration for the library's API is from David) ## License Copyright (c) 2013 Ford Motor Company Licensed under the BSD license.