1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
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 IsoTpShim object to pass them around:
IsoTpShim shims = isotp_init_shims(debug, send_can, set_timer);
### API
With your shims in hand, send an ISO-TP message:
// Optiona: 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.
}
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:
// 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_receive_can_frame, which can sometimes be more
// useful since you have more context.
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
IsoTp message = isotp_receive_can_frame(&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
## License
Copyright (c) 2013 Ford Motor Company
Licensed under the BSD license.
|