Skip to content

Commit

Permalink
CAN: implement new bus numbering scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
martinjaeger committed Dec 13, 2023
1 parent 631ffe5 commit 701912e
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 53 deletions.
65 changes: 41 additions & 24 deletions include/thingset/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ extern "C" {
*
* Channel-based messages using ISO-TP:
*
* 28 26 25 24 23 16 15 8 7 0
* +----------+-----+---------------+---------------+---------------+
* | Priority | 0x0 | bus ID | target addr | source addr |
* +----------+-----+---------------+---------------+---------------+
* 28 26 25 24 23 20 19 16 15 8 7 0
* +----------+-----+---------+---------+---------------+---------------+
* | Priority | 0x0 | tgt bus | src bus | target addr | source addr |
* +----------+-----+---------+---------+---------------+---------------+
*
* Priority: 6
*
* Bus ID:
* Set to 218 (0xDA) by default as suggested by ISO-TP standard (ISO 15765-2)
* for normal fixed addressing with N_TAtype = physical.
* tgt bus: Bus number of the target node (default for single bus systems is 0x0)
* src bus: Bus number of the source node (default for single bus systems is 0x0)
*
* Control and report messages (always single-frame):
*
Expand Down Expand Up @@ -86,18 +85,27 @@ extern "C" {
#define THINGSET_CAN_DATA_ID_GET(id) \
(((uint32_t)id & THINGSET_CAN_DATA_ID_MASK) >> THINGSET_CAN_DATA_ID_POS)

/* bus ID for request/response messages */
#define THINGSET_CAN_BUS_ID_POS (16U)
#define THINGSET_CAN_BUS_ID_MASK (0xFF << THINGSET_CAN_BUS_ID_POS)
#define THINGSET_CAN_BUS_ID_SET(id) \
(((uint32_t)id << THINGSET_CAN_BUS_ID_POS) & THINGSET_CAN_BUS_ID_MASK)
#define THINGSET_CAN_BUS_ID_GET(id) \
(((uint32_t)id & THINGSET_CAN_BUS_ID_MASK) >> THINGSET_CAN_BUS_ID_POS)
#define THINGSET_CAN_BUS_ID_DEFAULT (0xDA) // 218, N_TAtype = physical
/* bus numbers for request/response messages */
#define THINGSET_CAN_SOURCE_BUS_POS (16U)
#define THINGSET_CAN_SOURCE_BUS_MASK (0xF << THINGSET_CAN_SOURCE_BUS_POS)
#define THINGSET_CAN_SOURCE_BUS_SET(id) \
(((uint32_t)id << THINGSET_CAN_SOURCE_BUS_POS) & THINGSET_CAN_SOURCE_BUS_MASK)
#define THINGSET_CAN_SOURCE_BUS_GET(id) \
(((uint32_t)id & THINGSET_CAN_SOURCE_BUS_MASK) >> THINGSET_CAN_SOURCE_BUS_POS)
#define THINGSET_CAN_SOURCE_BUS_DEFAULT (0x0)
#define THINGSET_CAN_TARGET_BUS_POS (20U)
#define THINGSET_CAN_TARGET_BUS_MASK (0xF << THINGSET_CAN_TARGET_BUS_POS)
#define THINGSET_CAN_TARGET_BUS_SET(id) \
(((uint32_t)id << THINGSET_CAN_TARGET_BUS_POS) & THINGSET_CAN_TARGET_BUS_MASK)
#define THINGSET_CAN_TARGET_BUS_GET(id) \
(((uint32_t)id & THINGSET_CAN_TARGET_BUS_MASK) >> THINGSET_CAN_TARGET_BUS_POS)
#define THINGSET_CAN_TARGET_BUS_DEFAULT (0x0)

/* random number for address discovery messages */
#define THINGSET_CAN_RAND_SET THINGSET_CAN_BUS_ID_SET
#define THINGSET_CAN_RAND_GET THINGSET_CAN_BUS_ID_GET
#define THINGSET_CAN_RAND_POS (16U)
#define THINGSET_CAN_RAND_MASK (0xFF << THINGSET_CAN_RAND_POS)
#define THINGSET_CAN_RAND_SET(id) (((uint32_t)id << THINGSET_CAN_RAND_POS) & THINGSET_CAN_RAND_MASK)
#define THINGSET_CAN_RAND_GET(id) (((uint32_t)id & THINGSET_CAN_RAND_MASK) >> THINGSET_CAN_RAND_POS)

/* message types */
#define THINGSET_CAN_TYPE_POS (24U)
Expand Down Expand Up @@ -180,6 +188,7 @@ struct thingset_can
thingset_can_report_rx_callback_t report_rx_cb;
int64_t next_pub_time;
uint8_t node_addr;
uint8_t bus_number;
};

#ifdef CONFIG_THINGSET_CAN_MULTIPLE_INSTANCES
Expand All @@ -191,12 +200,13 @@ struct thingset_can
* @param rx_buf Buffer to store the message.
* @param rx_buf_size Size of the buffer to store the message.
* @param source_addr Pointer to store the node address the data was received from.
* @param source_bus Pointer to store the bus number the data was received from.
* @param timeout Timeout to wait for a message from the node.
*
* @returns length of message or negative errno in case of error
*/
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);
uint8_t *source_addr, uint8_t *source_bus, k_timeout_t timeout);

