Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions esp_isotp/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,4 @@ menu "ISO-TP Protocol"
Value used for padding when ISO_TP_FRAME_PADDING is enabled.
Common values: 0x00, 0xAA, 0xCC, 0xFF.

config ISO_TP_USER_SEND_CAN_ARG
bool "Enable User Send CAN Argument"
default y
help
Determines if an additional argument is present in the
definition of isotp_user_send_can function.

endmenu
76 changes: 59 additions & 17 deletions esp_isotp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,50 @@

[![Component Registry](https://components.espressif.com/components/espressif/esp_isotp/badge.svg)](https://components.espressif.com/components/espressif/esp_isotp)

ISO 15765-2 (ISO-TP) transport protocol implementation for ESP-IDF, enabling reliable transmission of large data payloads (up to 4095 bytes) over TWAI networks with automatic segmentation and reassembly.
ISO 15765-2 (ISO-TP) for ESP-IDF. Sends/receives large payloads (4095 B) over TWAI with segmentation and reassembly.

## Key Features

- **Automatic segmentation** for messages >7 bytes with flow control
- **Non-blocking API** with ISR-based frame processing
- **Multi-instance support** for concurrent communication channels
- **Automotive compliance** (UDS, OBD-II compatible)
- **Robust error handling** with timeout and sequence validation
- Segmentation + flow control for >7 B
- Non-blocking API, ISR-backed
- Multiple links in parallel
- UDS/OBD-II friendly
- Timeouts + sequence checks
- 11-bit and 29-bit IDs

> [!NOTE]
> TWAI-FD (Flexible Data-rate) is not supported in this version.

## Installation

To add this component to your project, run the following command from your project's root directory:

```bash
idf.py add-dependency espressif/esp_isotp
```

## Configuration

Configure ISO-TP protocol parameters:
You can configure protocol parameters like timing through the project configuration menu:

```bash
idf.py menuconfig
# Navigate to: Component config → ISO-TP Protocol Configuration
```

## Quick Start
Navigate to `Component config` → `ISO-TP Protocol Configuration`.

## Quick Start Guide

Here's a simple example that initializes the TWAI driver and an ISO-TP link, then echoes back any received data.

### Example Code

```c
#include "esp_isotp.h"
#include "esp_twai_onchip.h"

void app_main(void) {
// 1. Initialize TWAI
// 1) Init TWAI
twai_onchip_node_config_t twai_cfg = {
.io_cfg = {.tx = GPIO_NUM_5, .rx = GPIO_NUM_4},
.bit_timing = {.bitrate = 500000},
Expand All @@ -46,27 +54,61 @@ void app_main(void) {
twai_node_handle_t twai_node;
ESP_ERROR_CHECK(twai_new_node_onchip(&twai_cfg, &twai_node));

// 2. Create ISO-TP transport
// 2) Create ISO-TP (11-bit IDs, auto-detected)
esp_isotp_config_t config = {
.tx_id = 0x7E0, .rx_id = 0x7E8,
.tx_buffer_size = 4096, .rx_buffer_size = 4096,
.tx_id = 0x7E0, // request ID (11-bit, auto-detected)
.rx_id = 0x7E8, // response ID (11-bit, auto-detected)
.tx_buffer_size = 4096,
.rx_buffer_size = 4096,
};
esp_isotp_handle_t isotp_handle;
ESP_ERROR_CHECK(esp_isotp_new_transport(twai_node, &config, &isotp_handle));

// 3. Communication loop
// 3) Loop
uint8_t buffer[4096];
uint32_t received_size;

while (1) {
esp_isotp_poll(isotp_handle); // CRITICAL: Call every 1-10ms
// This is the engine of the component. Call it frequently!
esp_isotp_poll(isotp_handle);

// Check if a full message has been received
if (esp_isotp_receive(isotp_handle, buffer, sizeof(buffer), &received_size) == ESP_OK) {
printf("Received %lu bytes\n", received_size);
esp_isotp_send(isotp_handle, buffer, received_size); // Echo back
// Echo the message back
esp_isotp_send(isotp_handle, buffer, received_size);
}

vTaskDelay(pdMS_TO_TICKS(5));
vTaskDelay(pdMS_TO_TICKS(5)); // A small delay is good practice
}
}
```

## Extended (29-bit) IDs

- ID format is auto-detected: IDs > 0x7FF use 29-bit extended format, others use 11-bit standard format.
- `tx_id` and `rx_id` must differ and match peer's expected format.

```c
esp_isotp_config_t cfg = {
.tx_id = 0x18DAF110, // 29-bit ID (auto-detected as extended)
.rx_id = 0x18DA10F1, // 29-bit ID (auto-detected as extended)
.tx_buffer_size = 4096,
.rx_buffer_size = 4096,
};
```

## Errors

- Common: ESP_OK, ESP_ERR_INVALID_ARG, ESP_ERR_INVALID_SIZE, ESP_ERR_NO_MEM, ESP_ERR_TIMEOUT
- Send: ESP_ERR_NOT_FINISHED when previous TX in progress
- Receive: ESP_ERR_NOT_FOUND when no complete message; ESP_ERR_INVALID_RESPONSE on bad sequence
- Full list: see `esp_isotp.h`

## Checklist

- IDs valid and different; 11-bit vs 29-bit matches `use_extended_id`
- Buffers > 0; size gates max single-message length (≤4095 B)
- Call `esp_isotp_poll()` every 1–10 ms
- TWAI node created and enabled before use

141 changes: 107 additions & 34 deletions esp_isotp/inc/esp_isotp.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,6 @@
* **Large packets (>7 bytes)**: Split into multiple frames - first frame sent immediately,
* remaining frames sent during esp_isotp_poll() calls.
*
* ## Basic Usage
* ```c
* esp_isotp_handle_t handle;
* esp_isotp_new_transport(twai_node, &config, &handle);
*
* while (1) {
* esp_isotp_poll(handle); // MUST call regularly!
*
* // Send data (non-blocking)
* esp_isotp_send(handle, data, size);
*
* // Check for received data (non-blocking)
* uint16_t received_size;
* if (esp_isotp_receive(handle, buffer, sizeof(buffer), &received_size) == ESP_OK) {
* // Complete message received
* }
*
* vTaskDelay(pdMS_TO_TICKS(5));
* }
* ```
*/

#include "esp_err.h"
Expand All @@ -53,67 +33,155 @@ extern "C" {
*/
typedef struct esp_isotp_link_t *esp_isotp_handle_t;

/**
* @brief ISO-TP receive callback function type
*
* Called when a complete message has been received successfully.
*
* @warning This callback executes in the same context as isotp_on_can_message(),
* which is typically ISR context. Keep callback execution time minimal
* and avoid blocking operations.
* @note The data pointer is only valid during the callback execution.
* Copy data immediately if needed beyond the callback scope.
*
* @param[in] handle ISO-TP handle that received the message
* @param[in] data Pointer to received data (valid only during callback)
* @param[in] size Size of received data in bytes
* @param[in] user_arg User argument provided during configuration
*/
typedef void (*esp_isotp_rx_callback_t)(esp_isotp_handle_t handle, const uint8_t *data, uint32_t size, void *user_arg);

/**
* @brief ISO-TP transmit callback function type
*
* Called when a complete message has been transmitted successfully.
*
* @note Execution context depends on message type:
* - Single-frame: Called immediately from isotp_send() in caller's context
* - Multi-frame: Called from isotp_poll() in task context
* @note Keep callback execution time minimal to avoid affecting system performance.
*
* @param[in] handle ISO-TP handle that transmitted the message
* @param[in] tx_size Size of transmitted data in bytes
* @param[in] user_arg User argument provided during configuration
*/
typedef void (*esp_isotp_tx_callback_t)(esp_isotp_handle_t handle, uint32_t tx_size, void *user_arg);

/**
* @brief Configuration structure for creating a new ISO-TP link
*/
typedef struct {
uint32_t tx_id; /*!< TWAI ID for transmitting ISO-TP frames */
uint32_t rx_id; /*!< TWAI ID for receiving ISO-TP frames */
uint32_t tx_id; /*!< TWAI ID for transmitting ISO-TP frames (11-bit or 29-bit, auto-detected from value) */
uint32_t rx_id; /*!< TWAI ID for receiving ISO-TP frames (11-bit or 29-bit, auto-detected from value) */
uint32_t tx_buffer_size; /*!< Size of the transmit buffer (max message size to send) */
uint32_t rx_buffer_size; /*!< Size of the receive buffer (max message size to receive) */
uint32_t tx_frame_pool_size; /*!< Size of TX frame pool */

esp_isotp_rx_callback_t rx_callback; /*!< Receive completion callback (NULL for polling mode) */
esp_isotp_tx_callback_t tx_callback; /*!< Transmit completion callback (NULL to disable) */
void *callback_arg; /*!< User argument passed to callbacks */
} esp_isotp_config_t;

/**
* @brief Create a new ISO-TP link
* @brief Create a new ISO-TP transport bound to a TWAI node.
*
* Allocates internal buffers, creates TX frame pool, registers TWAI callbacks
* and enables the provided TWAI node.
*
* @param twai_node TWAI node handle
* @param config Pointer to the configuration structure
* @param[out] out_handle Pointer to store the created ISO-TP handle
* @param twai_node TWAI node handle to bind.
* @param config Transport configuration.
* @param[out] out_handle Returned ISO-TP transport handle.
* @return esp_err_t
* - ESP_OK: Success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_NO_MEM: Out of memory
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG for invalid parameters
* - ESP_ERR_INVALID_SIZE for invalid buffer sizes
* - ESP_ERR_NO_MEM when allocation fails
* - Other error codes from TWAI functions
*/
esp_err_t esp_isotp_new_transport(twai_node_handle_t twai_node, const esp_isotp_config_t *config, esp_isotp_handle_t *out_handle);

/**
* @brief Send data over an ISO-TP link (non-blocking)
* @brief Send data over an ISO-TP link (non-blocking, ISR-safe)
*
* Immediately sends first/single frame and returns. For multi-frame messages,
* remaining frames are sent during subsequent esp_isotp_poll() calls.
*
* @note This function is ISR-safe and can be called from interrupt context.
* @note TX completion callback timing:
* - Single-frame: Called immediately from isotp_send()
* - Multi-frame: Called from isotp_poll() when last frame is sent
*
* @param handle ISO-TP handle
* @param data Data to send
* @param size Data length in bytes
* @return
* - ESP_OK: Send initiated successfully
* - ESP_ERR_NOT_FINISHED: Previous send still in progress
* - ESP_ERR_NO_MEM: Data too large for buffer
* - ESP_ERR_NO_MEM: Data too large for buffer or no space available
* - ESP_ERR_INVALID_SIZE: Invalid data size
* - ESP_ERR_TIMEOUT: Send operation timed out
* - ESP_ERR_INVALID_ARG: Invalid parameters
* - ESP_FAIL: Other send errors
*/
esp_err_t esp_isotp_send(esp_isotp_handle_t handle, const uint8_t *data, uint32_t size);

/**
* @brief Extract a complete received message (non-blocking)
* @brief Send data over an ISO-TP link with specified TWAI ID (non-blocking, ISR-safe)
*
* Similar to esp_isotp_send(), but allows specifying a different TWAI ID for transmission.
* This function is primarily used for functional addressing where multiple nodes
* may respond to the same request.
*
* @note This function is ISR-safe and can be called from interrupt context.
* @note TX completion callback timing:
* - Single-frame: Called immediately from isotp_send_with_id()
* - Multi-frame: Called from isotp_poll() when last frame is sent
*
* @param handle ISO-TP handle
* @param id TWAI identifier to use for transmission (overrides configured tx_id)
* @param data Data to send
* @param size Data length in bytes
* @return
* - ESP_OK: Send initiated successfully
* - ESP_ERR_NOT_FINISHED: Previous send still in progress
* - ESP_ERR_NO_MEM: Data too large for buffer or no space available
* - ESP_ERR_INVALID_SIZE: Invalid data size
* - ESP_ERR_TIMEOUT: Send operation timed out
* - ESP_ERR_INVALID_ARG: Invalid parameters or ID exceeds maximum value
* - ESP_FAIL: Other send errors
*/
esp_err_t esp_isotp_send_with_id(esp_isotp_handle_t handle, uint32_t id, const uint8_t *data, uint32_t size);

/**
* @brief Extract a complete received message (non-blocking, task context only)
*
* This function only extracts data that has already been assembled by esp_isotp_poll().
* It does NOT process incoming TWAI frames - that happens in esp_isotp_poll().
*
* Process: TWAI frames → esp_isotp_poll() assembles → esp_isotp_receive() extracts
*
* @warning This function is NOT ISR-safe and must only be called from task context.
* @note When using callback mode (rx_callback != NULL), received messages are
* automatically delivered via callback. This function should only be used
* in polling mode (rx_callback == NULL).
*
* @param handle ISO-TP handle
* @param data Buffer to store received data
* @param size Buffer size in bytes
* @param[out] received_size Actual received data length
* @return
* - ESP_OK: Complete message extracted and internal buffer cleared
* - ESP_ERR_NOT_FOUND: No complete message ready for extraction
* - ESP_ERR_INVALID_SIZE: Receive buffer overflow or invalid size
* - ESP_ERR_INVALID_RESPONSE: Invalid sequence number or protocol error
* - ESP_ERR_TIMEOUT: Receive operation timed out
* - ESP_ERR_INVALID_ARG: Invalid parameters
* - ESP_FAIL: Other receive errors
*/
esp_err_t esp_isotp_receive(esp_isotp_handle_t handle, uint8_t *data, uint32_t size, uint32_t *received_size);

/**
* @brief Poll the ISO-TP link to process messages (CRITICAL - call regularly!)
* @brief Poll the ISO-TP link to process messages (CRITICAL - call regularly, task context only)
*
* This function drives the ISO-TP state machine. Call every 1-10ms for proper operation.
*
Expand All @@ -122,9 +190,13 @@ esp_err_t esp_isotp_receive(esp_isotp_handle_t handle, uint8_t *data, uint32_t s
* - Processes incoming TWAI frames and assembles complete messages
* - Handles flow control and timeouts
* - Updates internal state machine
* - Triggers TX completion callbacks for multi-frame messages
*
* Without regular polling: multi-frame sends will stall and receives won't complete.
*
* @warning This function is NOT ISR-safe and must only be called from task context.
* @note TX completion callbacks for multi-frame messages are triggered from this function.
*
* @param handle ISO-TP handle
* @return
* - ESP_OK: Processing successful
Expand All @@ -137,8 +209,9 @@ esp_err_t esp_isotp_poll(esp_isotp_handle_t handle);
*
* @param handle The handle of the ISO-TP link to delete
* @return
* - ESP_OK: Success
* - ESP_OK: Success (or TWAI disable warning logged)
* - ESP_ERR_INVALID_ARG: Invalid argument
* - Other ESP error codes: TWAI node disable failed
*/
esp_err_t esp_isotp_delete(esp_isotp_handle_t handle);

Expand Down
Loading
Loading