isotp-c/README.mkd

153 lines
5.5 KiB
Markdown
Raw Permalink Normal View History

2013-12-27 11:02:14 -08:00
ISO-TP (ISO 15765-2) Support Library in C
================================
2014-01-03 10:18:06 -08:00
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:
2013-12-27 11:02:14 -08:00
2014-01-03 10:18:06 -08:00
>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.
2014-01-03 10:18:06 -08:00
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
2014-01-03 10:18:06 -08:00
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) {
...
}
2014-01-03 10:18:06 -08:00
// 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)) {
...
2013-12-27 11:02:14 -08:00
}
With your shims in place, create an IsoTpShims object to pass them around:
2014-01-03 10:18:06 -08:00
IsoTpShims shims = isotp_init_shims(debug, send_can, set_timer);
2014-01-03 10:18:06 -08:00
### API
With your shims in hand, send an ISO-TP message:
2014-01-03 13:38:22 -08:00
// Optional: This is your callback that will be called when the message is
2014-01-03 10:18:06 -08:00
// 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.
}
2017-12-20 10:29:45 -08:00
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 {
2014-01-03 13:38:22 -08:00
// 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)
2017-12-20 10:29:45 -08:00
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:
2014-01-03 10:18:06 -08:00
// 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
2014-01-03 10:18:06 -08:00
// 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.
}
}
}
}
2013-12-27 08:22:56 -08:00
## Testing
The library includes a test suite that uses the `check` C unit test library.
$ make test
2014-01-03 09:45:46 -08:00
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
2013-12-27 08:22:56 -08:00
## Authors
* Chris Peplin cpeplin@ford.com
* David Boll dboll2@ford.com (the inspiration for the library's API is from David)
2013-12-27 08:22:56 -08:00
## License
Copyright (c) 2013 Ford Motor Company
Licensed under the BSD license.