#ifdef CONFIG_ISOTP_FAST
/**
Expand All @@ -206,6 +216,7 @@ int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buf, size
* @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 target_bus Target bus number (4-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.
Expand All @@ -214,8 +225,9 @@ int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buf, size
* @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);
uint8_t target_addr, uint8_t target_bus,
thingset_can_response_callback_t rsp_callback, void *callback_arg,
k_timeout_t timeout);
#else
/**
* Send ThingSet message to other node
Expand All @@ -224,11 +236,12 @@ int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t
* @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 target_bus Target bus number (4-bit value) to send the message to.
*
* @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);
uint8_t target_addr, uint8_t target_bus);

/**
* Process incoming ThingSet requests
Expand Down Expand Up @@ -268,10 +281,12 @@ int thingset_can_set_report_rx_callback_inst(struct thingset_can *ts_can,
*
* @param ts_can Pointer to the thingset_can context.
* @param can_dev Pointer to the CAN device that should be used.
* @param bus_number Assigned bus number of this CAN device.
*
* @returns 0 for success or negative errno in case of error
*/
int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev);
int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev,
uint8_t bus_number);

#else /* !CONFIG_THINGSET_CAN_MULTIPLE_INSTANCES */

Expand All @@ -282,10 +297,11 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can
* @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 target_bus Target bus number (4-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,
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t target_bus,
thingset_can_response_callback_t rsp_callback, void *callback_arg,
k_timeout_t timeout);
#else
Expand All @@ -295,10 +311,11 @@ int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr,
* @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 target_bus Target bus number (4-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);
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t target_bus);
#endif /* CONFIG_ISOTP_FAST */

