diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/include/dev/can/can-msg.h | 105 | ||||
-rw-r--r-- | cpukit/include/dev/can/can.h | 284 | ||||
-rw-r--r-- | cpukit/include/dev/can/canqueueimpl.h | 231 |
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 */ |