diff --git a/os/io/can.c b/os/io/can.c new file mode 100644 index 000000000..3dd0c99c3 --- /dev/null +++ b/os/io/can.c @@ -0,0 +1,220 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file CAN.c + * @brief CAN Driver code. + * @addtogroup CAN + * @{ + */ + +#include +#include + +/** + * @brief CAN Driver initialization. + */ +void canInit(void) { + + can_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p CANDriver structure. + * + * @param[in] canp pointer to the @p CANDriver object + */ +void canObjectInit(CANDriver *canp) { + + canp->can_state = CAN_STOP; + canp->can_config = NULL; + chSemInit(&canp->can_txsem); + chSemInit(&canp->can_rxsem); + chEvtInit(&canp->can_rxfull_event); + chEvtInit(&canp->can_txempty_event); +#if CAN_USE_SLEEP_MODE + chEvtInit(&canp->can_sleep_event); + chEvtInit(&canp->can_wakeup_event); +#endif /* CAN_USE_SLEEP_MODE */ +} + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] config pointer to the @p CANConfig object + */ +void canStart(CANDriver *canp, const CANConfig *config) { + + chDbgCheck((canp != NULL) && (config != NULL), "canStart"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_STOP) || (canp->can_state == CAN_READY), + "canStart(), #1", + "invalid state"); + canp->can_config = config; + can_lld_start(canp); + canp->can_state = CAN_READY; + chSysUnlock(); +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + */ +void canStop(CANDriver *canp) { + + chDbgCheck(canp != NULL, "canStop"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_STOP) || (canp->can_state == CAN_READY), + "canStop(), #1", + "invalid state"); + can_lld_stop(canp); + canp->can_state = CAN_STOP; + chSysUnlock(); +} + +/** + * @brief Can frame transmission. + * @details The specified frame is queued for transmission, if the hardware + * queue is full then the invoking thread is queued. + * @note Trying to transmit while in sleep mode simply enqueues the thread. + * + * @param canp[in] pointer to the @p CANDriver object + * @param cfp[in] pointer to the CAN frame to be transmitted + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The operation result. + * @retval RDY_OK the frame has been queued for transmission. + * @retval RDY_TIMEOUT operation not finished within the specified time. + * @retval RDY_RESET driver stopped while waiting. + */ +msg_t canTransmit(CANDriver *canp, const CANFrame *cfp, systime_t timeout) { + msg_t msg; + + chDbgCheck((canp != NULL) && (cfp != NULL), "canTransmit"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_READY) || (canp->can_state == CAN_SLEEP), + "canTransmit(), #1", + "invalid state"); + if ((canp->can_state == CAN_SLEEP) || !can_lld_can_transmit(canp)) { + msg = chSemWaitTimeoutS(&canp->can_txsem, timeout); + if (msg != RDY_OK) { + chSysUnlock(); + return msg; + } + } + msg = can_lld_transmit(canp, cfp); + chSysUnlock(); + return msg; +} + +/** + * @brief Can frame receive. + * @details The function waits until a frame is received. + * @note Trying to receive while in sleep mode simply enqueues the thread. + * + * @param canp[in] pointer to the @p CANDriver object + * @param cfp[out] pointer to the buffer where the CAN frame is copied + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The operation result. + * @retval RDY_OK a frame has been received and placed in the buffer. + * @retval RDY_TIMEOUT operation not finished within the specified time. + * @retval RDY_RESET driver stopped while waiting. + */ +msg_t canReceive(CANDriver *canp, CANFrame *cfp, systime_t timeout) { + msg_t msg; + + chDbgCheck((canp != NULL) && (cfp != NULL), "canReceive"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_READY) || (canp->can_state == CAN_SLEEP), + "canReceive(), #1", + "invalid state"); + if ((canp->can_state == CAN_SLEEP) || !can_lld_can_receive(canp)) { + msg = chSemWaitTimeoutS(&canp->can_rxsem, timeout); + if (msg != RDY_OK) { + chSysUnlock(); + return msg; + } + } + msg = can_lld_receive(canp, cfp); + chSysUnlock(); + return msg; +} + +#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) +/** + * @brief Enters the sleep mode. + * + * @param canp[in] pointer to the @p CANDriver object + */ +void canSleep(CANDriver *canp) { + + chDbgCheck(canp != NULL, "canSleep"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_READY) || (canp->can_state == CAN_SLEEP), + "canSleep(), #1", + "invalid state"); + if (canp->can_state = CAN_READY) { + can_lld_sleep(canp); + canp->can_state = CAN_SLEEP; + chEvtBroadcastI(&canp->can_sleep_event); + chSchRescheduleS(); + } + chSysUnlock(); +} + +/** + * @brief Enforces leaving the sleep mode. + * @note The sleep mode is supposed to be usually exited automatically by an + * hardware event. + * + * @param canp[in] pointer to the @p CANDriver object + */ +void canWakeup(CANDriver *canp) { + + chDbgCheck(canp != NULL, "canWakeup"); + + chSysLock(); + chDbgAssert((canp->can_state == CAN_READY) || (canp->can_state == CAN_SLEEP), + "canWakeup(), #1", + "invalid state"); + if (canp->can_state = CAN_SLEEP) { + can_lld_wakeup(canp); + canp->can_state = CAN_READY; + chEvtBroadcastI(&canp->can_wakeup_event); + chSchRescheduleS(); + } + chSysUnlock(); +} +#endif /* CAN_USE_SLEEP_MODE */ + +/** @} */ diff --git a/os/io/can.h b/os/io/can.h new file mode 100644 index 000000000..9d9462f86 --- /dev/null +++ b/os/io/can.h @@ -0,0 +1,61 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file can.h + * @brief CAN Driver macros and structures. + * @addtogroup CAN + * @{ + */ + +#ifndef _CAN_H_ +#define _CAN_H_ + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + CAN_UNINIT = 0, /**< @brief Not initialized. */ + CAN_STOP = 1, /**< @brief Stopped. */ + CAN_READY = 2, /**< @brief Ready. */ + CAN_SLEEP = 3 /**< @brief Sleep state. */ +} canstate_t; + +#include "can_lld.h" + +#ifdef __cplusplus +extern "C" { +#endif + void canInit(void); + void canObjectInit(CANDriver *canp); + void canStart(CANDriver *canp, const CANConfig *config); + void canStop(CANDriver *canp); + msg_t canTransmit(CANDriver *canp, const CANFrame *cfp, systime_t timeout); + msg_t canReceive(CANDriver *canp, CANFrame *cfp, systime_t timeout); +#if CAN_USE_SLEEP_MODE + void canSleep(CANDriver *canp); + void canWakeup(CANDriver *canp); +#endif /* CAN_USE_SLEEP_MODE */ +#ifdef __cplusplus +} +#endif + +#endif /* _CAN_H_ */ + +/** @} */ diff --git a/os/io/templates/can_lld.c b/os/io/templates/can_lld.c new file mode 100644 index 000000000..4fc0ae7d0 --- /dev/null +++ b/os/io/templates/can_lld.c @@ -0,0 +1,155 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file templates/can_lld.c + * @brief CAN Driver subsystem low level driver source template + * @addtogroup CAN_LLD + * @{ + */ + +#include +#include + +/*===========================================================================*/ +/* Low Level Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Low Level Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Low Level Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Low Level Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Low Level Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CAN driver initialization. + */ +void can_lld_init(void) { + +} + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + */ +void can_lld_start(CANDriver *canp) { + + if (canp->can_state == CAN_STOP) { + /* Clock activation.*/ + } + /* Configuration.*/ +} + +/** + * @brief Deactivates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + */ +void can_lld_stop(CANDriver *canp) { + +} + +/** + * @brief Determines whether a frame can be transmitted. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @return The queue space availability. + * @retval FALSE no space in the transmit queue. + * @retval TRUE transmit slot available. + */ +bool_t can_lld_can_transmit(CANDriver *canp) { + + return false; +} + +/** + * @brief Inserts a frame into the transmit queue. + * + * @param canp[in] pointer to the @p CANDriver object + * @param cfp[in] pointer to the CAN frame to be transmitted + * + * @return The operation status. + * @retval RDY_OK frame transmitted. + */ +msg_t can_lld_transmit(CANDriver *canp, const CANFrame *cfp) { + + return RDY_OK; +} + +/** + * @brief Determines whether a frame has been received. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @return The queue space availability. + * @retval FALSE no space in the transmit queue. + * @retval TRUE transmit slot available. + */ +bool_t can_lld_can_receive(CANDriver *canp) { + + return false; +} + +/** + * @brief Receives a frame from the input queue. + * + * @param canp[in] pointer to the @p CANDriver object + * @param cfp[out] pointer to the buffer where the CAN frame is copied + * + * @return The operation status. + * @retval RDY_OK frame received. + */ +msg_t can_lld_receive(CANDriver *canp, CANFrame *cfp) { + + return RDY_OK; +} + +#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) +/** + * @brief Enters the sleep mode. + * + * @param canp[in] pointer to the @p CANDriver object + */ +void can_lld_sleep(CANDriver *canp) { + +} + +/** + * @brief Enforces leaving the sleep mode. + * + * @param canp[in] pointer to the @p CANDriver object + */ +void can_lld_wakeup(CANDriver *canp) { + +} +#endif /* CAN_USE_SLEEP_MODE */ + +/** @} */ diff --git a/os/io/templates/can_lld.h b/os/io/templates/can_lld.h new file mode 100644 index 000000000..fcd8631a9 --- /dev/null +++ b/os/io/templates/can_lld.h @@ -0,0 +1,134 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file templates/can_lld.h + * @brief CAN Driver subsystem low level driver header template + * @addtogroup CAN_LLD + * @{ + */ + +#ifndef _CAN_LLD_H_ +#define _CAN_LLD_H_ + +/** + * @brief This switch defines whether the driver implementation supports + * a low power switch mode with automatic an wakeup feature. + */ +#define CAN_SUPPORTS_SLEEP TRUE + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + * @note This switch is enforced to @p FALSE if the driver implementation + * does not support the sleep mode. + */ +#if CAN_SUPPORTS_SLEEP || defined(__DOXYGEN__) +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif +#else /* !CAN_SUPPORTS_SLEEP */ +#define CAN_USE_SLEEP_MODE FALSE +#endif /* !CAN_SUPPORTS_SLEEP */ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + +} CANConfig; + +/** + * @brief Structure representing an CAN driver. + */ +typedef struct { + /** + * @brief Driver state. + */ + canstate_t can_state; + /** + * @brief Current configuration data. + */ + const CANConfig *can_config; + /** + * @brief Transmission queue semaphore. + */ + Semaphore can_txsem; + /** + * @brief Receive queue semaphore. + */ + Semaphore can_rxsem; + /** + * @brief One or more frames become available. + */ + EventSource can_rxfull_event; + /** + * @brief One or more transmission slots become available. + */ + EventSource can_txempty_event; +#if CAN_USE_SLEEP_MODE || defined __DOXYGEN__) + /** + * @brief Entering sleep state event. + */ + EventSource can_sleep_event; + /** + * @brief Exiting sleep state event. + */ + EventSource can_wakeup_event; +#endif /* CAN_USE_SLEEP_MODE */ + /* End of the mandatory fields.*/ +} CANDriver; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void can_lld_init(void); + void can_lld_start(CANDriver *canp); + void can_lld_stop(CANDriver *canp); + bool_t can_lld_can_transmit(CANDriver *canp); + msg_t can_lld_transmit(CANDriver *canp, const CANFrame *cfp); + bool_t can_lld_can_receive(CANDriver *canp); + msg_t can_lld_receive(CANDriver *canp, CANFrame *cfp); +#if CAN_USE_SLEEP_MODE + void can_lld_sleep(CANDriver *canp); + void can_lld_wakeup(CANDriver *canp); +#endif /* CAN_USE_SLEEP_MODE */ +#ifdef __cplusplus +} +#endif + +#endif /* _CAN_LLD_H_ */ + +/** @} */