Skip to content

Commit

Permalink
ISO-TP: new ISO-TP implementation
Browse files Browse the repository at this point in the history
- single public context for send and receive; no more unbinding to send a message
- CAN-FD support
- only supports ISO-TP fixed addressing at present
- broadly async approach, but sync receive supported for familiarity/compatibility
- conformance tests ported from existing implementation
  • Loading branch information
garethpotter committed Oct 23, 2023
1 parent f46e0f0 commit 95d03fa
Show file tree
Hide file tree
Showing 39 changed files with 3,144 additions and 18 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
container: zephyrprojectrtos/ci:v0.26.2
container: zephyrprojectrtos/ci:v0.26.5
env:
CMAKE_PREFIX_PATH: /opt/toolchains
steps:
Expand Down Expand Up @@ -36,7 +36,7 @@ jobs:
sudo apt install -y git make python3 python3-pip doxygen
pip3 install -r docs/requirements.txt
- name: Run build tests
- name: Run sample build tests
working-directory: thingset-zephyr-sdk
run: |
west build -p -b olimex_lora_stm32wl_devkit samples/counter -- -DOVERLAY_CONFIG=lorawan.conf
Expand All @@ -51,6 +51,11 @@ jobs:
west build -p -b native_posix samples/counter -- -DOVERLAY_CONFIG=native_websocket.conf
west build -p -b xiao_esp32c3 samples/serial_ble_gateway
- name: Run unit tests
working-directory: thingset-zephyr-sdk
run: |
../zephyr/scripts/twister -T ./tests --integration --inline-logs
- name: Build documentation
working-directory: thingset-zephyr-sdk
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# folders generated by west
build
twister-out*

# editors
.vscode/*
Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# This CMake file is picked by the Zephyr build system because it is defined
# as the module CMake entry point (see zephyr/module.yml).

add_subdirectory_ifdef(CONFIG_THINGSET_SDK src)
if (CONFIG_ISOTP_FAST OR CONFIG_THINGSET_SDK)
add_subdirectory(src)
endif()

zephyr_include_directories(include)
7 changes: 6 additions & 1 deletion Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (c) The ThingSet Project Contributors
# SPDX-License-Identifier: Apache-2.0

rsource "src/Kconfig.isotp_fast"

menuconfig THINGSET_SDK
bool "ThingSet SDK"

Expand Down Expand Up @@ -69,8 +71,11 @@ config THINGSET_NODE_NAME

config THINGSET_SHARED_TX_BUF_SIZE
int "Shared TX buffer size"
range 256 2048
range 256 10240
default 1024
help
This buffer is used to create ThingSet responses for the different interfaces. It has to be
large enough to fit the largest expected response.

config THINGSET_SDK_THREAD_STACK_SIZE
int "Common thread stack size"
Expand Down
65 changes: 64 additions & 1 deletion include/thingset/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef THINGSET_CAN_H_
#define THINGSET_CAN_H_

#include "isotp_fast.h"
#include <zephyr/canbus/isotp.h>
#include <zephyr/device.h>

Expand Down Expand Up @@ -138,6 +139,19 @@ extern "C" {
*/
typedef void (*thingset_can_report_rx_callback_t)(uint16_t data_id, const uint8_t *value,
size_t value_len, uint8_t source_addr);
#ifdef CONFIG_ISOTP_FAST
typedef void (*thingset_can_response_callback_t)(uint8_t *data, size_t len, int result,
uint8_t sender_id, void *arg);

struct thingset_can_request_response
{
struct k_sem sem;
struct k_timer timer;
isotp_fast_msg_id sender_addr;
thingset_can_response_callback_t callback;
void *cb_arg;
};
#endif /* CONFIG_ISOTP_FAST */

/**
* ThingSet CAN context storing all information required for one instance.
Expand All @@ -147,13 +161,20 @@ struct thingset_can
const struct device *dev;
struct k_work_delayable reporting_work;
struct k_work_delayable addr_claim_work;
#ifdef CONFIG_ISOTP_FAST
struct isotp_fast_ctx ctx;
#else
struct isotp_recv_ctx recv_ctx;
struct isotp_send_ctx send_ctx;
struct isotp_msg_id rx_addr;
struct isotp_msg_id tx_addr;
#endif
struct k_event events;
thingset_can_report_rx_callback_t report_rx_cb;
#ifdef CONFIG_ISOTP_FAST
struct thingset_can_request_response request_response;
#endif
uint8_t rx_buffer[CONFIG_THINGSET_CAN_RX_BUF_SIZE];
thingset_can_report_rx_callback_t report_rx_cb;
int64_t next_pub_time;
uint8_t node_addr;
bool pub_enable;
Expand All @@ -175,6 +196,25 @@ struct thingset_can
int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buf, size_t rx_buf_size,
uint8_t *source_addr, k_timeout_t timeout);

#ifdef CONFIG_ISOTP_FAST
/**
* Send ThingSet message to other node
*
* @param ts_can Pointer to the thingset_can context.
* @param tx_buf Buffer containing the message.
* @param tx_len Length of the message.
* @param target_addr Target node address (8-bit value) to send the message to.
* @param rsp_callback If a response is expected, this callback will be invoked,
* either when it arrives or if a timeout or some other error occurs.
* @param callback_arg User data for the callback.
* @param rsp_timeout Timeout to wait for a response.
*
* @returns 0 for success or negative errno in case of error
*/
int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t tx_len,
uint8_t target_addr, thingset_can_response_callback_t rsp_callback,
void *callback_arg, k_timeout_t timeout);
#else
/**
* Send ThingSet message to other node
*
Expand Down Expand Up @@ -206,6 +246,7 @@ int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t
* @retval -EAGAIN in case of timeout
*/
int thingset_can_process_inst(struct thingset_can *ts_can, k_timeout_t timeout);
#endif /* CONFIG_ISOTP_FAST */

