├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.mkd ├── isotp.c ├── isotp.h ├── isotp_config.h ├── isotp_defines.h ├── isotp_user.h └── vars.mk /.gitignore: -------------------------------------------------------------------------------- 1 | ### 2 | # .GITIGNORE FILE 3 | # This file contains instructions for filesystem entries git should ignore when 4 | # doing things to this repository. 5 | ### 6 | 7 | ### 8 | # Ignore Artifacts 9 | ### 10 | *.o 11 | bin/ 12 | 13 | ### 14 | # Ignore Backups 15 | ### 16 | *~ 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | compiler: 3 | - gcc 4 | - g++ 5 | - clang 6 | script: make travis 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | ### 4 | # Project definition 5 | ### 6 | project(isotp LANGUAGES C) 7 | 8 | ### 9 | # Get all include directories 10 | ### 11 | include_directories( 12 | ${CMAKE_CURRENT_SOURCE_DIR}/ 13 | ) 14 | 15 | ### 16 | # Compile isotp as Shared Lib 17 | ### 18 | add_library(isotp SHARED 19 | isotp.c) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Shen Li & Co-Operators 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include vars.mk 2 | 3 | CFLAGS := -Wall -g -ggdb $(STD) 4 | LDFLAGS := -shared 5 | BIN := ./bin 6 | 7 | .PHONY: all clean fPIC no_opt $(BIN)/$(LIB_NAME) $(BIN)/$(LIB_NAME).$(MAJOR_VER) $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION) travis 8 | 9 | ### 10 | # BEGIN TARGETS 11 | ### 12 | 13 | ### 14 | # Builds all library artifacts 15 | ### 16 | all: $(BIN)/$(LIB_NAME) 17 | @printf "########## BUILT $^ ##########\n\n\n" 18 | 19 | fPIC: CFLAGS += "-fPIC" 20 | 21 | travis: fPIC all 22 | 23 | ### 24 | # Builds all targets w/o optimisations enabled 25 | ### 26 | no_opt: CFLAGS += -g -O0 all 27 | 28 | ### 29 | # Removes all build artifacts 30 | ### 31 | clean: 32 | -rm -f *.o $(BIN)/$(LIB_NAME)* 33 | 34 | ### 35 | # Builds all library artifacts, including all symlinks. 36 | ### 37 | $(BIN)/$(LIB_NAME): $(BIN)/$(LIB_NAME).$(MAJOR_VER) 38 | -ln -s $^ $@ 39 | @printf "Linked $^ --> $@...\n" 40 | 41 | ### 42 | # Builds the shared object along with one symlink 43 | ### 44 | $(BIN)/$(LIB_NAME).$(MAJOR_VER): $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION) 45 | -ln -s $^ $@ 46 | @printf "Linked $^ --> $@...\n" 47 | 48 | $(BIN)/$(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION): libisotp.o 49 | if [ ! -d $(BIN) ]; then mkdir $(BIN); fi; 50 | ${COMP} $^ -o $@ ${LDFLAGS} 51 | 52 | ### 53 | # Compiles the isotp.c TU to an object file. 54 | ### 55 | libisotp.o: isotp.c 56 | ${COMP} -c $^ -o $@ ${CFLAGS} 57 | 58 | install: all 59 | @printf "Installing $(LIB_NAME) to $(INSTALL_DIR)...\n" 60 | cp $(BIN)/$(LIB_NAME)* $(INSTALL_DIR) 61 | @printf "Library was installed...\n" 62 | 63 | ### 64 | # END TARGETS 65 | ### 66 | 67 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | ISO-TP (ISO 15765-2) Support Library in C 2 | ================================ 3 | 4 | **This project is inspired by [openxc isotp-c](https://github.com/openxc/isotp-c), but the code has been completely re-written.** 5 | 6 | This is a platform agnostic C library that implements the [ISO 15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) (also known as ISO-TP) protocol, which runs over a CAN bus. Quoting Wikipedia: 7 | 8 | >ISO 15765-2, or ISO-TP, is an international standard for sending data packets over a CAN-Bus. 9 | >The protocol allows for the transport of messages that exceed the eight byte maximum payload of CAN frames. 10 | >ISO-TP segments longer messages into multiple frames, adding metadata that allows the interpretation of individual frames and reassembly 11 | >into a complete message packet by the recipient. It can carry up to 4095 bytes of payload per message packet. 12 | 13 | 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. 14 | 15 | **The current version supports [ISO-15765-2](https://en.wikipedia.org/wiki/ISO_15765-2) single and multiple frame transmition, and works in Full-duplex mode.** 16 | 17 | ## Builds 18 | 19 | ### Master Build 20 | [![Build Status](https://api.travis-ci.com/Beatsleigher/isotp-c.svg?branch=master)](https://travis-ci.com/Beatsleigher/isotp-c) 21 | 22 | ## Usage 23 | 24 | First, create some [shim](https://en.wikipedia.org/wiki/Shim_(computing)) functions to let this library use your lower level system: 25 | 26 | ```C 27 | /* required, this must send a single CAN message with the given arbitration 28 | * ID (i.e. the CAN message ID) and data. The size will never be more than 8 29 | * bytes. */ 30 | int isotp_user_send_can(const uint32_t arbitration_id, 31 | const uint8_t* data, const uint8_t size) { 32 | // ... 33 | } 34 | 35 | /* required, return system tick, unit is millisecond */ 36 | uint32_t isotp_user_get_ms(void) { 37 | // ... 38 | } 39 | 40 | /* optional, provide to receive debugging log messages */ 41 | void isotp_user_debug(const char* message, ...) { 42 | // ... 43 | } 44 | ``` 45 | 46 | ### API 47 | 48 | You can use isotp-c in the following way: 49 | 50 | ```C 51 | /* Alloc IsoTpLink statically in RAM */ 52 | static IsoTpLink g_link; 53 | 54 | /* Alloc send and receive buffer statically in RAM */ 55 | static uint8_t g_isotpRecvBuf[ISOTP_BUFSIZE]; 56 | static uint8_t g_isotpSendBuf[ISOTP_BUFSIZE]; 57 | 58 | int main(void) { 59 | /* Initialize CAN and other peripherals */ 60 | 61 | /* Initialize link, 0x7TT is the CAN ID you send with */ 62 | isotp_init_link(&g_link, 0x7TT, 63 | g_isotpSendBuf, sizeof(g_isotpSendBuf), 64 | g_isotpRecvBuf, sizeof(g_isotpRecvBuf)); 65 | 66 | while(1) { 67 | 68 | /* If receive any interested can message, call isotp_on_can_message to handle message */ 69 | ret = can_receive(&id, &data, &len); 70 | 71 | /* 0x7RR is CAN ID you want to receive */ 72 | if (RET_OK == ret && 0x7RR == id) { 73 | isotp_on_can_message(&g_link, data, len); 74 | } 75 | 76 | /* Poll link to handle multiple frame transmition */ 77 | isotp_poll(&g_link); 78 | 79 | /* You can receive message with isotp_receive. 80 | payload is upper layer message buffer, usually UDS; 81 | payload_size is payload buffer size; 82 | out_size is the actuall read size; 83 | */ 84 | ret = isotp_receive(&g_link, payload, payload_size, &out_size); 85 | if (ISOTP_RET_OK == ret) { 86 | /* Handle received message */ 87 | } 88 | 89 | /* And send message with isotp_send */ 90 | ret = isotp_send(&g_link, payload, payload_size); 91 | if (ISOTP_RET_OK == ret) { 92 | /* Send ok */ 93 | } else { 94 | /* An error occured */ 95 | } 96 | 97 | /* In case you want to send data w/ functional addressing, use isotp_send_with_id */ 98 | ret = isotp_send_with_id(&g_link, 0x7df, payload, payload_size); 99 | if (ISOTP_RET_OK == ret) { 100 | /* Send ok */ 101 | } else { 102 | /* Error occur */ 103 | } 104 | } 105 | 106 | return; 107 | } 108 | ``` 109 | 110 | You can call isotp_poll as frequently as you want, as it internally uses isotp_user_get_ms to measure timeout occurences. 111 | If you need handle functional addressing, you must use two separate links, one for each. 112 | 113 | ```C 114 | /* Alloc IsoTpLink statically in RAM */ 115 | static IsoTpLink g_phylink; 116 | static IsoTpLink g_funclink; 117 | 118 | /* Allocate send and receive buffer statically in RAM */ 119 | static uint8_t g_isotpPhyRecvBuf[512]; 120 | static uint8_t g_isotpPhySendBuf[512]; 121 | /* currently functional addressing is not supported with multi-frame messages */ 122 | static uint8_t g_isotpFuncRecvBuf[8]; 123 | static uint8_t g_isotpFuncSendBuf[8]; 124 | 125 | int main(void) { 126 | /* Initialize CAN and other peripherals */ 127 | 128 | /* Initialize link, 0x7TT is the CAN ID you send with */ 129 | isotp_init_link(&g_phylink, 0x7TT, 130 | g_isotpPhySendBuf, sizeof(g_isotpPhySendBuf), 131 | g_isotpPhyRecvBuf, sizeof(g_isotpPhyRecvBuf)); 132 | isotp_init_link(&g_funclink, 0x7TT, 133 | g_isotpFuncSendBuf, sizeof(g_isotpFuncSendBuf), 134 | g_isotpFuncRecvBuf, sizeof(g_isotpFuncRecvBuf)); 135 | 136 | while(1) { 137 | 138 | /* If any CAN messages are received, which are of interest, call isotp_on_can_message to handle the message */ 139 | ret = can_receive(&id, &data, &len); 140 | 141 | /* 0x7RR is CAN ID you want to receive */ 142 | if (RET_OK == ret) { 143 | if (0x7RR == id) { 144 | isotp_on_can_message(&g_phylink, data, len); 145 | } else if (0x7df == id) { 146 | isotp_on_can_message(&g_funclink, data, len); 147 | } 148 | } 149 | 150 | /* Poll link to handle multiple frame transmition */ 151 | isotp_poll(&g_phylink); 152 | isotp_poll(&g_funclink); 153 | 154 | /* You can receive message with isotp_receive. 155 | payload is upper layer message buffer, usually UDS; 156 | payload_size is payload buffer size; 157 | out_size is the actuall read size; 158 | */ 159 | ret = isotp_receive(&g_phylink, payload, payload_size, &out_size); 160 | if (ISOTP_RET_OK == ret) { 161 | /* Handle physical addressing message */ 162 | } 163 | 164 | ret = isotp_receive(&g_funclink, payload, payload_size, &out_size); 165 | if (ISOTP_RET_OK == ret) { 166 | /* Handle functional addressing message */ 167 | } 168 | 169 | /* And send message with isotp_send */ 170 | ret = isotp_send(&g_phylink, payload, payload_size); 171 | if (ISOTP_RET_OK == ret) { 172 | /* Send ok */ 173 | } else { 174 | /* An error occured */ 175 | } 176 | } 177 | 178 | return; 179 | } 180 | ``` 181 | 182 | ## Authors 183 | 184 | * **shen.li lishen5@gmail.com** (Original author!) 185 | * **Simon Cahill** **s.cahill@grimme.de** (or **simon@h3lix.de**) 186 | 187 | ## License 188 | 189 | Licensed under the MIT license. 190 | -------------------------------------------------------------------------------- /isotp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "assert.h" 3 | #include "isotp.h" 4 | 5 | /////////////////////////////////////////////////////// 6 | /// STATIC FUNCTIONS /// 7 | /////////////////////////////////////////////////////// 8 | 9 | /* st_min to microsecond */ 10 | static uint8_t isotp_ms_to_st_min(uint8_t ms) { 11 | uint8_t st_min; 12 | 13 | st_min = ms; 14 | if (st_min > 0x7F) { 15 | st_min = 0x7F; 16 | } 17 | 18 | return st_min; 19 | } 20 | 21 | /* st_min to msec */ 22 | static uint8_t isotp_st_min_to_ms(uint8_t st_min) { 23 | uint8_t ms; 24 | 25 | if (st_min >= 0xF1 && st_min <= 0xF9) { 26 | ms = 1; 27 | } else if (st_min <= 0x7F) { 28 | ms = st_min; 29 | } else { 30 | ms = 0; 31 | } 32 | 33 | return ms; 34 | } 35 | 36 | static int isotp_send_flow_control(IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint8_t st_min_ms) { 37 | 38 | IsoTpCanMessage message; 39 | int ret; 40 | 41 | /* setup message */ 42 | message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME; 43 | message.as.flow_control.FS = flow_status; 44 | message.as.flow_control.BS = block_size; 45 | message.as.flow_control.STmin = isotp_ms_to_st_min(st_min_ms); 46 | 47 | /* send message */ 48 | #ifdef ISO_TP_FRAME_PADDING 49 | (void) memset(message.as.flow_control.reserve, 0, sizeof(message.as.flow_control.reserve)); 50 | ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message)); 51 | #else 52 | ret = isotp_user_send_can(link->send_arbitration_id, 53 | message.as.data_array.ptr, 54 | 3); 55 | #endif 56 | 57 | return ret; 58 | } 59 | 60 | static int isotp_send_single_frame(IsoTpLink* link, uint32_t id) { 61 | 62 | IsoTpCanMessage message; 63 | int ret; 64 | 65 | /* multi frame message length must greater than 7 */ 66 | assert(link->send_size <= 7); 67 | 68 | /* setup message */ 69 | message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE; 70 | message.as.single_frame.SF_DL = (uint8_t) link->send_size; 71 | (void) memcpy(message.as.single_frame.data, link->send_buffer, link->send_size); 72 | 73 | /* send message */ 74 | #ifdef ISO_TP_FRAME_PADDING 75 | (void) memset(message.as.single_frame.data + link->send_size, 0, sizeof(message.as.single_frame.data) - link->send_size); 76 | ret = isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message)); 77 | #else 78 | ret = isotp_user_send_can(id, 79 | message.as.data_array.ptr, 80 | link->send_size + 1); 81 | #endif 82 | 83 | return ret; 84 | } 85 | 86 | static int isotp_send_first_frame(IsoTpLink* link, uint32_t id) { 87 | 88 | IsoTpCanMessage message; 89 | int ret; 90 | 91 | /* multi frame message length must greater than 7 */ 92 | assert(link->send_size > 7); 93 | 94 | /* setup message */ 95 | message.as.first_frame.type = ISOTP_PCI_TYPE_FIRST_FRAME; 96 | message.as.first_frame.FF_DL_low = (uint8_t) link->send_size; 97 | message.as.first_frame.FF_DL_high = (uint8_t) (0x0F & (link->send_size >> 8)); 98 | (void) memcpy(message.as.first_frame.data, link->send_buffer, sizeof(message.as.first_frame.data)); 99 | 100 | /* send message */ 101 | ret = isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message)); 102 | if (ISOTP_RET_OK == ret) { 103 | link->send_offset += sizeof(message.as.first_frame.data); 104 | link->send_sn = 1; 105 | } 106 | 107 | return ret; 108 | } 109 | 110 | static int isotp_send_consecutive_frame(IsoTpLink* link) { 111 | 112 | IsoTpCanMessage message; 113 | uint16_t data_length; 114 | int ret; 115 | 116 | /* multi frame message length must greater than 7 */ 117 | assert(link->send_size > 7); 118 | 119 | /* setup message */ 120 | message.as.consecutive_frame.type = TSOTP_PCI_TYPE_CONSECUTIVE_FRAME; 121 | message.as.consecutive_frame.SN = link->send_sn; 122 | data_length = link->send_size - link->send_offset; 123 | if (data_length > sizeof(message.as.consecutive_frame.data)) { 124 | data_length = sizeof(message.as.consecutive_frame.data); 125 | } 126 | (void) memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length); 127 | 128 | /* send message */ 129 | #ifdef ISO_TP_FRAME_PADDING 130 | (void) memset(message.as.consecutive_frame.data + data_length, 0, sizeof(message.as.consecutive_frame.data) - data_length); 131 | ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, sizeof(message)); 132 | #else 133 | ret = isotp_user_send_can(link->send_arbitration_id, 134 | message.as.data_array.ptr, 135 | data_length + 1); 136 | #endif 137 | if (ISOTP_RET_OK == ret) { 138 | link->send_offset += data_length; 139 | if (++(link->send_sn) > 0x0F) { 140 | link->send_sn = 0; 141 | } 142 | } 143 | 144 | return ret; 145 | } 146 | 147 | static int isotp_receive_single_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) { 148 | /* check data length */ 149 | if ((0 == message->as.single_frame.SF_DL) || (message->as.single_frame.SF_DL > (len - 1))) { 150 | isotp_user_debug("Single-frame length too small."); 151 | return ISOTP_RET_LENGTH; 152 | } 153 | 154 | /* copying data */ 155 | (void) memcpy(link->receive_buffer, message->as.single_frame.data, message->as.single_frame.SF_DL); 156 | link->receive_size = message->as.single_frame.SF_DL; 157 | 158 | return ISOTP_RET_OK; 159 | } 160 | 161 | static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) { 162 | uint16_t payload_length; 163 | 164 | if (8 != len) { 165 | isotp_user_debug("First frame should be 8 bytes in length."); 166 | return ISOTP_RET_LENGTH; 167 | } 168 | 169 | /* check data length */ 170 | payload_length = message->as.first_frame.FF_DL_high; 171 | payload_length = (payload_length << 8) + message->as.first_frame.FF_DL_low; 172 | 173 | /* should not use multiple frame transmition */ 174 | if (payload_length <= 7) { 175 | isotp_user_debug("Should not use multiple frame transmission."); 176 | return ISOTP_RET_LENGTH; 177 | } 178 | 179 | if (payload_length > link->receive_buf_size) { 180 | isotp_user_debug("Multi-frame response too large for receiving buffer."); 181 | return ISOTP_RET_OVERFLOW; 182 | } 183 | 184 | /* copying data */ 185 | (void) memcpy(link->receive_buffer, message->as.first_frame.data, sizeof(message->as.first_frame.data)); 186 | link->receive_size = payload_length; 187 | link->receive_offset = sizeof(message->as.first_frame.data); 188 | link->receive_sn = 1; 189 | 190 | return ISOTP_RET_OK; 191 | } 192 | 193 | static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) { 194 | uint16_t remaining_bytes; 195 | 196 | /* check sn */ 197 | if (link->receive_sn != message->as.consecutive_frame.SN) { 198 | return ISOTP_RET_WRONG_SN; 199 | } 200 | 201 | /* check data length */ 202 | remaining_bytes = link->receive_size - link->receive_offset; 203 | if (remaining_bytes > sizeof(message->as.consecutive_frame.data)) { 204 | remaining_bytes = sizeof(message->as.consecutive_frame.data); 205 | } 206 | if (remaining_bytes > len - 1) { 207 | isotp_user_debug("Consecutive frame too short."); 208 | return ISOTP_RET_LENGTH; 209 | } 210 | 211 | /* copying data */ 212 | (void) memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes); 213 | 214 | link->receive_offset += remaining_bytes; 215 | if (++(link->receive_sn) > 0x0F) { 216 | link->receive_sn = 0; 217 | } 218 | 219 | return ISOTP_RET_OK; 220 | } 221 | 222 | static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) { 223 | /* check message length */ 224 | if (len < 3) { 225 | isotp_user_debug("Flow control frame too short."); 226 | return ISOTP_RET_LENGTH; 227 | } 228 | 229 | return ISOTP_RET_OK; 230 | } 231 | 232 | /////////////////////////////////////////////////////// 233 | /// PUBLIC FUNCTIONS /// 234 | /////////////////////////////////////////////////////// 235 | 236 | int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size) { 237 | return isotp_send_with_id(link, link->send_arbitration_id, payload, size); 238 | } 239 | 240 | int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size) { 241 | int ret; 242 | 243 | if (link == 0x0) { 244 | isotp_user_debug("Link is null!"); 245 | return ISOTP_RET_ERROR; 246 | } 247 | 248 | if (size > link->send_buf_size) { 249 | isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n"); 250 | char message[128]; 251 | sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size); 252 | return ISOTP_RET_OVERFLOW; 253 | } 254 | 255 | if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) { 256 | isotp_user_debug("Abort previous message, transmission in progress.\n"); 257 | return ISOTP_RET_INPROGRESS; 258 | } 259 | 260 | /* copy into local buffer */ 261 | link->send_size = size; 262 | link->send_offset = 0; 263 | (void) memcpy(link->send_buffer, payload, size); 264 | 265 | if (link->send_size < 8) { 266 | /* send single frame */ 267 | ret = isotp_send_single_frame(link, id); 268 | } else { 269 | /* send multi-frame */ 270 | ret = isotp_send_first_frame(link, id); 271 | 272 | /* init multi-frame control flags */ 273 | if (ISOTP_RET_OK == ret) { 274 | link->send_bs_remain = 0; 275 | link->send_st_min = 0; 276 | link->send_wtf_count = 0; 277 | link->send_timer_st = isotp_user_get_ms(); 278 | link->send_timer_bs = isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT; 279 | link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK; 280 | link->send_status = ISOTP_SEND_STATUS_INPROGRESS; 281 | } 282 | } 283 | 284 | return ret; 285 | } 286 | 287 | void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len) { 288 | IsoTpCanMessage message; 289 | int ret; 290 | 291 | if (len < 2 || len > 8) { 292 | return; 293 | } 294 | 295 | memcpy(message.as.data_array.ptr, data, len); 296 | memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len); 297 | 298 | switch (message.as.common.type) { 299 | case ISOTP_PCI_TYPE_SINGLE: { 300 | /* update protocol result */ 301 | if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) { 302 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU; 303 | } else { 304 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK; 305 | } 306 | 307 | /* handle message */ 308 | ret = isotp_receive_single_frame(link, &message, len); 309 | 310 | if (ISOTP_RET_OK == ret) { 311 | /* change status */ 312 | link->receive_status = ISOTP_RECEIVE_STATUS_FULL; 313 | } 314 | break; 315 | } 316 | case ISOTP_PCI_TYPE_FIRST_FRAME: { 317 | /* update protocol result */ 318 | if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) { 319 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU; 320 | } else { 321 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK; 322 | } 323 | 324 | /* handle message */ 325 | ret = isotp_receive_first_frame(link, &message, len); 326 | 327 | /* if overflow happened */ 328 | if (ISOTP_RET_OVERFLOW == ret) { 329 | /* update protocol result */ 330 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW; 331 | /* change status */ 332 | link->receive_status = ISOTP_RECEIVE_STATUS_IDLE; 333 | /* send error message */ 334 | isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0); 335 | break; 336 | } 337 | 338 | /* if receive successful */ 339 | if (ISOTP_RET_OK == ret) { 340 | /* change status */ 341 | link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS; 342 | /* send fc frame */ 343 | link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE; 344 | isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN); 345 | /* refresh timer cs */ 346 | link->receive_timer_cr = isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT; 347 | } 348 | 349 | break; 350 | } 351 | case TSOTP_PCI_TYPE_CONSECUTIVE_FRAME: { 352 | /* check if in receiving status */ 353 | if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) { 354 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU; 355 | break; 356 | } 357 | 358 | /* handle message */ 359 | ret = isotp_receive_consecutive_frame(link, &message, len); 360 | 361 | /* if wrong sn */ 362 | if (ISOTP_RET_WRONG_SN == ret) { 363 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN; 364 | link->receive_status = ISOTP_RECEIVE_STATUS_IDLE; 365 | break; 366 | } 367 | 368 | /* if success */ 369 | if (ISOTP_RET_OK == ret) { 370 | /* refresh timer cs */ 371 | link->receive_timer_cr = isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT; 372 | 373 | /* receive finished */ 374 | if (link->receive_offset >= link->receive_size) { 375 | link->receive_status = ISOTP_RECEIVE_STATUS_FULL; 376 | } else { 377 | /* send fc when bs reaches limit */ 378 | if (0 == --link->receive_bs_count) { 379 | link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE; 380 | isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN); 381 | } 382 | } 383 | } 384 | 385 | break; 386 | } 387 | case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME: 388 | /* handle fc frame only when sending in progress */ 389 | if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) { 390 | break; 391 | } 392 | 393 | /* handle message */ 394 | ret = isotp_receive_flow_control_frame(link, &message, len); 395 | 396 | if (ISOTP_RET_OK == ret) { 397 | /* refresh bs timer */ 398 | link->send_timer_bs = isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT; 399 | 400 | /* overflow */ 401 | if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) { 402 | link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW; 403 | link->send_status = ISOTP_SEND_STATUS_ERROR; 404 | } 405 | 406 | /* wait */ 407 | else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) { 408 | link->send_wtf_count += 1; 409 | /* wait exceed allowed count */ 410 | if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) { 411 | link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN; 412 | link->send_status = ISOTP_SEND_STATUS_ERROR; 413 | } 414 | } 415 | 416 | /* permit send */ 417 | else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) { 418 | if (0 == message.as.flow_control.BS) { 419 | link->send_bs_remain = ISOTP_INVALID_BS; 420 | } else { 421 | link->send_bs_remain = message.as.flow_control.BS; 422 | } 423 | link->send_st_min = isotp_st_min_to_ms(message.as.flow_control.STmin); 424 | link->send_wtf_count = 0; 425 | } 426 | } 427 | break; 428 | default: 429 | break; 430 | }; 431 | 432 | return; 433 | } 434 | 435 | int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size) { 436 | uint16_t copylen; 437 | 438 | if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) { 439 | return ISOTP_RET_NO_DATA; 440 | } 441 | 442 | copylen = link->receive_size; 443 | if (copylen > payload_size) { 444 | copylen = payload_size; 445 | } 446 | 447 | memcpy(payload, link->receive_buffer, copylen); 448 | *out_size = copylen; 449 | 450 | link->receive_status = ISOTP_RECEIVE_STATUS_IDLE; 451 | 452 | return ISOTP_RET_OK; 453 | } 454 | 455 | void isotp_init_link(IsoTpLink *link, uint32_t sendid, uint8_t *sendbuf, uint16_t sendbufsize, uint8_t *recvbuf, uint16_t recvbufsize) { 456 | memset(link, 0, sizeof(*link)); 457 | link->receive_status = ISOTP_RECEIVE_STATUS_IDLE; 458 | link->send_status = ISOTP_SEND_STATUS_IDLE; 459 | link->send_arbitration_id = sendid; 460 | link->send_buffer = sendbuf; 461 | link->send_buf_size = sendbufsize; 462 | link->receive_buffer = recvbuf; 463 | link->receive_buf_size = recvbufsize; 464 | 465 | return; 466 | } 467 | 468 | void isotp_poll(IsoTpLink *link) { 469 | int ret; 470 | 471 | /* only polling when operation in progress */ 472 | if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) { 473 | 474 | /* continue send data */ 475 | if (/* send data if bs_remain is invalid or bs_remain large than zero */ 476 | (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) && 477 | /* and if st_min is zero or go beyond interval time */ 478 | (0 == link->send_st_min || (0 != link->send_st_min && IsoTpTimeAfter(isotp_user_get_ms(), link->send_timer_st)))) { 479 | 480 | ret = isotp_send_consecutive_frame(link); 481 | if (ISOTP_RET_OK == ret) { 482 | if (ISOTP_INVALID_BS != link->send_bs_remain) { 483 | link->send_bs_remain -= 1; 484 | } 485 | link->send_timer_bs = isotp_user_get_ms() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT; 486 | link->send_timer_st = isotp_user_get_ms() + link->send_st_min; 487 | 488 | /* check if send finish */ 489 | if (link->send_offset >= link->send_size) { 490 | link->send_status = ISOTP_SEND_STATUS_IDLE; 491 | } 492 | } else { 493 | link->send_status = ISOTP_SEND_STATUS_ERROR; 494 | } 495 | } 496 | 497 | /* check timeout */ 498 | if (IsoTpTimeAfter(isotp_user_get_ms(), link->send_timer_bs)) { 499 | link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS; 500 | link->send_status = ISOTP_SEND_STATUS_ERROR; 501 | } 502 | } 503 | 504 | /* only polling when operation in progress */ 505 | if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) { 506 | 507 | /* check timeout */ 508 | if (IsoTpTimeAfter(isotp_user_get_ms(), link->receive_timer_cr)) { 509 | link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR; 510 | link->receive_status = ISOTP_RECEIVE_STATUS_IDLE; 511 | } 512 | } 513 | 514 | return; 515 | } 516 | 517 | -------------------------------------------------------------------------------- /isotp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISOTP_H__ 2 | #define __ISOTP_H__ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | #include 9 | 10 | extern "C" { 11 | #endif 12 | 13 | #include "isotp_defines.h" 14 | #include "isotp_config.h" 15 | #include "isotp_user.h" 16 | 17 | /** 18 | * @brief Struct containing the data for linking an application to a CAN instance. 19 | * The data stored in this struct is used internally and may be used by software programs 20 | * using this library. 21 | */ 22 | typedef struct IsoTpLink { 23 | /* sender paramters */ 24 | uint32_t send_arbitration_id; /* used to reply consecutive frame */ 25 | /* message buffer */ 26 | uint8_t* send_buffer; 27 | uint16_t send_buf_size; 28 | uint16_t send_size; 29 | uint16_t send_offset; 30 | /* multi-frame flags */ 31 | uint8_t send_sn; 32 | uint16_t send_bs_remain; /* Remaining block size */ 33 | uint8_t send_st_min; /* Separation Time between consecutive frames, unit millis */ 34 | uint8_t send_wtf_count; /* Maximum number of FC.Wait frame transmissions */ 35 | uint32_t send_timer_st; /* Last time send consecutive frame */ 36 | uint32_t send_timer_bs; /* Time until reception of the next FlowControl N_PDU 37 | start at sending FF, CF, receive FC 38 | end at receive FC */ 39 | int send_protocol_result; 40 | uint8_t send_status; 41 | 42 | /* receiver paramters */ 43 | uint32_t receive_arbitration_id; 44 | /* message buffer */ 45 | uint8_t* receive_buffer; 46 | uint16_t receive_buf_size; 47 | uint16_t receive_size; 48 | uint16_t receive_offset; 49 | /* multi-frame control */ 50 | uint8_t receive_sn; 51 | uint8_t receive_bs_count; /* Maximum number of FC.Wait frame transmissions */ 52 | uint32_t receive_timer_cr; /* Time until transmission of the next ConsecutiveFrame N_PDU 53 | start at sending FC, receive CF 54 | end at receive FC */ 55 | int receive_protocol_result; 56 | uint8_t receive_status; 57 | } IsoTpLink; 58 | 59 | /** 60 | * @brief Initialises the ISO-TP library. 61 | * 62 | * @param link The @code IsoTpLink @endcode instance used for transceiving data. 63 | * @param sendid The ID used to send data to other CAN nodes. 64 | * @param sendbuf A pointer to an area in memory which can be used as a buffer for data to be sent. 65 | * @param sendbufsize The size of the buffer area. 66 | * @param recvbuf A pointer to an area in memory which can be used as a buffer for data to be received. 67 | * @param recvbufsize The size of the buffer area. 68 | */ 69 | void isotp_init_link(IsoTpLink *link, uint32_t sendid, 70 | uint8_t *sendbuf, uint16_t sendbufsize, 71 | uint8_t *recvbuf, uint16_t recvbufsize); 72 | 73 | /** 74 | * @brief Polling function; call this function periodically to handle timeouts, send consecutive frames, etc. 75 | * 76 | * @param link The @code IsoTpLink @endcode instance used. 77 | */ 78 | void isotp_poll(IsoTpLink *link); 79 | 80 | /** 81 | * @brief Handles incoming CAN messages. 82 | * Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly. 83 | * 84 | * @param link The @code IsoTpLink @endcode instance used for transceiving data. 85 | * @param data The data received via CAN. 86 | * @param len The length of the data received. 87 | */ 88 | void isotp_on_can_message(IsoTpLink *link, uint8_t *data, uint8_t len); 89 | 90 | /** 91 | * @brief Sends ISO-TP frames via CAN, using the ID set in the initialising function. 92 | * 93 | * Single-frame messages will be sent immediately when calling this function. 94 | * Multi-frame messages will be sent consecutively when calling isotp_poll. 95 | * 96 | * @param link The @code IsoTpLink @endcode instance used for transceiving data. 97 | * @param payload The payload to be sent. (Up to 4095 bytes). 98 | * @param size The size of the payload to be sent. 99 | * 100 | * @return Possible return values: 101 | * - @code ISOTP_RET_OVERFLOW @endcode 102 | * - @code ISOTP_RET_INPROGRESS @endcode 103 | * - @code ISOTP_RET_OK @endcode 104 | * - The return value of the user shim function isotp_user_send_can(). 105 | */ 106 | int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size); 107 | 108 | /** 109 | * @brief See @link isotp_send @endlink, with the exception that this function is used only for functional addressing. 110 | */ 111 | int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size); 112 | 113 | /** 114 | * @brief Receives and parses the received data and copies the parsed data in to the internal buffer. 115 | * @param link The @link IsoTpLink @endlink instance used to transceive data. 116 | * @param payload A pointer to an area in memory where the raw data is copied from. 117 | * @param payload_size The size of the received (raw) CAN data. 118 | * @param out_size A reference to a variable which will contain the size of the actual (parsed) data. 119 | * 120 | * @return Possible return values: 121 | * - @link ISOTP_RET_OK @endlink 122 | * - @link ISOTP_RET_NO_DATA @endlink 123 | */ 124 | int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size); 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif // __ISOTP_H__ 131 | 132 | -------------------------------------------------------------------------------- /isotp_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISOTP_CONFIG__ 2 | #define __ISOTP_CONFIG__ 3 | 4 | /* Max number of messages the receiver can receive at one time, this value 5 | * is affectied by can driver queue length 6 | */ 7 | #define ISO_TP_DEFAULT_BLOCK_SIZE 8 8 | 9 | /* The STmin parameter value specifies the minimum time gap allowed between 10 | * the transmission of consecutive frame network protocol data units 11 | */ 12 | #define ISO_TP_DEFAULT_ST_MIN 0 13 | 14 | /* This parameter indicate how many FC N_PDU WTs can be transmitted by the 15 | * receiver in a row. 16 | */ 17 | #define ISO_TP_MAX_WFT_NUMBER 1 18 | 19 | /* Private: The default timeout to use when waiting for a response during a 20 | * multi-frame send or receive. 21 | */ 22 | #define ISO_TP_DEFAULT_RESPONSE_TIMEOUT 100 23 | 24 | /* Private: Determines if by default, padding is added to ISO-TP message frames. 25 | */ 26 | #define ISO_TP_FRAME_PADDING 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /isotp_defines.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISOTP_TYPES__ 2 | #define __ISOTP_TYPES__ 3 | 4 | /************************************************************** 5 | * compiler specific defines 6 | *************************************************************/ 7 | #ifdef __GNUC__ 8 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 9 | #define ISOTP_BYTE_ORDER_LITTLE_ENDIAN 10 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 11 | #else 12 | #error "unsupported byte ordering" 13 | #endif 14 | #endif 15 | 16 | /************************************************************** 17 | * OS specific defines 18 | *************************************************************/ 19 | #ifdef _WIN32 20 | #define snprintf _snprintf 21 | #endif 22 | 23 | #ifdef _WIN32 24 | #define ISOTP_BYTE_ORDER_LITTLE_ENDIAN 25 | #define __builtin_bswap8 _byteswap_uint8 26 | #define __builtin_bswap16 _byteswap_uint16 27 | #define __builtin_bswap32 _byteswap_uint32 28 | #define __builtin_bswap64 _byteswap_uint64 29 | #endif 30 | 31 | /************************************************************** 32 | * internal used defines 33 | *************************************************************/ 34 | #define ISOTP_RET_OK 0 35 | #define ISOTP_RET_ERROR -1 36 | #define ISOTP_RET_INPROGRESS -2 37 | #define ISOTP_RET_OVERFLOW -3 38 | #define ISOTP_RET_WRONG_SN -4 39 | #define ISOTP_RET_NO_DATA -5 40 | #define ISOTP_RET_TIMEOUT -6 41 | #define ISOTP_RET_LENGTH -7 42 | 43 | /* return logic true if 'a' is after 'b' */ 44 | #define IsoTpTimeAfter(a,b) ((int32_t)((int32_t)(b) - (int32_t)(a)) < 0) 45 | 46 | /* invalid bs */ 47 | #define ISOTP_INVALID_BS 0xFFFF 48 | 49 | /* ISOTP sender status */ 50 | typedef enum { 51 | ISOTP_SEND_STATUS_IDLE, 52 | ISOTP_SEND_STATUS_INPROGRESS, 53 | ISOTP_SEND_STATUS_ERROR, 54 | } IsoTpSendStatusTypes; 55 | 56 | /* ISOTP receiver status */ 57 | typedef enum { 58 | ISOTP_RECEIVE_STATUS_IDLE, 59 | ISOTP_RECEIVE_STATUS_INPROGRESS, 60 | ISOTP_RECEIVE_STATUS_FULL, 61 | } IsoTpReceiveStatusTypes; 62 | 63 | /* can fram defination */ 64 | #if defined(ISOTP_BYTE_ORDER_LITTLE_ENDIAN) 65 | typedef struct { 66 | uint8_t reserve_1:4; 67 | uint8_t type:4; 68 | uint8_t reserve_2[7]; 69 | } IsoTpPciType; 70 | 71 | typedef struct { 72 | uint8_t SF_DL:4; 73 | uint8_t type:4; 74 | uint8_t data[7]; 75 | } IsoTpSingleFrame; 76 | 77 | typedef struct { 78 | uint8_t FF_DL_high:4; 79 | uint8_t type:4; 80 | uint8_t FF_DL_low; 81 | uint8_t data[6]; 82 | } IsoTpFirstFrame; 83 | 84 | typedef struct { 85 | uint8_t SN:4; 86 | uint8_t type:4; 87 | uint8_t data[7]; 88 | } IsoTpConsecutiveFrame; 89 | 90 | typedef struct { 91 | uint8_t FS:4; 92 | uint8_t type:4; 93 | uint8_t BS; 94 | uint8_t STmin; 95 | uint8_t reserve[5]; 96 | } IsoTpFlowControl; 97 | 98 | #else 99 | 100 | typedef struct { 101 | uint8_t type:4; 102 | uint8_t reserve_1:4; 103 | uint8_t reserve_2[7]; 104 | } IsoTpPciType; 105 | 106 | /* 107 | * single frame 108 | * +-------------------------+-----+ 109 | * | byte #0 | ... | 110 | * +-------------------------+-----+ 111 | * | nibble #0 | nibble #1 | ... | 112 | * +-------------+-----------+ ... + 113 | * | PCIType = 0 | SF_DL | ... | 114 | * +-------------+-----------+-----+ 115 | */ 116 | typedef struct { 117 | uint8_t type:4; 118 | uint8_t SF_DL:4; 119 | uint8_t data[7]; 120 | } IsoTpSingleFrame; 121 | 122 | /* 123 | * first frame 124 | * +-------------------------+-----------------------+-----+ 125 | * | byte #0 | byte #1 | ... | 126 | * +-------------------------+-----------+-----------+-----+ 127 | * | nibble #0 | nibble #1 | nibble #2 | nibble #3 | ... | 128 | * +-------------+-----------+-----------+-----------+-----+ 129 | * | PCIType = 1 | FF_DL | ... | 130 | * +-------------+-----------+-----------------------+-----+ 131 | */ 132 | typedef struct { 133 | uint8_t type:4; 134 | uint8_t FF_DL_high:4; 135 | uint8_t FF_DL_low; 136 | uint8_t data[6]; 137 | } IsoTpFirstFrame; 138 | 139 | /* 140 | * consecutive frame 141 | * +-------------------------+-----+ 142 | * | byte #0 | ... | 143 | * +-------------------------+-----+ 144 | * | nibble #0 | nibble #1 | ... | 145 | * +-------------+-----------+ ... + 146 | * | PCIType = 0 | SN | ... | 147 | * +-------------+-----------+-----+ 148 | */ 149 | typedef struct { 150 | uint8_t type:4; 151 | uint8_t SN:4; 152 | uint8_t data[7]; 153 | } IsoTpConsecutiveFrame; 154 | 155 | /* 156 | * flow control frame 157 | * +-------------------------+-----------------------+-----------------------+-----+ 158 | * | byte #0 | byte #1 | byte #2 | ... | 159 | * +-------------------------+-----------+-----------+-----------+-----------+-----+ 160 | * | nibble #0 | nibble #1 | nibble #2 | nibble #3 | nibble #4 | nibble #5 | ... | 161 | * +-------------+-----------+-----------+-----------+-----------+-----------+-----+ 162 | * | PCIType = 1 | FS | BS | STmin | ... | 163 | * +-------------+-----------+-----------------------+-----------------------+-----+ 164 | */ 165 | typedef struct { 166 | uint8_t type:4; 167 | uint8_t FS:4; 168 | uint8_t BS; 169 | uint8_t STmin; 170 | uint8_t reserve[5]; 171 | } IsoTpFlowControl; 172 | 173 | #endif 174 | 175 | typedef struct { 176 | uint8_t ptr[8]; 177 | } IsoTpDataArray; 178 | 179 | typedef struct { 180 | union { 181 | IsoTpPciType common; 182 | IsoTpSingleFrame single_frame; 183 | IsoTpFirstFrame first_frame; 184 | IsoTpConsecutiveFrame consecutive_frame; 185 | IsoTpFlowControl flow_control; 186 | IsoTpDataArray data_array; 187 | } as; 188 | } IsoTpCanMessage; 189 | 190 | /************************************************************** 191 | * protocol specific defines 192 | *************************************************************/ 193 | 194 | /* Private: Protocol Control Information (PCI) types, for identifying each frame of an ISO-TP message. 195 | */ 196 | typedef enum { 197 | ISOTP_PCI_TYPE_SINGLE = 0x0, 198 | ISOTP_PCI_TYPE_FIRST_FRAME = 0x1, 199 | TSOTP_PCI_TYPE_CONSECUTIVE_FRAME = 0x2, 200 | ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME = 0x3 201 | } IsoTpProtocolControlInformation; 202 | 203 | /* Private: Protocol Control Information (PCI) flow control identifiers. 204 | */ 205 | typedef enum { 206 | PCI_FLOW_STATUS_CONTINUE = 0x0, 207 | PCI_FLOW_STATUS_WAIT = 0x1, 208 | PCI_FLOW_STATUS_OVERFLOW = 0x2 209 | } IsoTpFlowStatus; 210 | 211 | /* Private: network layer resault code. 212 | */ 213 | #define ISOTP_PROTOCOL_RESULT_OK 0 214 | #define ISOTP_PROTOCOL_RESULT_TIMEOUT_A -1 215 | #define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS -2 216 | #define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR -3 217 | #define ISOTP_PROTOCOL_RESULT_WRONG_SN -4 218 | #define ISOTP_PROTOCOL_RESULT_INVALID_FS -5 219 | #define ISOTP_PROTOCOL_RESULT_UNEXP_PDU -6 220 | #define ISOTP_PROTOCOL_RESULT_WFT_OVRN -7 221 | #define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW -8 222 | #define ISOTP_PROTOCOL_RESULT_ERROR -9 223 | 224 | #endif 225 | 226 | -------------------------------------------------------------------------------- /isotp_user.h: -------------------------------------------------------------------------------- 1 | #ifndef __ISOTP_USER_H__ 2 | #define __ISOTP_USER_H__ 3 | 4 | /* user implemented, print debug message */ 5 | void isotp_user_debug(const char* message, ...); 6 | 7 | /* user implemented, send can message. should return ISOTP_RET_OK when success. 8 | */ 9 | int isotp_user_send_can(const uint32_t arbitration_id, 10 | const uint8_t* data, const uint8_t size); 11 | 12 | /* user implemented, get millisecond */ 13 | uint32_t isotp_user_get_ms(void); 14 | 15 | #endif // __ISOTP_H__ 16 | 17 | -------------------------------------------------------------------------------- /vars.mk: -------------------------------------------------------------------------------- 1 | ### 2 | # CROSS variable 3 | # Use for cross-compilation. 4 | # Uncommenting and setting this variable to the prefix of 5 | # your cross compiler will allow you to cross compile this library. 6 | ### 7 | #CROSS=powerpc-linux-gnu 8 | 9 | ### 10 | # LANG variable 11 | # Set this value according to the language 12 | # you wish to compile against. 13 | # Possible (legal) values: 14 | # - C [c] 15 | # - C++ [c++] 16 | ### 17 | LANG := "C++" 18 | 19 | ### 20 | # STD variables. 21 | # Do NOT set the STD variable. 22 | # Instead, set the C/C++ STD variables 23 | # according to the standard you wish to use. 24 | ### 25 | CSTD := "gnu99" 26 | CPPSTD := "c++0x" 27 | 28 | ### 29 | # OUTPUT_NAME variable. 30 | # This variable contains the name of the output file (the .so). 31 | ### 32 | LIB_NAME := "libisotp.so" 33 | MAJOR_VER := "1" 34 | MINOR_VER := "0" 35 | REVISION := "0" 36 | OUTPUT_NAME := $(LIB_NAME).$(MAJOR_VER).$(MINOR_VER).$(REVISION) 37 | 38 | ### 39 | # INSTALL_DIR variable. 40 | # Set this variable to the location where the lib should be installed. 41 | ### 42 | INSTALL_DIR := /usr/lib 43 | 44 | ### 45 | # Compute compiler and language standard to use 46 | # This section determines which compiler to use. 47 | ### 48 | ifeq ($(LANG), "C++") 49 | STD := "-std=$(CPPSTD)" 50 | ifeq ($(strip $(CROSS)),) 51 | COMP := g++ 52 | else 53 | COMP := $(CROSS)g++ 54 | endif 55 | endif 56 | ifeq ($(LANG), "C") 57 | STD := "-std=$(CSTD)" 58 | ifeq ($(strip $(CROSS)),) 59 | COMP := gcc 60 | else 61 | COMP := $(CROSS)gcc 62 | endif 63 | endif 64 | --------------------------------------------------------------------------------