2019-03-18 17:19:35 +01:00
|
|
|
/*
|
2021-12-16 15:23:05 +01:00
|
|
|
* Copyright (c) 2021 Vestas Wind Systems A/S
|
2019-03-18 17:19:35 +01:00
|
|
|
* Copyright (c) 2018 Alexander Wachter
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
#define DT_DRV_COMPAT zephyr_can_loopback
|
|
|
|
|
2019-03-18 17:19:35 +01:00
|
|
|
#include <stdbool.h>
|
2021-12-16 15:23:05 +01:00
|
|
|
#include <string.h>
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/can.h>
|
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
LOG_MODULE_REGISTER(can_loopback, CONFIG_CAN_LOG_LEVEL);
|
2020-02-12 15:36:47 +01:00
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_frame {
|
2022-08-11 15:31:59 +02:00
|
|
|
struct can_frame frame;
|
2020-02-12 15:36:47 +01:00
|
|
|
can_tx_callback_t cb;
|
|
|
|
void *cb_arg;
|
|
|
|
};
|
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_filter {
|
|
|
|
can_rx_callback_t rx_cb;
|
|
|
|
void *cb_arg;
|
2022-08-11 15:31:59 +02:00
|
|
|
struct can_filter filter;
|
2021-12-16 15:23:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct can_loopback_data {
|
|
|
|
struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER];
|
|
|
|
struct k_mutex mtx;
|
|
|
|
struct k_msgq tx_msgq;
|
|
|
|
char msgq_buffer[CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE * sizeof(struct can_loopback_frame)];
|
|
|
|
struct k_thread tx_thread_data;
|
2022-08-31 14:28:42 +02:00
|
|
|
bool started;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
bool loopback;
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
bool fd;
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
2021-12-16 15:23:05 +01:00
|
|
|
|
|
|
|
K_KERNEL_STACK_MEMBER(tx_thread_stack,
|
|
|
|
CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE);
|
|
|
|
};
|
2020-02-12 15:36:47 +01:00
|
|
|
|
2022-10-31 12:54:18 +01:00
|
|
|
static void receive_frame(const struct device *dev,
|
|
|
|
const struct can_frame *frame,
|
|
|
|
struct can_loopback_filter *filter)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2022-08-11 15:31:59 +02:00
|
|
|
struct can_frame frame_tmp = *frame;
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2020-02-12 15:36:47 +01:00
|
|
|
LOG_DBG("Receiving %d bytes. Id: 0x%x, ID type: %s %s",
|
2020-11-19 20:46:56 +01:00
|
|
|
frame->dlc, frame->id,
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
(frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard",
|
|
|
|
(frame->flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : "");
|
2020-02-12 15:36:47 +01:00
|
|
|
|
2022-03-17 22:06:51 +01:00
|
|
|
filter->rx_cb(dev, &frame_tmp, filter->cb_arg);
|
2019-03-18 17:19:35 +01:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static void tx_thread(void *arg1, void *arg2, void *arg3)
|
2020-02-12 15:36:47 +01:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
const struct device *dev = arg1;
|
|
|
|
struct can_loopback_data *data = dev->data;
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_frame frame;
|
2020-02-12 15:36:47 +01:00
|
|
|
struct can_loopback_filter *filter;
|
2023-01-24 17:01:17 +01:00
|
|
|
int ret;
|
2022-03-17 22:06:51 +01:00
|
|
|
|
|
|
|
ARG_UNUSED(arg2);
|
|
|
|
ARG_UNUSED(arg3);
|
2020-02-12 15:36:47 +01:00
|
|
|
|
|
|
|
while (1) {
|
2023-01-24 17:01:17 +01:00
|
|
|
ret = k_msgq_get(&data->tx_msgq, &frame, K_FOREVER);
|
|
|
|
if (ret < 0) {
|
|
|
|
LOG_DBG("Pend on TX queue returned without valid frame (err %d)", ret);
|
|
|
|
continue;
|
|
|
|
}
|
2022-10-31 12:52:18 +01:00
|
|
|
frame.cb(dev, 0, frame.cb_arg);
|
|
|
|
|
|
|
|
if (!data->loopback) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-02-12 15:36:47 +01:00
|
|
|
k_mutex_lock(&data->mtx, K_FOREVER);
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2020-02-12 15:36:47 +01:00
|
|
|
for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) {
|
|
|
|
filter = &data->filters[i];
|
2022-10-31 12:54:18 +01:00
|
|
|
if (filter->rx_cb != NULL &&
|
2023-02-07 10:26:19 +01:00
|
|
|
can_frame_matches_filter(&frame.frame, &filter->filter)) {
|
2022-10-31 12:54:18 +01:00
|
|
|
receive_frame(dev, &frame.frame, filter);
|
2020-02-12 15:36:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
k_mutex_unlock(&data->mtx);
|
|
|
|
}
|
|
|
|
}
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_loopback_send(const struct device *dev,
|
2022-08-11 15:31:59 +02:00
|
|
|
const struct can_frame *frame,
|
2022-03-30 15:09:31 +02:00
|
|
|
k_timeout_t timeout, can_tx_callback_t callback,
|
|
|
|
void *user_data)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
struct can_loopback_frame loopback_frame;
|
2022-07-18 13:23:17 +02:00
|
|
|
uint8_t max_dlc = CAN_MAX_DLC;
|
|
|
|
int ret;
|
2020-02-12 15:36:47 +01:00
|
|
|
|
2022-09-20 17:21:21 +02:00
|
|
|
__ASSERT_NO_MSG(callback != NULL);
|
|
|
|
|
2020-02-12 15:36:47 +01:00
|
|
|
LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s",
|
2020-11-19 20:46:56 +01:00
|
|
|
frame->dlc, dev->name, frame->id,
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
(frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard",
|
|
|
|
(frame->flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : "");
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR |
|
|
|
|
CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((frame->flags & CAN_FRAME_FDF) != 0) {
|
|
|
|
if (!data->fd) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
max_dlc = CANFD_MAX_DLC;
|
|
|
|
}
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
#else /* CONFIG_CAN_FD_MODE */
|
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_CAN_FD_MODE */
|
2022-07-18 13:23:17 +02:00
|
|
|
|
|
|
|
if (frame->dlc > max_dlc) {
|
|
|
|
LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, max_dlc);
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EINVAL;
|
2019-11-06 10:03:20 +01:00
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (!data->started) {
|
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2020-02-12 15:36:47 +01:00
|
|
|
loopback_frame.frame = *frame;
|
|
|
|
loopback_frame.cb = callback;
|
2021-12-04 15:21:32 +01:00
|
|
|
loopback_frame.cb_arg = user_data;
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
ret = k_msgq_put(&data->tx_msgq, &loopback_frame, timeout);
|
2022-10-31 12:57:03 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
LOG_DBG("TX queue full (err %d)", ret);
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2022-10-31 12:57:03 +01:00
|
|
|
return 0;
|
2019-03-18 17:19:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int get_free_filter(struct can_loopback_filter *filters)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) {
|
|
|
|
if (filters[i].rx_cb == NULL) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2019-03-18 17:19:35 +01:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_loopback_add_rx_filter(const struct device *dev, can_rx_callback_t cb,
|
2022-08-11 15:31:59 +02:00
|
|
|
void *cb_arg, const struct can_filter *filter)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_data *data = dev->data;
|
2019-03-18 17:19:35 +01:00
|
|
|
struct can_loopback_filter *loopback_filter;
|
|
|
|
int filter_id;
|
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask);
|
|
|
|
|
2022-11-09 11:23:54 +07:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA |
|
|
|
|
CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0) {
|
|
|
|
#else
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) {
|
2022-11-09 11:23:54 +07:00
|
|
|
#endif
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2019-03-18 17:19:35 +01:00
|
|
|
|
|
|
|
k_mutex_lock(&data->mtx, K_FOREVER);
|
|
|
|
filter_id = get_free_filter(data->filters);
|
|
|
|
|
|
|
|
if (filter_id < 0) {
|
|
|
|
LOG_ERR("No free filter left");
|
|
|
|
k_mutex_unlock(&data->mtx);
|
|
|
|
return filter_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
loopback_filter = &data->filters[filter_id];
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
loopback_filter->rx_cb = cb;
|
2019-03-18 17:19:35 +01:00
|
|
|
loopback_filter->cb_arg = cb_arg;
|
|
|
|
loopback_filter->filter = *filter;
|
|
|
|
k_mutex_unlock(&data->mtx);
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
LOG_DBG("Filter added. ID: %d", filter_id);
|
2019-03-18 17:19:35 +01:00
|
|
|
|
|
|
|
return filter_id;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static void can_loopback_remove_rx_filter(const struct device *dev, int filter_id)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_data *data = dev->data;
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2022-10-31 12:58:46 +01:00
|
|
|
if (filter_id >= ARRAY_SIZE(data->filters)) {
|
|
|
|
LOG_ERR("filter ID %d out-of-bounds", filter_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
LOG_DBG("Remove filter ID: %d", filter_id);
|
2019-03-18 17:19:35 +01:00
|
|
|
k_mutex_lock(&data->mtx, K_FOREVER);
|
|
|
|
data->filters[filter_id].rx_cb = NULL;
|
|
|
|
k_mutex_unlock(&data->mtx);
|
|
|
|
}
|
|
|
|
|
2022-07-12 16:36:20 +02:00
|
|
|
static int can_loopback_get_capabilities(const struct device *dev, can_mode_t *cap)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
|
|
|
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK;
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
#if CONFIG_CAN_FD_MODE
|
|
|
|
*cap |= CAN_MODE_FD;
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
|
|
|
|
2022-07-12 16:36:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
static int can_loopback_start(const struct device *dev)
|
|
|
|
{
|
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
|
|
|
|
if (data->started) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->started = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_loopback_stop(const struct device *dev)
|
|
|
|
{
|
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
|
|
|
|
if (!data->started) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->started = false;
|
|
|
|
|
2023-01-24 17:01:17 +01:00
|
|
|
k_msgq_purge(&data->tx_msgq);
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-05 11:28:30 +02:00
|
|
|
static int can_loopback_set_mode(const struct device *dev, can_mode_t mode)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_data *data = dev->data;
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (data->started) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) {
|
|
|
|
LOG_ERR("unsupported mode: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
|
|
|
|
data->fd = (mode & CAN_MODE_FD) != 0;
|
2022-07-18 13:23:17 +02:00
|
|
|
#else
|
|
|
|
if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) {
|
|
|
|
LOG_ERR("unsupported mode: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
data->loopback = (mode & CAN_MODE_LOOPBACK) != 0;
|
|
|
|
|
2019-03-18 17:19:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_loopback_set_timing(const struct device *dev,
|
2022-05-03 22:05:53 +02:00
|
|
|
const struct can_timing *timing)
|
2020-04-27 18:58:05 +02:00
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
ARG_UNUSED(timing);
|
2022-05-03 22:05:53 +02:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (data->started) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
static int can_loopback_set_timing_data(const struct device *dev,
|
|
|
|
const struct can_timing *timing)
|
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
ARG_UNUSED(timing);
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (data->started) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:23:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
static int can_loopback_get_state(const struct device *dev, enum can_state *state,
|
|
|
|
struct can_bus_err_cnt *err_cnt)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_loopback_data *data = dev->data;
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
if (state != NULL) {
|
2022-08-31 14:28:42 +02:00
|
|
|
if (data->started) {
|
|
|
|
*state = CAN_STATE_ERROR_ACTIVE;
|
|
|
|
} else {
|
|
|
|
*state = CAN_STATE_STOPPED;
|
|
|
|
}
|
2022-01-19 10:21:01 +01:00
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
if (err_cnt) {
|
|
|
|
err_cnt->tx_err_cnt = 0;
|
|
|
|
err_cnt->rx_err_cnt = 0;
|
|
|
|
}
|
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
return 0;
|
2018-06-19 18:26:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_loopback_recover(const struct device *dev, k_timeout_t timeout)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_loopback_data *data = dev->data;
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
ARG_UNUSED(timeout);
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (!data->started) {
|
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
static void can_loopback_set_state_change_callback(const struct device *dev,
|
2022-01-10 12:32:19 +01:00
|
|
|
can_state_change_callback_t cb,
|
|
|
|
void *user_data)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
2021-12-28 20:00:34 +01:00
|
|
|
ARG_UNUSED(cb);
|
2022-01-10 12:32:19 +01:00
|
|
|
ARG_UNUSED(user_data);
|
2018-06-19 18:26:31 +02:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_loopback_get_core_clock(const struct device *dev, uint32_t *rate)
|
2020-04-27 18:58:05 +02:00
|
|
|
{
|
|
|
|
/* Return 16MHz as an realistic value for the testcases */
|
|
|
|
*rate = 16000000;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
static int can_loopback_get_max_filters(const struct device *dev, bool ide)
|
2021-10-12 11:46:44 +02:00
|
|
|
{
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
ARG_UNUSED(ide);
|
2021-10-12 11:46:44 +02:00
|
|
|
|
|
|
|
return CONFIG_CAN_MAX_FILTER;
|
|
|
|
}
|
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
static const struct can_driver_api can_loopback_driver_api = {
|
2022-07-12 16:36:20 +02:00
|
|
|
.get_capabilities = can_loopback_get_capabilities,
|
2022-08-31 14:28:42 +02:00
|
|
|
.start = can_loopback_start,
|
|
|
|
.stop = can_loopback_stop,
|
2020-04-27 18:58:05 +02:00
|
|
|
.set_mode = can_loopback_set_mode,
|
|
|
|
.set_timing = can_loopback_set_timing,
|
2019-03-18 17:19:35 +01:00
|
|
|
.send = can_loopback_send,
|
2021-12-28 20:00:34 +01:00
|
|
|
.add_rx_filter = can_loopback_add_rx_filter,
|
|
|
|
.remove_rx_filter = can_loopback_remove_rx_filter,
|
2018-06-19 18:26:31 +02:00
|
|
|
.get_state = can_loopback_get_state,
|
|
|
|
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
|
|
|
.recover = can_loopback_recover,
|
|
|
|
#endif
|
2021-12-28 20:00:34 +01:00
|
|
|
.set_state_change_callback = can_loopback_set_state_change_callback,
|
2020-04-27 18:58:05 +02:00
|
|
|
.get_core_clock = can_loopback_get_core_clock,
|
2021-10-12 11:46:44 +02:00
|
|
|
.get_max_filters = can_loopback_get_max_filters,
|
2020-04-27 18:58:05 +02:00
|
|
|
.timing_min = {
|
|
|
|
.sjw = 0x1,
|
2020-12-10 15:13:26 +01:00
|
|
|
.prop_seg = 0x01,
|
2020-04-27 18:58:05 +02:00
|
|
|
.phase_seg1 = 0x01,
|
|
|
|
.phase_seg2 = 0x01,
|
|
|
|
.prescaler = 0x01
|
|
|
|
},
|
|
|
|
.timing_max = {
|
|
|
|
.sjw = 0x0F,
|
|
|
|
.prop_seg = 0x0F,
|
|
|
|
.phase_seg1 = 0x0F,
|
|
|
|
.phase_seg2 = 0x0F,
|
|
|
|
.prescaler = 0xFFFF
|
2022-07-18 13:23:17 +02:00
|
|
|
},
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
.set_timing_data = can_loopback_set_timing_data,
|
|
|
|
.timing_data_min = {
|
|
|
|
.sjw = 0x1,
|
|
|
|
.prop_seg = 0x01,
|
|
|
|
.phase_seg1 = 0x01,
|
|
|
|
.phase_seg2 = 0x01,
|
|
|
|
.prescaler = 0x01
|
|
|
|
},
|
|
|
|
.timing_data_max = {
|
|
|
|
.sjw = 0x0F,
|
|
|
|
.prop_seg = 0x0F,
|
|
|
|
.phase_seg1 = 0x0F,
|
|
|
|
.phase_seg2 = 0x0F,
|
|
|
|
.prescaler = 0xFFFF
|
|
|
|
},
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
2019-03-18 17:19:35 +01:00
|
|
|
};
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int can_loopback_init(const struct device *dev)
|
2019-03-18 17:19:35 +01:00
|
|
|
{
|
2021-12-16 15:23:05 +01:00
|
|
|
struct can_loopback_data *data = dev->data;
|
2020-02-12 15:36:47 +01:00
|
|
|
k_tid_t tx_tid;
|
2019-03-18 17:19:35 +01:00
|
|
|
|
|
|
|
k_mutex_init(&data->mtx);
|
|
|
|
|
|
|
|
for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) {
|
|
|
|
data->filters[i].rx_cb = NULL;
|
|
|
|
}
|
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
k_msgq_init(&data->tx_msgq, data->msgq_buffer, sizeof(struct can_loopback_frame),
|
|
|
|
CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE);
|
|
|
|
|
|
|
|
tx_tid = k_thread_create(&data->tx_thread_data, data->tx_thread_stack,
|
|
|
|
K_KERNEL_STACK_SIZEOF(data->tx_thread_stack),
|
2022-03-17 22:06:51 +01:00
|
|
|
tx_thread, (void *)dev, NULL, NULL,
|
2020-02-12 15:36:47 +01:00
|
|
|
CONFIG_CAN_LOOPBACK_TX_THREAD_PRIORITY,
|
|
|
|
0, K_NO_WAIT);
|
|
|
|
if (!tx_tid) {
|
|
|
|
LOG_ERR("ERROR spawning tx thread");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-03-09 12:49:07 +01:00
|
|
|
LOG_INF("Init of %s done", dev->name);
|
|
|
|
|
2019-03-18 17:19:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
#define CAN_LOOPBACK_INIT(inst) \
|
|
|
|
static struct can_loopback_data can_loopback_dev_data_##inst; \
|
|
|
|
\
|
|
|
|
DEVICE_DT_INST_DEFINE(inst, &can_loopback_init, NULL, \
|
|
|
|
&can_loopback_dev_data_##inst, NULL, \
|
|
|
|
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \
|
|
|
|
&can_loopback_driver_api);
|
2019-03-18 17:19:35 +01:00
|
|
|
|
2021-12-16 15:23:05 +01:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT)
|