/**
* Set callback for received reports from other nodes
Expand All @@ -232,6 +273,20 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can

#else /* !CONFIG_THINGSET_CAN_MULTIPLE_INSTANCES */

#ifdef CONFIG_ISOTP_FAST
/**
* Send ThingSet message to other node
*
* @param tx_buf Buffer containing the message.
* @param tx_len Length of the message.
* @param target_addr Target node address (8-bit value) to send the message to.
*
* @returns 0 for success or negative errno in case of error
*/
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr,
thingset_can_response_callback_t rsp_callback, void *callback_arg,
k_timeout_t timeout);
#else
/**
* Send ThingSet message to other node
*
Expand All @@ -242,6 +297,7 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can
* @returns 0 for success or negative errno in case of error
*/
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr);
#endif /* CONFIG_ISOTP_FAST */

/**
* Set callback for received reports from other nodes
Expand All @@ -255,6 +311,13 @@ int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr);
*/
int thingset_can_set_report_rx_callback(thingset_can_report_rx_callback_t rx_cb);

/**
* Get ThingSet CAN instance
*
* @returns Pointer to internal ThingSet CAN instance
*/
struct thingset_can *thingset_can_get_inst();

#endif /* CONFIG_THINGSET_CAN_MULTIPLE_INSTANCES */

#ifdef __cplusplus
Expand Down
142 changes: 142 additions & 0 deletions include/thingset/isotp_fast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2023 Brill Power
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifdef CONFIG_ISOTP_FAST
#include <zephyr/canbus/isotp.h>

#ifndef ISOTP_MSG_FDF
#define ISOTP_MSG_FDF BIT(3)
#endif

/* Represents a sender or a receiver in an ISO-TP fixed addressing scheme */
typedef uint8_t isotp_fast_node_id;
/* ISO-TP message ID, i.e. the CAN ID */
typedef uint32_t isotp_fast_msg_id;

/**
* Callback invoked when a message is received.
* @param buffer Pointer to a @ref net_buf. Call @ref net_buf_frags_len to
* obtain the length of the buffer, then @ref net_buf_linearize to copy the
* contents of the buffer into a local buffer.
* @param rem_len At present, this should always be zero. In future, this
* callback may be called repeatedly as a message's packets arrive to reduce
* the need to buffer an entire message in memory before it is dispatched
* to user code.
* @param sender_addr The CAN ID of the message that has been received.
* @param arg The value of @ref recv_cb_arg passed to @ref isotp_fast_bind.
*/
typedef void (*isotp_fast_recv_callback_t)(struct net_buf *buffer, int rem_len,
isotp_fast_msg_id sender_addr, void *arg);

/**
* Callback invoked when an error occurs during message receiption.
* @param error The error code.
* @param sender_addr The CAN ID of the sender of the message, if available.
* @param arg The value of @ref recv_cb_arg passed to @ref isotp_fast_bind.
*/
typedef void (*isotp_fast_recv_error_callback_t)(int8_t error, isotp_fast_msg_id sender_addr,
void *arg);

/**
* Callback invoked when a message has been sent.
* @param result If non-zero, an error has occurred.
* @param arg The value of @ref sent_cb_arg passed to @ref isotp_fast_send.
*/
typedef void (*isotp_fast_send_callback_t)(int result, void *arg);

/**
* Options pertaining to the bound context.
*/
struct isotp_fast_opts
{
uint8_t bs; /**< Block size. Number of CF PDUs before next CF is sent */
uint8_t stmin; /**< Minimum separation time. Min time between frames */
uint8_t flags;
};

