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 14, 2023
1 parent 846bfc8 commit 891e365
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 76 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 @@ -133,10 +133,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 uint8_t target_addr, void *sent_cb_arg);
const uint8_t target_addr, uint8_t target_bus, void *sent_cb_arg);
16 changes: 16 additions & 0 deletions src/Kconfig.can
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,28 @@ config THINGSET_CAN_PACKETIZED_REPORTS_FRAME_TX_INTERVAL

config THINGSET_CAN_MULTIPLE_INSTANCES
bool "Support for multiple ThingSet CAN instances"
depends on ISOTP_FAST
help
If enabled, the CAN message processing does not happen in the
background anymore. Instead, each instance has to be initialized
for a dedicated CAN device and and messages have to be processed
manually in application threads.

The bus numbering scheme in the CAN ID is not compatible with
the current Zephyr upstream ISO-TP implementation, so it depends
on ISOTP_FAST.

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
61 changes: 36 additions & 25 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 @@ -459,9 +464,10 @@ void isotp_fast_recv_callback(struct net_buf *buffer, int rem_len, uint32_t can_
int tx_len =
thingset_process_message(&ts, ts_can->rx_buffer, len, sbuf->data, sbuf->size);
if (tx_len > 0) {
uint8_t 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);
uint8_t 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 @@ -492,19 +498,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 All @@ -522,11 +530,12 @@ int thingset_can_process_inst(struct thingset_can *ts_can, k_timeout_t timeout)
{
struct shared_buffer *sbuf = thingset_sdk_shared_buffer();
uint8_t external_addr;
uint8_t external_bus;
int tx_len, rx_len;
int err;

rx_len = thingset_can_receive_inst(ts_can, ts_can->rx_buffer, sizeof(ts_can->rx_buffer),
&external_addr, timeout);
&external_addr, &external_bus, timeout);
if (rx_len == -EAGAIN) {
return -EAGAIN;
}
Expand Down Expand Up @@ -554,7 +563,7 @@ int thingset_can_process_inst(struct thingset_can *ts_can, k_timeout_t timeout)
k_sleep(K_MSEC(CONFIG_THINGSET_CAN_RESPONSE_DELAY));

if (tx_len > 0) {
err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, external_addr);
err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, external_addr, external_bus);
if (err == -ENODEV) {
LOG_ERR("CAN processing stopped because device not ready");
k_sem_give(&sbuf->lock);
Expand All @@ -567,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 @@ -592,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 @@ -751,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 @@ -779,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
Loading

0 comments on commit 891e365

Please sign in to comment.