/**
Expand Down
3 changes: 2 additions & 1 deletion include/thingset/isotp_fast.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,11 @@ int isotp_fast_recv(struct isotp_fast_ctx *ctx, struct can_filter sender, uint8_
* @param target_addr 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 target_bus Target bus number (4-bit value) to send the message to.
* @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 target_addr, void *sent_cb_arg);
const isotp_fast_node_id target_addr, uint8_t target_bus, void *sent_cb_arg);
11 changes: 11 additions & 0 deletions src/Kconfig.can
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ config THINGSET_CAN_MULTIPLE_INSTANCES
for a dedicated CAN device and and messages have to be processed
manually in application threads.

config THINGSET_CAN_BUS_NUMBER
int "ThingSet CAN bus number"
depends on !THINGSET_CAN_MULTIPLE_INSTANCES
range 0 15
default 0
help
The bus number can be used to identify multiple CAN buses in one system.
It is used by gateways to forward messages between different buses.

For a single bus system, the default bus number 0 should be used.

config THINGSET_CAN_RESPONSE_DELAY
int "ThingSet CAN response delay"
range 0 100
Expand Down
56 changes: 33 additions & 23 deletions src/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ void thingset_can_request_response_timeout_handler(struct k_timer *timer)
}
#else
int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buffer, size_t rx_buf_size,
uint8_t *source_addr, k_timeout_t timeout)
uint8_t *source_addr, uint8_t *source_bus, k_timeout_t timeout)
{
int ret, rem_len, rx_len;
struct net_buf *netbuf;
Expand Down Expand Up @@ -390,7 +390,9 @@ int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buffer, s
}
else if (rx_len > 0 && rem_len == 0) {
*source_addr = THINGSET_CAN_SOURCE_GET(ts_can->recv_ctx.rx_addr.ext_id);
LOG_DBG("ISO-TP received %d bytes from addr %d", rx_len, *source_addr);
*source_bus = THINGSET_CAN_SOURCE_BUS_GET(ts_can->recv_ctx.rx_addr.ext_id);
LOG_DBG("ISO-TP received %d bytes from addr 0x%X on bus 0x%X", rx_len, *source_addr,
*source_bus);
return rx_len;
}
else if (rem_len == ISOTP_RECV_TIMEOUT) {
Expand All @@ -404,8 +406,9 @@ int thingset_can_receive_inst(struct thingset_can *ts_can, uint8_t *rx_buffer, s

#ifdef CONFIG_ISOTP_FAST
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)
uint8_t target_addr, uint8_t target_bus,
thingset_can_response_callback_t rsp_callback, void *callback_arg,
k_timeout_t timeout)
{
if (!device_is_ready(ts_can->dev)) {
return -ENODEV;
Expand All @@ -422,16 +425,18 @@ int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t
NULL);
k_timer_start(&ts_can->request_response.timer, timeout, timeout);
ts_can->request_response.can_id = THINGSET_CAN_TYPE_CHANNEL | THINGSET_CAN_PRIO_CHANNEL
| THINGSET_CAN_TARGET_BUS_SET(ts_can->bus_number)
| THINGSET_CAN_SOURCE_BUS_SET(target_bus)
| THINGSET_CAN_TARGET_SET(ts_can->node_addr)
| THINGSET_CAN_SOURCE_SET(target_addr);
}
int ret = isotp_fast_send(&ts_can->ctx, tx_buf, tx_len, target_addr, ts_can);
int ret = isotp_fast_send(&ts_can->ctx, tx_buf, tx_len, target_addr, target_bus, ts_can);

if (ret == ISOTP_N_OK) {
return 0;
}
else {
LOG_ERR("Error sending data to addr %d: %d", target_addr, ret);
LOG_ERR("Error sending data to addr 0x%X: %d", target_addr, ret);
return -EIO;
}
}
Expand Down Expand Up @@ -460,9 +465,10 @@ void isotp_fast_recv_callback(struct net_buf *buffer, int rem_len, isotp_fast_ca
int tx_len =
thingset_process_message(&ts, ts_can->rx_buffer, len, sbuf->data, sbuf->size);
if (tx_len > 0) {
isotp_fast_node_id target_id = (uint8_t)(can_id & 0xFF);
int err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, target_id, NULL, NULL,
K_NO_WAIT);
isotp_fast_node_id target_addr = THINGSET_CAN_SOURCE_GET(can_id);
uint8_t target_bus = THINGSET_CAN_SOURCE_BUS_GET(can_id);
int err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, target_addr,
target_bus, NULL, NULL, K_NO_WAIT);
if (err != 0) {
k_sem_give(&sbuf->lock);
}
Expand Down Expand Up @@ -493,19 +499,21 @@ void isotp_fast_sent_callback(int result, void *arg)
}
#else
int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t tx_len,
uint8_t target_addr)
uint8_t target_addr, uint8_t target_bus)
{
if (!device_is_ready(ts_can->dev)) {
return -ENODEV;
}

ts_can->tx_addr.ext_id = THINGSET_CAN_TYPE_CHANNEL | THINGSET_CAN_PRIO_CHANNEL
| THINGSET_CAN_TARGET_SET(target_addr)
| THINGSET_CAN_SOURCE_SET(ts_can->node_addr);
ts_can->tx_addr.ext_id =
THINGSET_CAN_TYPE_CHANNEL | THINGSET_CAN_PRIO_CHANNEL
| THINGSET_CAN_TARGET_BUS_SET(target_bus) | THINGSET_CAN_SOURCE_BUS_SET(ts_can->bus_number)
| THINGSET_CAN_TARGET_SET(target_addr) | THINGSET_CAN_SOURCE_SET(ts_can->node_addr);

ts_can->rx_addr.ext_id = THINGSET_CAN_TYPE_CHANNEL | THINGSET_CAN_PRIO_CHANNEL
| THINGSET_CAN_TARGET_SET(ts_can->node_addr)
| THINGSET_CAN_SOURCE_SET(target_addr);
ts_can->rx_addr.ext_id =
THINGSET_CAN_TYPE_CHANNEL | THINGSET_CAN_PRIO_CHANNEL
| THINGSET_CAN_TARGET_BUS_SET(ts_can->bus_number) | THINGSET_CAN_SOURCE_BUS_SET(target_bus)
| THINGSET_CAN_TARGET_SET(ts_can->node_addr) | THINGSET_CAN_SOURCE_SET(target_addr);

int ret = isotp_send(&ts_can->send_ctx, ts_can->dev, tx_buf, tx_len, &ts_can->tx_addr,
&ts_can->rx_addr, NULL, NULL);
Expand Down Expand Up @@ -568,7 +576,8 @@ int thingset_can_process_inst(struct thingset_can *ts_can, k_timeout_t timeout)
}
#endif /* CONFIG_ISOTP_FAST */

