summaryrefslogtreecommitdiffstats
path: root/cpukit/include
diff options
context:
space:
mode:
authorPrashanth S <fishesprashanth@gmail.com>2022-08-07 19:23:13 +0530
committerChristian Mauderer <oss@c-mauderer.de>2022-10-30 09:35:54 +0100
commitcd91b37dce728b372f164355719a4e601e12e7b3 (patch)
treefcbd6a88dd80a68b9f2a5b40ec1fba297bc39fa3 /cpukit/include
parentbsps/riscv: Workaround for sporadic linker issues (diff)
downloadrtems-cd91b37dce728b372f164355719a4e601e12e7b3.tar.bz2
cpukit/dev/can: Added CAN support
Diffstat (limited to '')
-rw-r--r--cpukit/include/dev/can/can-msg.h105
-rw-r--r--cpukit/include/dev/can/can.h284
-rw-r--r--cpukit/include/dev/can/canqueueimpl.h231
3 files changed, 620 insertions, 0 deletions
diff --git a/cpukit/include/dev/can/can-msg.h b/cpukit/include/dev/can/can-msg.h
new file mode 100644
index 0000000000..9863e14d84
--- /dev/null
+++ b/cpukit/include/dev/can/can-msg.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup CANBus
+ *
+ * @brief Controller Area Network (CAN) Bus Implementation
+ *
+ */
+
+/*
+ * Copyright (C) 2022 Prashanth S <fishesprashanth@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_CAN_CAN_MSG_H
+#define _DEV_CAN_CAN_MSG_H
+
+/**
+ * @defgroup Controller Area Network (CAN) Driver
+ *
+ * @ingroup RTEMSDeviceDrivers
+ *
+ * @brief Controller Area Network (CAN) bus and device driver support.
+ *
+ * @{
+ */
+
+/**
+ * @defgroup CANBus CAN Bus Driver
+ *
+ * @ingroup CAN
+ *
+ * @{
+ */
+
+/**
+ * @brief CAN message size
+ */
+#define CAN_MSG_MAX_SIZE (8u)
+
+/**
+ * @brief Number of CAN tx buffers
+ */
+#define CAN_TX_BUF_COUNT (10u)
+
+/**
+ * @brief Number of CAN rx buffers
+ */
+#define CAN_RX_BUF_COUNT (2u)
+
+#define CAN_MSGLEN(msg) (sizeof(struct can_msg) - (CAN_MSG_MAX_SIZE - msg->len))
+
+/**
+ * @brief CAN message structure.
+ */
+struct can_msg {
+ /**
+ * @brief CAN message id.
+ */
+ uint32_t id;
+ /**
+ * @brief CAN message timestamp.
+ */
+ uint32_t timestamp;
+ /**
+ * @brief CAN message flags RTR | BRS | EXT.
+ */
+ uint16_t flags;
+ /**
+ * @brief CAN message length.
+ */
+ uint16_t len;
+ /**
+ * @brief CAN message.
+ */
+ uint8_t data[CAN_MSG_MAX_SIZE];
+};
+
+/** @} */ /* end of CAN message */
+
+/** @} */
+
+#endif /* _DEV_CAN_CAN_MSG_H */
diff --git a/cpukit/include/dev/can/can.h b/cpukit/include/dev/can/can.h
new file mode 100644
index 0000000000..9e55395039
--- /dev/null
+++ b/cpukit/include/dev/can/can.h
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup CANBus
+ *
+ * @brief Controller Area Network (CAN) Bus Implementation
+ *
+ */
+
+/*
+ * Copyright (C) 2022 Prashanth S (fishesprashanth@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_CAN_CAN_H
+#define _DEV_CAN_CAN_H
+
+#include <rtems/imfs.h>
+#include <rtems/thread.h>
+#include <semaphore.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dev/can/can-msg.h>
+
+#define DEBUG(str, ...) \
+ do { \
+ printf("CAN: %s:%d ID: %08X ", __FILE__, __LINE__, rtems_task_self()); \
+ printf(str, ##__VA_ARGS__); \
+ } while (false);
+
+#define CAN_DEBUG(str, ...) DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_BUF(str, ...) CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_ISR(str, ...) CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_LOCK(str, ...) CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_RX(str, ...) CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_TX(str, ...) CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_DEBUG_REG(str, ...) //CAN_DEBUG(str, ##__VA_ARGS__)
+#define CAN_ERR(str, ...) DEBUG(str, ##__VA_ARGS__)
+
+#define CAN_MSG_LEN(msg) ((char *)(&((struct can_msg *)msg)->data[(uint16_t)((struct can_msg *)msg)->len]) - (char *)(msg))
+
+/* Maximum Bus Reg (255) */
+#define CAN_BUS_REG_MAX (255)
+
+/**
+ * @defgroup Controller Area Network (CAN) Driver
+ *
+ * @ingroup RTEMSDeviceDrivers
+ *
+ * @brief Controller Area Network (CAN) bus and device driver support.
+ *
+ * @{
+ */
+
+/**
+ * @defgroup CANBus CAN Bus Driver
+ *
+ * @ingroup CAN
+ *
+ * @{
+ */
+
+/**
+ * @brief CAN tx fifo data structure.
+ */
+struct ring_buf {
+ /**
+ * @brief Pointer to array of can_msg structure.
+ */
+ struct can_msg *pbuf;
+ /**
+ * @brief Index of the next free buffer.
+ */
+ uint32_t head;
+ /**
+ * @brief Index of the produced buffer.
+ */
+ uint32_t tail;
+ /**
+ * @brief Number of empty buffers.
+ */
+ uint32_t empty_count;
+};
+
+/**
+ * @brief CAN Controller device specific operations.
+ * These function pointers are initialized by the CAN device driver while
+ * registering (can_bus_register).
+ */
+typedef struct can_dev_ops {
+ /**
+ * @brief Transfers CAN messages to device fifo.
+ *
+ * @param[in] priv device control structure.
+ * @param[in] msg can_msg message structure.
+ *
+ * @retval 0 Successful operation.
+ * @retval >0 error number in case of an error.
+ */
+ int32_t (*dev_tx)(void *priv, struct can_msg *msg);
+ /**
+ * @brief Check device is ready to transfer a CAN message
+ *
+ * @param[in] priv device control structure.
+ *
+ * @retval true device ready.
+ * @retval false device not ready.
+ */
+ bool (*dev_tx_ready)(void *priv);
+ /**
+ * @brief Enable/Disable CAN interrupts.
+ *
+ * @param[in] priv device control structure.
+ * @param[in] flag true/false to Enable/Disable CAN interrupts.
+ *
+ */
+ void (*dev_int)(void *priv, bool flag);
+ /**
+ * @brief CAN device specific I/O controls.
+ *
+ * @param[in] priv device control structure.
+ * @param[in] buffer This depends on the cmd.
+ * @param[in] cmd Device specific I/O commands.
+ *
+ * @retval 0 Depends on the cmd.
+ */
+ int32_t (*dev_ioctl)(void *priv, void *buffer, size_t cmd);
+} can_dev_ops;
+
+/**
+ * @name CAN bus control
+ *
+ * @{
+ */
+
+/**
+ * @brief Obtains the bus.
+ *
+ * This command has no argument.
+ */
+typedef struct can_bus {
+ /**
+ * @brief Device specific control.
+ */
+ void *priv;
+ /**
+ * @brief Device controller index.
+ */
+ uint8_t index;
+ /**
+ * @brief Device specific operations.
+ */
+ struct can_dev_ops *can_dev_ops;
+ /**
+ * @brief tx fifo.
+ */
+ struct ring_buf tx_fifo;
+ /**
+ * @brief Counting semaphore id (for fifo sync).
+ */
+ rtems_id tx_fifo_sem_id;
+
+ /* FIXME: Using only one CAN msg buffer, Should create a ring buffer */
+ /**
+ * @brief rx fifo.
+ */
+ struct can_msg can_rx_msg;
+ /**
+ * @brief Mutex to handle bus concurrency.
+ */
+ rtems_mutex mutex;
+ /**
+ * @brief Destroys the bus.
+ *
+ * @param[in] bus control structure.
+ */
+ void (*destroy)(struct can_bus *bus);
+#ifdef CAN_DEBUG_LOCK
+
+ /**
+ * @brief For debugging semaphore obtain/release.
+ */
+ int sem_count;
+
+#endif /* CAN_DEBUG_LOCK */
+
+} can_bus;
+
+/** @} */
+
+/**
+ * @brief Register a CAN node with the CAN bus driver.
+ *
+ * @param[in] bus bus control structure.
+ * @param[in] bus_path path of device node.
+ *
+ * @retval >=0 rtems status.
+ */
+rtems_status_code can_bus_register(can_bus *bus, const char *bus_path);
+
+/**
+ * @brief Allocate and initilaize bus control structure.
+ *
+ * @param[in] size Size of the bus control structure.
+ *
+ * @retval NULL No memory available.
+ * @retval Address Pointer to the allocated bus control structure.
+ */
+can_bus *can_bus_alloc_and_init(size_t size);
+
+/**
+ * @brief initilaize bus control structure.
+ *
+ * @param[in] bus bus control structure.
+ *
+ * @retval 0 success.
+ * @retval >0 error number.
+ */
+int can_bus_init(can_bus *bus);
+
+/**
+ * @brief Initiates CAN message transfer.
+ *
+ * Should be called with CAN interrupt disabled.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval 0 success.
+ * @retval >0 error number.
+ */
+int can_tx_done(struct can_bus *bus);
+
+/**
+ * @brief Sends the received CAN message to the application.
+ *
+ * Should be called by the device when CAN message should be sent to applicaiton.
+ * Should be called only with CAN interrupts disabled.
+ *
+ * @param[in] bus bus control structure.
+ * @param[in] msg can_msg structure.
+ *
+ * @retval 0 success.
+ * @retval >0 error number.
+ */
+int can_receive(struct can_bus *bus, struct can_msg *msg);
+
+/**
+ * @brief Prints the can_msg values pointed by msg.
+ *
+ * @param[in] msg can_msg structure.
+ *
+ */
+void can_print_msg(struct can_msg const *msg);
+
+/** @} */ /* end of CAN device driver */
+
+/** @} */
+
+#endif /* _DEV_CAN_CAN_H */
diff --git a/cpukit/include/dev/can/canqueueimpl.h b/cpukit/include/dev/can/canqueueimpl.h
new file mode 100644
index 0000000000..ef0d56fe31
--- /dev/null
+++ b/cpukit/include/dev/can/canqueueimpl.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup CANBus
+ *
+ * @brief Controller Area Network (CAN) Bus Implementation
+ *
+ */
+
+/*
+ * Copyright (C) 2022 Prashanth S <fishesprashanth@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_CAN_CAN_QUEUE_H
+#define _DEV_CAN_CAN_QUEUE_H
+
+#include <rtems/imfs.h>
+#include <rtems/thread.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dev/can/can-msg.h>
+#include <dev/can/can.h>
+
+/**
+ * @defgroup Controller Area Network (CAN) Driver
+ *
+ * @ingroup RTEMSDeviceDrivers
+ *
+ * @brief Controller Area Network (CAN) bus and device driver support.
+ *
+ * @{
+ */
+
+/**
+ * @defgroup CANBus CAN Bus Driver
+ *
+ * @ingroup CAN
+ *
+ * @{
+ */
+
+/**
+ * @brief Create CAN tx buffers.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval 0 Successful operation.
+ * @retval >0 error number in case of an error.
+ */
+static rtems_status_code can_bus_create_tx_buffers(struct can_bus *bus);
+
+/**
+ * @brief Free CAN tx buffers.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ */
+static void can_bus_free_tx_buffers(struct can_bus *bus);
+
+/**
+ * @brief Check for atleast one empty CAN tx buffer.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval true If atleast one CAN buffer is empty.
+ * @retval false If no CAN buffer is empty.
+ */
+static bool can_bus_tx_buf_is_empty(struct can_bus *bus);
+
+/**
+ * @brief Get a produced tx buffer to transmit from the tx fifo.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval can_msg Pointer to can_msg structure buffer.
+ * @retval NULL If no can_msg buffer.
+ */
+static struct can_msg *can_bus_tx_get_data_buf(struct can_bus *bus);
+
+/**
+ * @brief Get a empty tx buffer.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval can_msg Pointer to can_msg structure buffer.
+ * @retval NULL If no empty can_msg buffer.
+ */
+static struct can_msg *can_bus_tx_get_empty_buf(struct can_bus *bus);
+
+/**
+ * @brief Creates tx buffers for the CAN bus driver.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval rtems_status_code
+ */
+static rtems_status_code can_bus_create_tx_buffers(struct can_bus *bus)
+{
+ bus->tx_fifo.pbuf = (struct can_msg *)malloc(CAN_TX_BUF_COUNT *
+ sizeof(struct can_msg));
+ if (bus->tx_fifo.pbuf == NULL) {
+ CAN_ERR("can_create_tx_buffers: malloc failed\n");
+ return RTEMS_NO_MEMORY;
+ }
+
+ bus->tx_fifo.empty_count = CAN_TX_BUF_COUNT;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Free tx buffers for the CAN bus driver.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ */
+static void can_bus_free_tx_buffers(struct can_bus *bus)
+{
+ free(bus->tx_fifo.pbuf);
+}
+
+/**
+ * @brief Check if there is atleast one tx buffer in the CAN
+ * bus driver.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval true - If there is at least one free tx buffer.
+ * false - If there is no free tx buffer.
+ */
+static bool can_bus_tx_buf_is_empty(struct can_bus *bus)
+{
+ if (bus->tx_fifo.empty_count == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief To get a can_msg tx buf which contains valid data to send in
+ * in the CAN bus.
+ *
+ * Note: freeing the returned data buf is done in the same function,
+ * So the returned buffer should be sent before releasing the
+ * lock acquired while calling this function.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval *can_msg - If there is atleast one tx buffer to send in the CAN bus.
+ * NULL - If there is no valid tx buffer.
+ */
+static struct can_msg *can_bus_tx_get_data_buf(struct can_bus *bus)
+{
+ struct can_msg *msg = NULL;
+
+ if (bus->tx_fifo.empty_count == CAN_TX_BUF_COUNT ||
+ bus->tx_fifo.tail >= CAN_TX_BUF_COUNT) {
+ CAN_DEBUG_BUF("can_bus_tx_get_data_buf: All buffers are empty\n");
+ return NULL;
+ }
+
+ msg = &bus->tx_fifo.pbuf[bus->tx_fifo.tail];
+ bus->tx_fifo.empty_count++;
+ bus->tx_fifo.tail = (bus->tx_fifo.tail + 1) % CAN_TX_BUF_COUNT;
+
+ return msg;
+}
+
+/**
+ * @brief To get a can_msg tx buf which is empty (contains no valid data).
+ *
+ * Note: marking the returned buf valid is done in the same function
+ * So a valid CAN message should be copied to the returned buffer before
+ * releasing the lock acquired while calling this function.
+ *
+ * @param[in] bus Bus control structure.
+ *
+ * @retval *can_msg - If there is atleast one empty tx buffer.
+ * NULL - If there is no empty tx buffer.
+ */
+static struct can_msg *can_bus_tx_get_empty_buf(struct can_bus *bus)
+{
+ struct can_msg *msg = NULL;
+
+ /* Check whether there is a empty CAN msg buffer */
+ if (can_bus_tx_buf_is_empty(bus) == false) {
+ CAN_DEBUG_BUF("can_bus_tx_get_empty_buf: No empty buffer\n");
+ return NULL;
+ }
+
+ bus->tx_fifo.empty_count--;
+
+ /* tx_fifo.head always points to a empty buffer if there is atleast one */
+ msg = &bus->tx_fifo.pbuf[bus->tx_fifo.head];
+ bus->tx_fifo.head = (bus->tx_fifo.head + 1) % CAN_TX_BUF_COUNT;
+
+ return msg;
+}
+
+/** @} */ /* end of CAN device driver */
+
+/** @} */
+
+#endif /*_DEV_CAN_CAN_QUEUE_H */