From 408aa71c971684560a1a07af6bf59e3c56b83d54 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 29 Nov 2009 08:26:06 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1343 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/haltmp/src/can.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 os/haltmp/src/can.c (limited to 'os/haltmp/src/can.c') diff --git a/os/haltmp/src/can.c b/os/haltmp/src/can.c new file mode 100644 index 000000000..bb3e0d1a5 --- /dev/null +++ b/os/haltmp/src/can.c @@ -0,0 +1,224 @@ +/* + 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 "ch.h" +#include "hal.h" + +#if CH_HAL_USE_CAN + +/** + * @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, 0); + chSemInit(&canp->can_rxsem, 0); + 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[in] canp pointer to the @p CANDriver object + * @param[in] cfp 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[in] canp pointer to the @p CANDriver object + * @param[out] cfp 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[in] canp 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[in] canp 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 */ + +#endif /* CH_HAL_USE_CAN */ + +/** @} */ -- cgit v1.2.3