int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev)
int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can_dev,
uint8_t bus_number)
{
struct can_frame tx_frame = {
.flags = CAN_FRAME_IDE,
Expand All @@ -593,6 +602,7 @@ int thingset_can_init_inst(struct thingset_can *ts_can, const struct device *can
k_work_init_delayable(&ts_can->addr_claim_work, thingset_can_addr_claim_tx_handler);

ts_can->dev = can_dev;
ts_can->bus_number = bus_number;

/* set initial address (will be changed if already used on the bus) */
if (ts_can->node_addr < 1 || ts_can->node_addr > THINGSET_CAN_ADDR_MAX) {
Expand Down Expand Up @@ -752,17 +762,17 @@ THINGSET_ADD_ITEM_UINT8(TS_ID_NET, TS_ID_NET_CAN_NODE_ADDR, "pCANNodeAddr",
&ts_can_single.node_addr, THINGSET_ANY_RW, TS_SUBSET_NVM);

#ifdef CONFIG_ISOTP_FAST
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr,
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t target_bus,
thingset_can_response_callback_t rsp_callback, void *callback_arg,
k_timeout_t timeout)
{
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr, rsp_callback,
callback_arg, timeout);
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr, target_bus,
rsp_callback, callback_arg, timeout);
}
#else
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr)
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t target_bus)
{
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr);
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr, target_bus);
}
#endif /* CONFIG_ISOTP_FAST */

Expand All @@ -780,7 +790,7 @@ static void thingset_can_thread()
{
int err;

err = thingset_can_init_inst(&ts_can_single, can_dev);
err = thingset_can_init_inst(&ts_can_single, can_dev, CONFIG_THINGSET_CAN_BUS_NUMBER);
if (err != 0) {
LOG_ERR("Failed to init ThingSet CAN: %d", err);
return;
Expand Down
12 changes: 7 additions & 5 deletions src/isotp_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,13 @@ static void receive_can_tx(const struct device *dev, int error, void *arg)

static void receive_send_fc(struct isotp_fast_recv_ctx *rctx, uint8_t fs)
{
/* swap bus and address for FC frame */
struct can_frame frame = {
.flags =
CAN_FRAME_IDE | ((rctx->ctx->opts->flags & ISOTP_MSG_FDF) != 0 ? CAN_FRAME_FDF : 0),
.id = (rctx->rx_can_id & 0xFFFF0000) | ((rctx->rx_can_id & 0xFF00) >> 8)
| ((rctx->rx_can_id & 0xFF) << 8)
.id = (rctx->rx_can_id & 0xFF000000) | ((rctx->rx_can_id & 0x0000FF00) >> 8)
| ((rctx->rx_can_id & 0x000000FF) << 8) | ((rctx->rx_can_id & 0x000F0000) << 4)
| ((rctx->rx_can_id & 0x00F00000) >> 4)
};
uint8_t *data = frame.data;
uint8_t payload_len;
Expand Down Expand Up @@ -821,7 +823,7 @@ static inline void prepare_filter(struct can_filter *filter, isotp_fast_can_id r
const struct isotp_fast_opts *opts)
{
filter->id = rx_can_id;
filter->mask = ISOTP_FIXED_ADDR_RX_MASK;
filter->mask = 0x03F0FF00; /* fixed target bus and target address of any priority */
filter->flags = CAN_FILTER_DATA | CAN_FILTER_IDE
| ((opts->flags & ISOTP_MSG_FDF) != 0 ? CAN_FILTER_FDF : 0);
}
Expand Down Expand Up @@ -990,9 +992,9 @@ int isotp_fast_recv(struct isotp_fast_ctx *ctx, struct can_filter sender, uint8_
#endif /* CONFIG_ISOTP_FAST_BLOCKING_RECEIVE */

int isotp_fast_send(struct isotp_fast_ctx *ctx, const uint8_t *data, size_t len,
const isotp_fast_node_id target_addr, void *cb_arg)
const isotp_fast_node_id target_addr, uint8_t target_bus, void *cb_arg)
{
const isotp_fast_can_id rx_can_id = (ctx->rx_can_id & 0xFFFF0000)
const isotp_fast_can_id rx_can_id = (ctx->rx_can_id & 0xFFFF0000) | (target_bus << 20)
| (isotp_fast_get_target_addr(ctx->rx_can_id))
| (target_addr << ISOTP_FIXED_ADDR_TA_POS);
if (len <= (CAN_MAX_DLEN - ISOTP_FAST_SF_LEN_BYTE)) {
Expand Down

0 comments on commit 701912e

Please sign in to comment.