Skip to content

Commit

Permalink
CAN: Implement bridge routing as alternative to bus routing
Browse files Browse the repository at this point in the history
  • Loading branch information
martinjaeger committed Feb 28, 2024
1 parent 60d01ea commit 22b5e7f
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 27 deletions.
41 changes: 30 additions & 11 deletions include/thingset/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extern "C" {
/*
* ThingSet addressing in 29-bit CAN ID
*
* Request/response messages using ISO-TP:
* Request/response messages using ISO-TP (bus forwarding scheme):
*
* 28 26 25 24 23 20 19 16 15 8 7 0
* +----------+-----+---------+---------+---------------+---------------+
Expand All @@ -31,6 +31,17 @@ extern "C" {
* 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)
*
* Request/response messages using ISO-TP (bridge forwarding scheme):
*
* 28 26 25 24 23 16 15 8 7 0
* +----------+-----+----------+---------------+---------------+
* | Priority | 0x0 | bridge | target addr | source addr |
* +----------+-----+----------+---------------+---------------+
*
* Priority: 6
*
* bridge: Bridge number for message forwarding (0x00 for local communication)
*
* Multi-frame reports:
*
* 28 26 25 24 23 20 19 16 15 13 12 11 8 7 0
Expand All @@ -42,6 +53,7 @@ extern "C" {
* msg#: Wrapping message counter from 0 to 7
* end: End of message flag
* seq#: Wrapping sequence counter from 0 to 15
* src bus and res: Either source bus or bridge number
*
* Single-frame reports:
*
Expand Down Expand Up @@ -116,7 +128,7 @@ extern "C" {
#define THINGSET_CAN_MSG_NO_GET(id) \
(((uint32_t)id & THINGSET_CAN_MSG_NO_MASK) >> THINGSET_CAN_MSG_NO_POS)

/* bus numbers for request/response messages */
/* bus numbers for request/response messages and multi-frame reports */
#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) \
Expand All @@ -132,6 +144,15 @@ extern "C" {
(((uint32_t)id & THINGSET_CAN_TARGET_BUS_MASK) >> THINGSET_CAN_TARGET_BUS_POS)
#define THINGSET_CAN_TARGET_BUS_DEFAULT (0x0)

/* bridge numbers for request/response messages and multi-frame reports */
#define THINGSET_CAN_BRIDGE_POS (16U)
#define THINGSET_CAN_BRIDGE_MASK (0xFF << THINGSET_CAN_BRIDGE_POS)
#define THINGSET_CAN_BRIDGE_SET(id) \
(((uint32_t)id << THINGSET_CAN_BRIDGE_POS) & THINGSET_CAN_BRIDGE_MASK)
#define THINGSET_CAN_BRIDGE_GET(id) \
(((uint32_t)id & THINGSET_CAN_BRIDGE_MASK) >> THINGSET_CAN_BRIDGE_POS)
#define THINGSET_CAN_BRIDGE_LOCAL (0x00)

/* random number for address discovery messages */
#define THINGSET_CAN_RAND_POS (16U)
#define THINGSET_CAN_RAND_MASK (0xFF << THINGSET_CAN_RAND_POS)
Expand Down Expand Up @@ -242,7 +263,8 @@ struct thingset_can
int64_t next_control_report_time;
#endif
uint8_t node_addr;
uint8_t bus_number : 4;
/** bus or bridge number */
uint8_t route;
uint8_t msg_no;
};

Expand All @@ -267,7 +289,7 @@ int thingset_can_send_report_inst(struct thingset_can *ts_can, const char *path,
* @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 route Target bus/bridge number to send the message to.
* @param callback This callback will be invoked when a response is received or an error during
* sending or receiving occurred. Set to NULL if no response is expected.
* @param callback_arg User data for the callback.
Expand All @@ -276,7 +298,7 @@ int thingset_can_send_report_inst(struct thingset_can *ts_can, const char *path,
* @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_bus,
uint8_t target_addr, uint8_t route,
thingset_can_reqresp_callback_t callback, void *callback_arg,
k_timeout_t timeout);

Expand Down Expand Up @@ -317,7 +339,7 @@ int thingset_can_set_item_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.
* @param bus_number Assigned bus number of this CAN device (ignored if bridge routing is used)
*
* @returns 0 for success or negative errno in case of error
*/
Expand All @@ -339,14 +361,11 @@ int thingset_can_send_report(const char *path, enum thingset_data_format format)
/**
* 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.
* @param target_bus Target bus number (4-bit value) to send the message to.
* See thingset_can_send_inst() for function parameters.
*
* @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, uint8_t target_bus,
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t route,
thingset_can_reqresp_callback_t callback, void *callback_arg,
k_timeout_t timeout);

Expand Down
44 changes: 38 additions & 6 deletions src/Kconfig.can
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ menuconfig THINGSET_CAN
depends on ISOTP_FAST
depends on ENTROPY_GENERATOR
select EVENTS
select ISOTP_FAST_CUSTOM_ADDRESSING

if THINGSET_CAN

Expand Down Expand Up @@ -95,6 +96,36 @@ config THINGSET_CAN_CONTROL_REPORTING_PERIOD
depends on THINGSET_CAN_CONTROL_REPORTING
default 100

choice THINGSET_CAN_ROUTING
prompt "Message routing scheme"
default THINGSET_CAN_ROUTING_BUSES
help
Select how frames should be routed between different buses.

config THINGSET_CAN_ROUTING_BUSES
bool "Bus numbers"
depends on ISOTP_FAST
select ISOTP_FAST_CUSTOM_ADDRESSING
help
Bits 16-23 of the CAN ID are used for a target bus (higher nibble) and a
source bus (lower nibble).

Buses should be used to allow message routing from one bus to any other bus.
There is no hierarchy between the buses.

config THINGSET_CAN_ROUTING_BRIDGES
bool "Bridge numbers"
select ISOTP_FAST_FIXED_ADDRESSING
help
Bits 16-23 of the CAN ID are used to define a bridge number between 1 and
255. Each bridge defines the connection between two fixed buses. Bridge
number 0 is reserved local communication on the same bus (i.e. no routing).

Bridges should be used if the maximum amount of 16 buses is not
sufficient. Otherwise, routing using bus numbers are more simple and generic.

endchoice

config THINGSET_CAN_MULTIPLE_INSTANCES
bool "Support for multiple ThingSet CAN instances"
depends on ISOTP_FAST
Expand All @@ -108,16 +139,17 @@ config THINGSET_CAN_MULTIPLE_INSTANCES
the current Zephyr upstream ISO-TP implementation, so it depends
on ISOTP_FAST.

config THINGSET_CAN_BUS_NUMBER
int "ThingSet CAN bus number"
config THINGSET_CAN_DEFAULT_ROUTE
int "ThingSet CAN default route"
depends on !THINGSET_CAN_MULTIPLE_INSTANCES
range 0 15
range 0 15 if THINGSET_CAN_ROUTING_BUSES
range 0 255 if THINGSET_CAN_ROUTING_BRIDGES
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.
The bus or bridge number (depending on THINGSET_CAN_ROUTING choice) is
used to route messages between different buses.

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

config THINGSET_CAN_RESPONSE_DELAY
int "ThingSet CAN response delay"
Expand Down
29 changes: 19 additions & 10 deletions src/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,12 @@ static struct isotp_fast_addr thingset_can_get_tx_addr(const struct isotp_fast_a
{
return (struct isotp_fast_addr){
.ext_id = (rx_addr->ext_id & 0x1F000000)
#ifdef CONFIG_THINGSET_CAN_ROUTING_BUSES
| THINGSET_CAN_TARGET_BUS_SET(THINGSET_CAN_SOURCE_BUS_GET(rx_addr->ext_id))
| THINGSET_CAN_SOURCE_BUS_SET(THINGSET_CAN_TARGET_BUS_GET(rx_addr->ext_id))
#else /* CONFIG_THINGSET_CAN_ROUTING_BRIDGES */
| THINGSET_CAN_BRIDGE_SET(THINGSET_CAN_BRIDGE_GET(rx_addr->ext_id))
#endif
| THINGSET_CAN_SOURCE_SET(THINGSET_CAN_TARGET_GET(rx_addr->ext_id))
| THINGSET_CAN_TARGET_SET(THINGSET_CAN_SOURCE_GET(rx_addr->ext_id)),
};
Expand All @@ -418,7 +422,7 @@ static void thingset_can_reqresp_timeout_handler(struct k_timer *timer)
}

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_bus,
uint8_t target_addr, uint8_t route,
thingset_can_reqresp_callback_t callback, void *callback_arg,
k_timeout_t timeout)
{
Expand All @@ -428,8 +432,11 @@ int thingset_can_send_inst(struct thingset_can *ts_can, uint8_t *tx_buf, size_t

struct isotp_fast_addr tx_addr = {
.ext_id = THINGSET_CAN_TYPE_REQRESP | THINGSET_CAN_PRIO_REQRESP
| THINGSET_CAN_SOURCE_BUS_SET(ts_can->bus_number)
| THINGSET_CAN_TARGET_BUS_SET(target_bus)
#ifdef CONFIG_THINGSET_CAN_ROUTING_BUSES
| THINGSET_CAN_SOURCE_BUS_SET(ts_can->route) | THINGSET_CAN_TARGET_BUS_SET(route)
#else /* CONFIG_THINGSET_CAN_ROUTING_BRIDGES */
| THINGSET_CAN_BRIDGE_SET(route)
#endif
| THINGSET_CAN_SOURCE_SET(ts_can->node_addr)
| THINGSET_CAN_TARGET_SET(target_addr),
};
Expand Down Expand Up @@ -484,9 +491,11 @@ static void thingset_can_reqresp_recv_callback(struct net_buf *buffer, int rem_l
thingset_process_message(&ts, ts_can->rx_buffer, len, sbuf->data, sbuf->size);
if (tx_len > 0) {
uint8_t target_addr = THINGSET_CAN_SOURCE_GET(addr.ext_id);
uint8_t target_bus = THINGSET_CAN_SOURCE_BUS_GET(addr.ext_id);
int err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, target_addr,
target_bus, NULL, NULL, K_NO_WAIT);
uint8_t route = IS_ENABLED(CONFIG_THINGSET_CAN_ROUTING_BUSES)
? THINGSET_CAN_SOURCE_BUS_GET(addr.ext_id)
: THINGSET_CAN_BRIDGE_GET(addr.ext_id);
int err = thingset_can_send_inst(ts_can, sbuf->data, tx_len, target_addr, route,
NULL, NULL, K_NO_WAIT);
if (err != 0) {
k_sem_give(&sbuf->lock);
}
Expand Down Expand Up @@ -546,7 +555,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;
ts_can->route = bus_number;

/* set initial address (will be changed if already used on the bus) */
if (ts_can->node_addr < THINGSET_CAN_ADDR_MIN || ts_can->node_addr > THINGSET_CAN_ADDR_MAX) {
Expand Down Expand Up @@ -729,11 +738,11 @@ int thingset_can_send_report(const char *path, enum thingset_data_format format)
return thingset_can_send_report_inst(&ts_can_single, path, format);
}

int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t target_bus,
int thingset_can_send(uint8_t *tx_buf, size_t tx_len, uint8_t target_addr, uint8_t route,
thingset_can_reqresp_callback_t callback, void *callback_arg,
k_timeout_t timeout)
{
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr, target_bus, callback,
return thingset_can_send_inst(&ts_can_single, tx_buf, tx_len, target_addr, route, callback,
callback_arg, timeout);
}

Expand Down Expand Up @@ -761,7 +770,7 @@ static void thingset_can_thread()
int err;

LOG_DBG("Initialising ThingSet CAN");
err = thingset_can_init_inst(&ts_can_single, can_dev, CONFIG_THINGSET_CAN_BUS_NUMBER);
err = thingset_can_init_inst(&ts_can_single, can_dev, CONFIG_THINGSET_CAN_DEFAULT_ROUTE);
if (err != 0) {
LOG_ERR("Failed to init ThingSet CAN: %d", err);
return;
Expand Down

0 comments on commit 22b5e7f

Please sign in to comment.