/**
* General context object.
*/
struct isotp_fast_ctx
{
/* The CAN device to which the context is bound via @ref isotp_fast_bind */
const struct device *can_dev;
/* Identifies the CAN filter which filters incoming messages */
int filter_id;
/* Pointer to context options described above */
const struct isotp_fast_opts *opts;
/* Callback that is invoked when a message is received */
isotp_fast_recv_callback_t recv_callback;
/* Pointer to user-supplied data to be passed to @ref recv_callback */
void *recv_cb_arg;
/* Callback that is invoked when a receive error occurs */
isotp_fast_recv_error_callback_t recv_error_callback;
/* Callback that is invoked when a message is sent */
isotp_fast_send_callback_t sent_callback;
/* CAN ID of this node, used in both transmission and receipt of messages */
isotp_fast_msg_id my_addr;
#ifdef CONFIG_ISOTP_FAST_BLOCKING_RECEIVE
sys_slist_t wait_recv_list;
#endif
};

/**
* Binds the supplied ISO-TP context to the supplied CAN device. Messages
* addressed to the given address (@ref my_addr) will be delivered to user
* code by invoking the supplied callback, @ref recv_callback.
*
* @param ctx A pointer to the general ISO-TP context
* @param can_dev The CAN device to which the context should be bound
* @param my_addr The address to listen on for incoming messages or to use
* when transmitting messages
* @param opts A pointer to an options structure, @ref isotp_fast_opts
* @param recv_callback A callback that is invoked when a message is received
* @param recv_cb_arg A pointer to data to be supplied to @ref recv_callback
* @param recv_error_callback A callback that is invoked when an error occurs.
* @param sent_callback A callback that is invoked when a message is sent
*
* @returns 0 on success, otherwise an error code < 0.
*/
int isotp_fast_bind(struct isotp_fast_ctx *ctx, const struct device *can_dev,
const isotp_fast_msg_id my_addr, const struct isotp_fast_opts *opts,
isotp_fast_recv_callback_t recv_callback, void *recv_cb_arg,
isotp_fast_recv_error_callback_t recv_error_callback,
isotp_fast_send_callback_t sent_callback);

/**
* Unbinds the supplied ISO-TP context. Removes the CAN filter if it was
* successfully set.
*
* @param ctx A pointer to the context to unbind
*
* @returns 0 on success.
*/
int isotp_fast_unbind(struct isotp_fast_ctx *ctx);

#ifdef CONFIG_ISOTP_FAST_BLOCKING_RECEIVE
int isotp_fast_recv(struct isotp_fast_ctx *ctx, struct can_filter sender, uint8_t *buf, size_t size,
k_timeout_t timeout);
#endif

/**
* Send a message to a given recipient. If the message fits within a
* CAN frame, it will be sent synchronously. If not, it will be sent
* asynchronously.
*
* @param ctx The bound context on which the message should be sent
* @param data A pointer to the data containing the message to send
* @param len The length of the data in @ref data
* @param their_id The node ID identifying the recipient. This will be
* combined with the sending address @ref my_addr on @ref ctx to form
* the CAN ID on the message.
* @param sent_cb_arg A pointer to data to be supplied to the callback
* that will be invoked when the message is sent.
*
* @returns 0 on success.
*/
int isotp_fast_send(struct isotp_fast_ctx *ctx, const uint8_t *data, size_t len,
const isotp_fast_node_id their_id, void *sent_cb_arg);
#endif /* CONFIG_ISOTP_FAST */
6 changes: 4 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Copyright (c) The ThingSet Project Contributors
# SPDX-License-Identifier: Apache-2.0

target_sources(app PRIVATE sdk.c)
target_sources(app PRIVATE packetizer.c)
target_sources_ifdef(CONFIG_ISOTP_FAST app PRIVATE isotp_fast.c)

target_sources_ifdef(CONFIG_THINGSET_SDK app PRIVATE sdk.c)
target_sources_ifdef(CONFIG_THINGSET_SDK app PRIVATE packetizer.c)

target_sources_ifdef(CONFIG_THINGSET_AUTH app PRIVATE auth.c)
target_sources_ifdef(CONFIG_THINGSET_BLE app PRIVATE ble.c)
Expand Down
41 changes: 41 additions & 0 deletions src/Kconfig.isotp_fast
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
menuconfig ISOTP_FAST
bool "New ISO-TP context"
depends on CAN
depends on ISOTP
select EVENTS

if ISOTP_FAST

config ISOTP_FAST_RX_MAX_PACKET_COUNT
int "Max packets for ISO-TP reception"
default 8
help
Max number of packets expected in a single ISO-TP message.

config ISOTP_FAST_RX_BUF_COUNT
int "Max number of RX buffers"
default 4
help
This broadly implies the max number of simultaneous receptions.

config ISOTP_FAST_TX_BUF_COUNT
int "Max number of TX buffers"
default 4
help
This broadly implies the max number of simultaneous transmissions.

config ISOTP_FAST_PER_FRAME_DISPATCH
bool "Per-frame dispatch"
default false
help
Whether to invoke the receive callback on receipt of every frame

config ISOTP_FAST_BLOCKING_RECEIVE
bool "Blocking receive"
default false
depends on !ISOTP_FAST_PER_FRAME_DISPATCH
help
Whether to make blocking receive functionality available
to ease migration from the old API.

endif
Loading

0 comments on commit 95d03fa

Please sign in to comment.