zoukankan      html  css  js  c++  java
  • ChibiOS/RT 2.6.9 CAN Driver

    Detailed Description

    Generic CAN Driver.

    This module implements a generic CAN (Controller Area Network) driver allowing the exchange of information at frame level.

    Precondition:
    In order to use the CAN driver the HAL_USE_CAN option must be enabled in halconf.h.

    Driver State Machine

    The driver implements a state machine internally, not all the driver functionalities can be used in any moment,

    any transition not explicitly shown in the following diagram has to be considered an error and shall be captured by an assertion (if enabled).

    00001 /*
    00002     ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
    00003 
    00004     Licensed under the Apache License, Version 2.0 (the "License");
    00005     you may not use this file except in compliance with the License.
    00006     You may obtain a copy of the License at
    00007 
    00008         http://www.apache.org/licenses/LICENSE-2.0
    00009 
    00010     Unless required by applicable law or agreed to in writing, software
    00011     distributed under the License is distributed on an "AS IS" BASIS,
    00012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    00013     See the License for the specific language governing permissions and
    00014     limitations under the License.
    00015 */
    00016 
    00017 /**
    00018  * @file    templates/can_lld.h
    00019  * @brief   CAN Driver subsystem low level driver header template.
    00020  *
    00021  * @addtogroup CAN
    00022  * @{
    00023  */
    00024 
    00025 #ifndef _CAN_LLD_H_
    00026 #define _CAN_LLD_H_
    00027 
    00028 #if HAL_USE_CAN || defined(__DOXYGEN__)
    00029 
    00030 /*===========================================================================*/
    00031 /* Driver constants.                                                         */
    00032 /*===========================================================================*/
    00033 
    00034 /**
    00035  * @brief   This switch defines whether the driver implementation supports
    00036  *          a low power switch mode with automatic an wakeup feature.
    00037  */
    00038 #define CAN_SUPPORTS_SLEEP          TRUE
    00039 
    00040 /**
    00041  * @brief   This implementation supports three transmit mailboxes.
    00042  */
    00043 #define CAN_TX_MAILBOXES            3
    00044 
    00045 /**
    00046  * @brief   This implementation supports two receive mailboxes.
    00047  */
    00048 #define CAN_RX_MAILBOXES            2
    00049 
    00050 /*===========================================================================*/
    00051 /* Driver pre-compile time settings.                                         */
    00052 /*===========================================================================*/
    00053 
    00054 /**
    00055  * @name    Configuration options
    00056  * @{
    00057  */
    00058 /**
    00059  * @brief   CAN1 driver enable switch.
    00060  * @details If set to @p TRUE the support for CAN1 is included.
    00061  */
    00062 #if !defined(PLATFORM_CAN_USE_CAN1) || defined(__DOXYGEN__)
    00063 #define PLATFORM_CAN_USE_CAN1               FALSE
    00064 #endif
    00065 /** @} */
    00066 
    00067 /*===========================================================================*/
    00068 /* Derived constants and error checks.                                       */
    00069 /*===========================================================================*/
    00070 
    00071 #if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP
    00072 #error "CAN sleep mode not supported in this architecture"
    00073 #endif
    00074 
    00075 /*===========================================================================*/
    00076 /* Driver data structures and types.                                         */
    00077 /*===========================================================================*/
    00078 
    00079 /**
    00080  * @brief   Type of a transmission mailbox index.
    00081  */
    00082 typedef uint32_t canmbx_t;
    00083 
    00084 /**
    00085  * @brief   CAN transmission frame.
    00086  * @note    Accessing the frame data as word16 or word32 is not portable because
    00087  *          machine data endianness, it can be still useful for a quick filling.
    00088  */
    00089 typedef struct {
    00090   struct {
    00091     uint8_t                 DLC:4;          /**< @brief Data length.        */
    00092     uint8_t                 RTR:1;          /**< @brief Frame type.         */
    00093     uint8_t                 IDE:1;          /**< @brief Identifier type.    */
    00094   };
    00095   union {
    00096     struct {
    00097       uint32_t              SID:11;         /**< @brief Standard identifier.*/
    00098     };
    00099     struct {
    00100       uint32_t              EID:29;         /**< @brief Extended identifier.*/
    00101     };
    00102   };
    00103   union {
    00104     uint8_t                 data8[8];       /**< @brief Frame data.         */
    00105     uint16_t                data16[4];      /**< @brief Frame data.         */
    00106     uint32_t                data32[2];      /**< @brief Frame data.         */
    00107   };
    00108 } CANTxFrame;
    00109 
    00110 /**
    00111  * @brief   CAN received frame.
    00112  * @note    Accessing the frame data as word16 or word32 is not portable because
    00113  *          machine data endianness, it can be still useful for a quick filling.
    00114  */
    00115 typedef struct {
    00116   struct {
    00117     uint8_t                 DLC:4;          /**< @brief Data length.        */
    00118     uint8_t                 RTR:1;          /**< @brief Frame type.         */
    00119     uint8_t                 IDE:1;          /**< @brief Identifier type.    */
    00120   };
    00121   union {
    00122     struct {
    00123       uint32_t              SID:11;         /**< @brief Standard identifier.*/
    00124     };
    00125     struct {
    00126       uint32_t              EID:29;         /**< @brief Extended identifier.*/
    00127     };
    00128   };
    00129   union {
    00130     uint8_t                 data8[8];       /**< @brief Frame data.         */
    00131     uint16_t                data16[4];      /**< @brief Frame data.         */
    00132     uint32_t                data32[2];      /**< @brief Frame data.         */
    00133   };
    00134 } CANRxFrame;
    00135 
    00136 /**
    00137  * @brief   CAN filter.
    00138  * @note    Implementations may extend this structure to contain more,
    00139  *          architecture dependent, fields.
    00140  * @note    It could not be present on some architectures.
    00141  */
    00142 typedef struct {
    00143   uint32_t                  dummy;
    00144 } CANFilter;
    00145 
    00146 /**
    00147  * @brief   Driver configuration structure.
    00148  * @note    Implementations may extend this structure to contain more,
    00149  *          architecture dependent, fields.
    00150  * @note    It could be empty on some architectures.
    00151  */
    00152 typedef struct {
    00153   uint32_t                  dummy;
    00154 } CANConfig;
    00155 
    00156 /**
    00157  * @brief   Structure representing an CAN driver.
    00158  */
    00159 typedef struct {
    00160   /**
    00161    * @brief   Driver state.
    00162    */
    00163   canstate_t                state;
    00164   /**
    00165    * @brief   Current configuration data.
    00166    */
    00167   const CANConfig           *config;
    00168   /**
    00169    * @brief   Transmission queue semaphore.
    00170    */
    00171   Semaphore                 txsem;
    00172   /**
    00173    * @brief   Receive queue semaphore.
    00174    */
    00175   Semaphore                 rxsem;
    00176   /**
    00177    * @brief   One or more frames become available.
    00178    * @note    After broadcasting this event it will not be broadcasted again
    00179    *          until the received frames queue has been completely emptied. It
    00180    *          is <b>not</b> broadcasted for each received frame. It is
    00181    *          responsibility of the application to empty the queue by
    00182    *          repeatedly invoking @p chReceive() when listening to this event.
    00183    *          This behavior minimizes the interrupt served by the system
    00184    *          because CAN traffic.
    00185    * @note    The flags associated to the listeners will indicate which
    00186    *          receive mailboxes become non-empty.
    00187    */
    00188   EventSource               rxfull_event;
    00189   /**
    00190    * @brief   One or more transmission mailbox become available.
    00191    * @note    The flags associated to the listeners will indicate which
    00192    *          transmit mailboxes become empty.
    00193    *
    00194    */
    00195   EventSource               txempty_event;
    00196   /**
    00197    * @brief   A CAN bus error happened.
    00198    * @note    The flags associated to the listeners will indicate the
    00199    *          error(s) that have occurred.
    00200    */
    00201   EventSource               error_event;
    00202 #if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__)
    00203   /**
    00204    * @brief   Entering sleep state event.
    00205    */
    00206   EventSource               sleep_event;
    00207   /**
    00208    * @brief   Exiting sleep state event.
    00209    */
    00210   EventSource               wakeup_event;
    00211 #endif /* CAN_USE_SLEEP_MODE */
    00212   /* End of the mandatory fields.*/
    00213 } CANDriver;
    00214 
    00215 /*===========================================================================*/
    00216 /* Driver macros.                                                            */
    00217 /*===========================================================================*/
    00218 
    00219 /*===========================================================================*/
    00220 /* External declarations.                                                    */
    00221 /*===========================================================================*/
    00222 
    00223 #if PLATFORM_CAN_USE_CAN1 && !defined(__DOXYGEN__)
    00224 extern CANDriver CAND1;
    00225 #endif
    00226 
    00227 #ifdef __cplusplus
    00228 extern "C" {
    00229 #endif
    00230   void can_lld_init(void);
    00231   void can_lld_start(CANDriver *canp);
    00232   void can_lld_stop(CANDriver *canp);
    00233   bool_t can_lld_is_tx_empty(CANDriver *canp,
    00234                              canmbx_t mailbox);
    00235   void can_lld_transmit(CANDriver *canp,
    00236                         canmbx_t mailbox,
    00237                         const CANTxFrame *crfp);
    00238   bool_t can_lld_is_rx_nonempty(CANDriver *canp,
    00239                                 canmbx_t mailbox);
    00240   void can_lld_receive(CANDriver *canp,
    00241                        canmbx_t mailbox,
    00242                        CANRxFrame *ctfp);
    00243 #if CAN_USE_SLEEP_MODE
    00244   void can_lld_sleep(CANDriver *canp);
    00245   void can_lld_wakeup(CANDriver *canp);
    00246 #endif /* CAN_USE_SLEEP_MODE */
    00247 #ifdef __cplusplus
    00248 }
    00249 #endif
    00250 
    00251 #endif /* HAL_USE_CAN */
    00252 
    00253 #endif /* _CAN_LLD_H_ */
    00254 
    00255 /** @} */
    00001 /*
    00002     ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
    00003 
    00004     Licensed under the Apache License, Version 2.0 (the "License");
    00005     you may not use this file except in compliance with the License.
    00006     You may obtain a copy of the License at
    00007 
    00008         http://www.apache.org/licenses/LICENSE-2.0
    00009 
    00010     Unless required by applicable law or agreed to in writing, software
    00011     distributed under the License is distributed on an "AS IS" BASIS,
    00012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    00013     See the License for the specific language governing permissions and
    00014     limitations under the License.
    00015 */
    00016 
    00017 /**
    00018  * @file    templates/can_lld.c
    00019  * @brief   CAN Driver subsystem low level driver source template.
    00020  *
    00021  * @addtogroup CAN
    00022  * @{
    00023  */
    00024 
    00025 #include "ch.h"
    00026 #include "hal.h"
    00027 
    00028 #if HAL_USE_CAN || defined(__DOXYGEN__)
    00029 
    00030 /*===========================================================================*/
    00031 /* Driver local definitions.                                                 */
    00032 /*===========================================================================*/
    00033 
    00034 /*===========================================================================*/
    00035 /* Driver exported variables.                                                */
    00036 /*===========================================================================*/
    00037 
    00038 /**
    00039  * @brief   CAN1 driver identifier.
    00040  */
    00041 #if PLATFORM_CAN_USE_CAN1 || defined(__DOXYGEN__)
    00042 CANDriver CAND1;
    00043 #endif
    00044 
    00045 /*===========================================================================*/
    00046 /* Driver local variables and types.                                         */
    00047 /*===========================================================================*/
    00048 
    00049 /*===========================================================================*/
    00050 /* Driver local functions.                                                   */
    00051 /*===========================================================================*/
    00052 
    00053 /*===========================================================================*/
    00054 /* Driver interrupt handlers.                                                */
    00055 /*===========================================================================*/
    00056 
    00057 /*===========================================================================*/
    00058 /* Driver exported functions.                                                */
    00059 /*===========================================================================*/
    00060 
    00061 /**
    00062  * @brief   Low level CAN driver initialization.
    00063  *
    00064  * @notapi
    00065  */
    00066 void can_lld_init(void) {
    00067 
    00068 #if PLATFORM_CAN_USE_CAN1
    00069   /* Driver initialization.*/
    00070   canObjectInit(&CAND1);
    00071 #endif /* PLATFORM_CAN_USE_CAN1 */
    00072 }
    00073 
    00074 /**
    00075  * @brief   Configures and activates the CAN peripheral.
    00076  *
    00077  * @param[in] canp      pointer to the @p CANDriver object
    00078  *
    00079  * @notapi
    00080  */
    00081 void can_lld_start(CANDriver *canp) {
    00082 
    00083   if (canp->state == CAN_STOP) {
    00084     /* Enables the peripheral.*/
    00085 #if PLATFORM_CAN_USE_CAN1
    00086     if (&CAND1 == canp) {
    00087 
    00088     }
    00089 #endif /* PLATFORM_CAN_USE_CAN1 */
    00090   }
    00091   /* Configures the peripheral.*/
    00092 
    00093 }
    00094 
    00095 /**
    00096  * @brief   Deactivates the CAN peripheral.
    00097  *
    00098  * @param[in] canp      pointer to the @p CANDriver object
    00099  *
    00100  * @notapi
    00101  */
    00102 void can_lld_stop(CANDriver *canp) {
    00103 
    00104   if (canp->state == CAN_READY) {
    00105     /* Resets the peripheral.*/
    00106 
    00107     /* Disables the peripheral.*/
    00108 #if PLATFORM_CAN_USE_CAN1
    00109     if (&CAND1 == canp) {
    00110 
    00111     }
    00112 #endif /* PLATFORM_CAN_USE_CAN1 */
    00113   }
    00114 }
    00115 
    00116 /**
    00117  * @brief   Determines whether a frame can be transmitted.
    00118  *
    00119  * @param[in] canp      pointer to the @p CANDriver object
    00120  * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
    00121  *
    00122  * @return              The queue space availability.
    00123  * @retval FALSE        no space in the transmit queue.
    00124  * @retval TRUE         transmit slot available.
    00125  *
    00126  * @notapi
    00127  */
    00128 bool_t can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) {
    00129 
    00130   (void)canp;
    00131 
    00132   switch (mailbox) {
    00133   case CAN_ANY_MAILBOX:
    00134     return FALSE;
    00135   case 1:
    00136     return FALSE;
    00137   case 2:
    00138     return FALSE;
    00139   case 3:
    00140     return FALSE;
    00141   default:
    00142     return FALSE;
    00143   }
    00144 }
    00145 
    00146 /**
    00147  * @brief   Inserts a frame into the transmit queue.
    00148  *
    00149  * @param[in] canp      pointer to the @p CANDriver object
    00150  * @param[in] ctfp      pointer to the CAN frame to be transmitted
    00151  * @param[in] mailbox   mailbox number,  @p CAN_ANY_MAILBOX for any mailbox
    00152  *
    00153  * @notapi
    00154  */
    00155 void can_lld_transmit(CANDriver *canp,
    00156                       canmbx_t mailbox,
    00157                       const CANTxFrame *ctfp) {
    00158 
    00159   (void)canp;
    00160   (void)mailbox;
    00161   (void)ctfp;
    00162 
    00163 }
    00164 
    00165 /**
    00166  * @brief   Determines whether a frame has been received.
    00167  *
    00168  * @param[in] canp      pointer to the @p CANDriver object
    00169  * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
    00170  *
    00171  * @return              The queue space availability.
    00172  * @retval FALSE        no space in the transmit queue.
    00173  * @retval TRUE         transmit slot available.
    00174  *
    00175  * @notapi
    00176  */
    00177 bool_t can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) {
    00178 
    00179   (void)canp;
    00180   (void)mailbox;
    00181 
    00182   switch (mailbox) {
    00183   case CAN_ANY_MAILBOX:
    00184     return FALSE;
    00185   case 1:
    00186     return FALSE;
    00187   case 2:
    00188     return FALSE;
    00189   default:
    00190     return FALSE;
    00191   }
    00192 }
    00193 
    00194 /**
    00195  * @brief   Receives a frame from the input queue.
    00196  *
    00197  * @param[in] canp      pointer to the @p CANDriver object
    00198  * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
    00199  * @param[out] crfp     pointer to the buffer where the CAN frame is copied
    00200  *
    00201  * @notapi
    00202  */
    00203 void can_lld_receive(CANDriver *canp,
    00204                      canmbx_t mailbox,
    00205                      CANRxFrame *crfp) {
    00206 
    00207   (void)canp;
    00208   (void)mailbox;
    00209   (void)crfp;
    00210 
    00211 }
    00212 
    00213 #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
    00214 /**
    00215  * @brief   Enters the sleep mode.
    00216  *
    00217  * @param[in] canp      pointer to the @p CANDriver object
    00218  *
    00219  * @notapi
    00220  */
    00221 void can_lld_sleep(CANDriver *canp) {
    00222 
    00223   (void)canp;
    00224 
    00225 }
    00226 
    00227 /**
    00228  * @brief   Enforces leaving the sleep mode.
    00229  *
    00230  * @param[in] canp      pointer to the @p CANDriver object
    00231  *
    00232  * @notapi
    00233  */
    00234 void can_lld_wakeup(CANDriver *canp) {
    00235 
    00236   (void)canp;
    00237 
    00238 }
    00239 #endif /* CAN_USE_SLEEP_MODE */
    00240 
    00241 #endif /* HAL_USE_CAN */
    00242 
    00243 /** @} */
    00001 /*
    00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
    00003                  2011,2012,2013 Giovanni Di Sirio.
    00004 
    00005     This file is part of ChibiOS/RT.
    00006 
    00007     ChibiOS/RT is free software; you can redistribute it and/or modify
    00008     it under the terms of the GNU General Public License as published by
    00009     the Free Software Foundation; either version 3 of the License, or
    00010     (at your option) any later version.
    00011 
    00012     ChibiOS/RT is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00015     GNU General Public License for more details.
    00016 
    00017     You should have received a copy of the GNU General Public License
    00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
    00019 
    00020                                       ---
    00021 
    00022     A special exception to the GPL can be applied should you wish to distribute
    00023     a combined work that includes ChibiOS/RT, without being obliged to provide
    00024     the source code for any proprietary components. See the file exception.txt
    00025     for full details of how and when the exception can be applied.
    00026 */
    00027 
    00028 /**
    00029  * @file    can.h
    00030  * @brief   CAN Driver macros and structures.
    00031  *
    00032  * @addtogroup CAN
    00033  * @{
    00034  */
    00035 
    00036 #ifndef _CAN_H_
    00037 #define _CAN_H_
    00038 
    00039 #if HAL_USE_CAN || defined(__DOXYGEN__)
    00040 
    00041 /*===========================================================================*/
    00042 /* Driver constants.                                                         */
    00043 /*===========================================================================*/
    00044 
    00045 /**
    00046  * @name    CAN status flags
    00047  * @{
    00048  */
    00049 /**
    00050  * @brief   Errors rate warning.
    00051  */
    00052 #define CAN_LIMIT_WARNING           1
    00053 /**
    00054  * @brief   Errors rate error.
    00055  */
    00056 #define CAN_LIMIT_ERROR             2
    00057 /**
    00058  * @brief   Bus off condition reached.
    00059  */
    00060 #define CAN_BUS_OFF_ERROR           4
    00061 /**
    00062  * @brief   Framing error of some kind on the CAN bus.
    00063  */
    00064 #define CAN_FRAMING_ERROR           8
    00065 /**
    00066  * @brief   Overflow in receive queue.
    00067  */
    00068 #define CAN_OVERFLOW_ERROR          16
    00069 /** @} */
    00070 
    00071 /**
    00072  * @brief   Special mailbox identifier.
    00073  */
    00074 #define CAN_ANY_MAILBOX             0
    00075 
    00076 /*===========================================================================*/
    00077 /* Driver pre-compile time settings.                                         */
    00078 /*===========================================================================*/
    00079 
    00080 /**
    00081  * @name    CAN configuration options
    00082  * @{
    00083  */
    00084 /**
    00085  * @brief   Sleep mode related APIs inclusion switch.
    00086  * @details This option can only be enabled if the CAN implementation supports
    00087  *          the sleep mode, see the macro @p CAN_SUPPORTS_SLEEP exported by
    00088  *          the underlying implementation.
    00089  */
    00090 #if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
    00091 #define CAN_USE_SLEEP_MODE          TRUE
    00092 #endif
    00093 /** @} */
    00094 
    00095 /*===========================================================================*/
    00096 /* Derived constants and error checks.                                       */
    00097 /*===========================================================================*/
    00098 
    00099 #if !CH_USE_SEMAPHORES || !CH_USE_EVENTS
    00100 #error "CAN driver requires CH_USE_SEMAPHORES and CH_USE_EVENTS"
    00101 #endif
    00102 
    00103 /*===========================================================================*/
    00104 /* Driver data structures and types.                                         */
    00105 /*===========================================================================*/
    00106 
    00107 /**
    00108  * @brief   Driver state machine possible states.
    00109  */
    00110 typedef enum {
    00111   CAN_UNINIT = 0,                           /**< Not initialized.           */
    00112   CAN_STOP = 1,                             /**< Stopped.                   */
    00113   CAN_STARTING = 2,                         /**< Starting.                  */
    00114   CAN_READY = 3,                            /**< Ready.                     */
    00115   CAN_SLEEP = 4                             /**< Sleep state.               */
    00116 } canstate_t;
    00117 
    00118 #include "can_lld.h"
    00119 
    00120 /*===========================================================================*/
    00121 /* Driver macros.                                                            */
    00122 /*===========================================================================*/
    00123 
    00124 /**
    00125  * @name    Macro Functions
    00126  * @{
    00127  */
    00128 /**
    00129  * @brief   Converts a mailbox index to a bit mask.
    00130  */
    00131 #define CAN_MAILBOX_TO_MASK(mbx) (1 << ((mbx) - 1))
    00132 /** @} */
    00133 
    00134 /*===========================================================================*/
    00135 /* External declarations.                                                    */
    00136 /*===========================================================================*/
    00137 
    00138 #ifdef __cplusplus
    00139 extern "C" {
    00140 #endif
    00141   void canInit(void);
    00142   void canObjectInit(CANDriver *canp);
    00143   void canStart(CANDriver *canp, const CANConfig *config);
    00144   void canStop(CANDriver *canp);
    00145   msg_t canTransmit(CANDriver *canp,
    00146                     canmbx_t mailbox,
    00147                     const CANTxFrame *ctfp,
    00148                     systime_t timeout);
    00149   msg_t canReceive(CANDriver *canp,
    00150                    canmbx_t mailbox,
    00151                    CANRxFrame *crfp,
    00152                    systime_t timeout);
    00153 #if CAN_USE_SLEEP_MODE
    00154   void canSleep(CANDriver *canp);
    00155   void canWakeup(CANDriver *canp);
    00156 #endif /* CAN_USE_SLEEP_MODE */
    00157 #ifdef __cplusplus
    00158 }
    00159 #endif
    00160 
    00161 #endif /* HAL_USE_CAN */
    00162 
    00163 #endif /* _CAN_H_ */
    00164 
    00165 /** @} */
    00001 /*
    00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
    00003                  2011,2012,2013 Giovanni Di Sirio.
    00004 
    00005     This file is part of ChibiOS/RT.
    00006 
    00007     ChibiOS/RT is free software; you can redistribute it and/or modify
    00008     it under the terms of the GNU General Public License as published by
    00009     the Free Software Foundation; either version 3 of the License, or
    00010     (at your option) any later version.
    00011 
    00012     ChibiOS/RT is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00015     GNU General Public License for more details.
    00016 
    00017     You should have received a copy of the GNU General Public License
    00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
    00019 
    00020                                       ---
    00021 
    00022     A special exception to the GPL can be applied should you wish to distribute
    00023     a combined work that includes ChibiOS/RT, without being obliged to provide
    00024     the source code for any proprietary components. See the file exception.txt
    00025     for full details of how and when the exception can be applied.
    00026 */
    00027 
    00028 /**
    00029  * @file    can.c
    00030  * @brief   CAN Driver code.
    00031  *
    00032  * @addtogroup CAN
    00033  * @{
    00034  */
    00035 
    00036 #include "ch.h"
    00037 #include "hal.h"
    00038 
    00039 #if HAL_USE_CAN || defined(__DOXYGEN__)
    00040 
    00041 /*===========================================================================*/
    00042 /* Driver local definitions.                                                 */
    00043 /*===========================================================================*/
    00044 
    00045 /*===========================================================================*/
    00046 /* Driver exported variables.                                                */
    00047 /*===========================================================================*/
    00048 
    00049 /*===========================================================================*/
    00050 /* Driver local variables and types.                                         */
    00051 /*===========================================================================*/
    00052 
    00053 /*===========================================================================*/
    00054 /* Driver local functions.                                                   */
    00055 /*===========================================================================*/
    00056 
    00057 /*===========================================================================*/
    00058 /* Driver exported functions.                                                */
    00059 /*===========================================================================*/
    00060 
    00061 /**
    00062  * @brief   CAN Driver initialization.
    00063  * @note    This function is implicitly invoked by @p halInit(), there is
    00064  *          no need to explicitly initialize the driver.
    00065  *
    00066  * @init
    00067  */
    00068 void canInit(void) {
    00069 
    00070   can_lld_init();
    00071 }
    00072 
    00073 /**
    00074  * @brief   Initializes the standard part of a @p CANDriver structure.
    00075  *
    00076  * @param[out] canp     pointer to the @p CANDriver object
    00077  *
    00078  * @init
    00079  */
    00080 void canObjectInit(CANDriver *canp) {
    00081 
    00082   canp->state    = CAN_STOP;
    00083   canp->config   = NULL;
    00084   chSemInit(&canp->txsem, 0);
    00085   chSemInit(&canp->rxsem, 0);
    00086   chEvtInit(&canp->rxfull_event);
    00087   chEvtInit(&canp->txempty_event);
    00088   chEvtInit(&canp->error_event);
    00089 #if CAN_USE_SLEEP_MODE
    00090   chEvtInit(&canp->sleep_event);
    00091   chEvtInit(&canp->wakeup_event);
    00092 #endif /* CAN_USE_SLEEP_MODE */
    00093 }
    00094 
    00095 /**
    00096  * @brief   Configures and activates the CAN peripheral.
    00097  * @note    Activating the CAN bus can be a slow operation this this function
    00098  *          is not atomic, it waits internally for the initialization to
    00099  *          complete.
    00100  *
    00101  * @param[in] canp      pointer to the @p CANDriver object
    00102  * @param[in] config    pointer to the @p CANConfig object. Depending on
    00103  *                      the implementation the value can be @p NULL.
    00104  *
    00105  * @api
    00106  */
    00107 void canStart(CANDriver *canp, const CANConfig *config) {
    00108 
    00109   chDbgCheck(canp != NULL, "canStart");
    00110 
    00111   chSysLock();
    00112   chDbgAssert((canp->state == CAN_STOP) ||
    00113               (canp->state == CAN_STARTING) ||
    00114               (canp->state == CAN_READY),
    00115               "canStart(), #1", "invalid state");
    00116   while (canp->state == CAN_STARTING)
    00117     chThdSleepS(1);
    00118   if (canp->state == CAN_STOP) {
    00119     canp->config = config;
    00120     can_lld_start(canp);
    00121     canp->state = CAN_READY;
    00122   }
    00123   chSysUnlock();
    00124 }
    00125 
    00126 /**
    00127  * @brief   Deactivates the CAN peripheral.
    00128  *
    00129  * @param[in] canp      pointer to the @p CANDriver object
    00130  *
    00131  * @api
    00132  */
    00133 void canStop(CANDriver *canp) {
    00134 
    00135   chDbgCheck(canp != NULL, "canStop");
    00136 
    00137   chSysLock();
    00138   chDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY),
    00139               "canStop(), #1", "invalid state");
    00140   can_lld_stop(canp);
    00141   canp->state  = CAN_STOP;
    00142   chSemResetI(&canp->rxsem, 0);
    00143   chSemResetI(&canp->txsem, 0);
    00144   chSchRescheduleS();
    00145   chSysUnlock();
    00146 }
    00147 
    00148 /**
    00149  * @brief   Can frame transmission.
    00150  * @details The specified frame is queued for transmission, if the hardware
    00151  *          queue is full then the invoking thread is queued.
    00152  * @note    Trying to transmit while in sleep mode simply enqueues the thread.
    00153  *
    00154  * @param[in] canp      pointer to the @p CANDriver object
    00155  * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
    00156  * @param[in] ctfp      pointer to the CAN frame to be transmitted
    00157  * @param[in] timeout   the number of ticks before the operation timeouts,
    00158  *                      the following special values are allowed:
    00159  *                      - @a TIME_IMMEDIATE immediate timeout.
    00160  *                      - @a TIME_INFINITE no timeout.
    00161  *                      .
    00162  * @return              The operation result.
    00163  * @retval RDY_OK       the frame has been queued for transmission.
    00164  * @retval RDY_TIMEOUT  The operation has timed out.
    00165  * @retval RDY_RESET    The driver has been stopped while waiting.
    00166  *
    00167  * @api
    00168  */
    00169 msg_t canTransmit(CANDriver *canp,
    00170                   canmbx_t mailbox,
    00171                   const CANTxFrame *ctfp,
    00172                   systime_t timeout) {
    00173 
    00174   chDbgCheck((canp != NULL) && (ctfp != NULL) && (mailbox <= CAN_TX_MAILBOXES),
    00175              "canTransmit");
    00176 
    00177   chSysLock();
    00178   chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
    00179               "canTransmit(), #1", "invalid state");
    00180   while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) {
    00181     msg_t msg = chSemWaitTimeoutS(&canp->txsem, timeout);
    00182     if (msg != RDY_OK) {
    00183       chSysUnlock();
    00184       return msg;
    00185     }
    00186   }
    00187   can_lld_transmit(canp, mailbox, ctfp);
    00188   chSysUnlock();
    00189   return RDY_OK;
    00190 }
    00191 
    00192 /**
    00193  * @brief   Can frame receive.
    00194  * @details The function waits until a frame is received.
    00195  * @note    Trying to receive while in sleep mode simply enqueues the thread.
    00196  *
    00197  * @param[in] canp      pointer to the @p CANDriver object
    00198  * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
    00199  * @param[out] crfp     pointer to the buffer where the CAN frame is copied
    00200  * @param[in] timeout   the number of ticks before the operation timeouts,
    00201  *                      the following special values are allowed:
    00202  *                      - @a TIME_IMMEDIATE immediate timeout (useful in an
    00203  *                        event driven scenario where a thread never blocks
    00204  *                        for I/O).
    00205  *                      - @a TIME_INFINITE no timeout.
    00206  *                      .
    00207  * @return              The operation result.
    00208  * @retval RDY_OK       a frame has been received and placed in the buffer.
    00209  * @retval RDY_TIMEOUT  The operation has timed out.
    00210  * @retval RDY_RESET    The driver has been stopped while waiting.
    00211  *
    00212  * @api
    00213  */
    00214 msg_t canReceive(CANDriver *canp,
    00215                  canmbx_t mailbox,
    00216                  CANRxFrame *crfp,
    00217                  systime_t timeout) {
    00218 
    00219   chDbgCheck((canp != NULL) && (crfp != NULL) && (mailbox <= CAN_RX_MAILBOXES),
    00220              "canReceive");
    00221 
    00222   chSysLock();
    00223   chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
    00224               "canReceive(), #1", "invalid state");
    00225   while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) {
    00226     msg_t msg = chSemWaitTimeoutS(&canp->rxsem, timeout);
    00227     if (msg != RDY_OK) {
    00228       chSysUnlock();
    00229       return msg;
    00230     }
    00231   }
    00232   can_lld_receive(canp, mailbox, crfp);
    00233   chSysUnlock();
    00234   return RDY_OK;
    00235 }
    00236 
    00237 #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
    00238 /**
    00239  * @brief   Enters the sleep mode.
    00240  * @details This function puts the CAN driver in sleep mode and broadcasts
    00241  *          the @p sleep_event event source.
    00242  * @pre     In order to use this function the option @p CAN_USE_SLEEP_MODE must
    00243  *          be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported
    00244  *          by the low level driver.
    00245  *
    00246  * @param[in] canp      pointer to the @p CANDriver object
    00247  *
    00248  * @api
    00249  */
    00250 void canSleep(CANDriver *canp) {
    00251 
    00252   chDbgCheck(canp != NULL, "canSleep");
    00253 
    00254   chSysLock();
    00255   chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
    00256               "canSleep(), #1", "invalid state");
    00257   if (canp->state == CAN_READY) {
    00258     can_lld_sleep(canp);
    00259     canp->state = CAN_SLEEP;
    00260     chEvtBroadcastI(&canp->sleep_event);
    00261     chSchRescheduleS();
    00262   }
    00263   chSysUnlock();
    00264 }
    00265 
    00266 /**
    00267  * @brief   Enforces leaving the sleep mode.
    00268  * @note    The sleep mode is supposed to be usually exited automatically by
    00269  *          an hardware event.
    00270  *
    00271  * @param[in] canp      pointer to the @p CANDriver object
    00272  */
    00273 void canWakeup(CANDriver *canp) {
    00274 
    00275   chDbgCheck(canp != NULL, "canWakeup");
    00276 
    00277   chSysLock();
    00278   chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP),
    00279               "canWakeup(), #1", "invalid state");
    00280   if (canp->state == CAN_SLEEP) {
    00281     can_lld_wakeup(canp);
    00282     canp->state = CAN_READY;
    00283     chEvtBroadcastI(&canp->wakeup_event);
    00284     chSchRescheduleS();
    00285   }
    00286   chSysUnlock();
    00287 }
    00288 #endif /* CAN_USE_SLEEP_MODE */
    00289 
    00290 #endif /* HAL_USE_CAN */
    00291 
    00292 /** @} */

    void canInit(void )

    CAN Driver initialization.

    Note:
    This function is implicitly invoked by halInit(), there is no need to explicitly initialize the driver.
    Function Class:
    Initializer, this function just initializes an object and can be invoked before the kernel is initialized.

    Here is the call graph for this function:

    void canObjectInit ( CANDriver * canp )

    Initializes the standard part of a CANDriver structure.

    Function Class:
    Initializer, this function just initializes an object and can be invoked before the kernel is initialized.
     
    void canStart ( CANDriver * canp, const CANConfig * config )

    Configures and activates the CAN peripheral.

    Note:
    Activating the CAN bus can be a slow operation this this function is not atomic, it waits internally for the initialization to complete.

    Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.

    void canStop ( CANDriver * canp )

    Deactivates the CAN peripheral.

    Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.

    msg_t canTransmit ( CANDriver * canp, canmbx_t mailbox, const CANTxFrame * ctfp, systime_t timeout )

    Can frame transmission.

    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.

    Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.

    msg_t canReceive ( CANDriver * canp, canmbx_t mailbox, CANRxFrame * crfp, systime_t timeout )

    Can frame receive.

    The function waits until a frame is received.

    Note:
    Trying to receive while in sleep mode simply enqueues the thread.

    Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.

    void canSleep ( CANDriver * canp )

    Enters the sleep mode.

    This function puts the CAN driver in sleep mode and broadcasts the sleep_event event source.

    Precondition:
    In order to use this function the option CAN_USE_SLEEP_MODE must be enabled
    and the CAN_SUPPORTS_SLEEP mode must be supported by the low level driver.

    Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.

    void canWakeup ( CANDriver * canp )

    Enforces leaving the sleep mode.

    Note:
    The sleep mode is supposed to be usually exited automatically by an hardware event.
    /**
     * This switch defines whether the driver implementation supports
     *          a low power switch mode with automatic an wakeup feature.
     */
    #define CAN_SUPPORTS_SLEEP          TRUE
    
    /**
     * This implementation supports three transmit mailboxes.
     */
    #define CAN_TX_MAILBOXES            3
    
    /**
     * This implementation supports two receive mailboxes.
     */
    #define CAN_RX_MAILBOXES            2
    
    /*===========================================================================*/
    /* Driver pre-compile time settings.                                         */
    /*===========================================================================*/
    
    /**
     * @name    Configuration options
     * @{
     */
    /**
     * CAN1 driver enable switch.
     * @details If set to @p TRUE the support for CAN1 is included.
     */
    #if !defined(PLATFORM_CAN_USE_CAN1) || defined(__DOXYGEN__)
    #define PLATFORM_CAN_USE_CAN1               FALSE
    #endif
    
    /*===========================================================================*/
    /* Derived constants and error checks.                                       */
    /*===========================================================================*/
    
    #if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP
    #error "CAN sleep mode not supported in this architecture"
    #endif
    
    /*===========================================================================*/
    /* Driver data structures and types.                                         */
    /*===========================================================================*/
    
    /**
     * Type of a transmission mailbox index.
     */
    typedef uint32_t canmbx_t;
    
    /**
     * CAN transmission frame.
     * @note    Accessing the frame data as word16 or word32 is not portable because
     *          machine data endianness, it can be still useful for a quick filling.
     */
    typedef struct
    {
      struct
      {
        uint8_t DLC :4; /**< @brief Data length.        */
        uint8_t RTR :1; /**< @brief Frame type.         */
        uint8_t IDE :1; /**< @brief Identifier type.    */
      };
      union
      {
        struct
        {
          uint32_t SID :11; /**< @brief Standard identifier.*/
        };
        struct
        {
          uint32_t EID :29; /**< @brief Extended identifier.*/
        };
      };
      union
      {
        uint8_t data8[ 8 ]; /**< @brief Frame data.         */
        uint16_t data16[ 4 ]; /**< @brief Frame data.         */
        uint32_t data32[ 2 ]; /**< @brief Frame data.         */
      };
    } CANTxFrame;
    
    /**
     * CAN received frame.
     * @note    Accessing the frame data as word16 or word32 is not portable because
     *          machine data endianness, it can be still useful for a quick filling.
     */
    typedef struct
    {
      struct
      {
        uint8_t DLC :4; /**< @brief Data length.        */
        uint8_t RTR :1; /**< @brief Frame type.         */
        uint8_t IDE :1; /**< @brief Identifier type.    */
      };
      union
      {
        struct
        {
          uint32_t SID :11; /**< @brief Standard identifier.*/
        };
        struct
        {
          uint32_t EID :29; /**< @brief Extended identifier.*/
        };
      };
      union
      {
        uint8_t data8[ 8 ]; /**< @brief Frame data.         */
        uint16_t data16[ 4 ]; /**< @brief Frame data.         */
        uint32_t data32[ 2 ]; /**< @brief Frame data.         */
      };
    } CANRxFrame;
    
    /**
     * CAN filter.
     * @note    Implementations may extend this structure to contain more,
     *          architecture dependent, fields.
     * @note    It could not be present on some architectures.
     */
    typedef struct
    {
      uint32_t dummy;
    } CANFilter;
    
    /**
     * Driver configuration structure.
     * @note    Implementations may extend this structure to contain more,
     *          architecture dependent, fields.
     * @note    It could be empty on some architectures.
     */
    typedef struct
    {
      uint32_t dummy;
    } CANConfig;
    
    /**
     * Structure representing an CAN driver.
     */
    typedef struct
    {
      /**
       * Driver state.
       */
      canstate_t state;
      /**
       * Current configuration data.
       */
      const CANConfig *config;
      /**
       * Transmission queue semaphore.
       */
      Semaphore txsem;
      /**
       * Receive queue semaphore.
       */
      Semaphore rxsem;
      /**
       * One or more frames become available.
       * @note    After broadcasting this event it will not be broadcasted again
       *          until the received frames queue has been completely emptied. It
       *          is <b>not</b> broadcasted for each received frame. It is
       *          responsibility of the application to empty the queue by
       *          repeatedly invoking @p chReceive() when listening to this event.
       *          This behavior minimizes the interrupt served by the system
       *          because CAN traffic.
       * @note    The flags associated to the listeners will indicate which
       *          receive mailboxes become non-empty.
       */
      EventSource rxfull_event;
      /**
       * One or more transmission mailbox become available.
       * @note    The flags associated to the listeners will indicate which
       *          transmit mailboxes become empty.
       *
       */
      EventSource txempty_event;
      /**
       * A CAN bus error happened.
       * @note    The flags associated to the listeners will indicate the
       *          error(s) that have occurred.
       */
      EventSource error_event;
      /**
       * Entering sleep state event.
       */
      EventSource sleep_event;
      /**
       * Exiting sleep state event.
       */
      EventSource wakeup_event;
    /* End of the mandatory fields.*/
    } CANDriver;
    
    extern CANDriver CAND1;
    void can_lld_init( void );
    void can_lld_start( CANDriver *canp );
    void can_lld_stop( CANDriver *canp );
    uiknt32_t can_lld_is_tx_empty( CANDriver *canp, canmbx_t mailbox );
    void can_lld_transmit( CANDriver *canp, canmbx_t mailbox,
      const CANTxFrame *crfp );
    uiknt32_t can_lld_is_rx_nonempty( CANDriver *canp, canmbx_t mailbox );
    void can_lld_receive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *ctfp );
    void can_lld_sleep( CANDriver *canp );
    void can_lld_wakeup( CANDriver *canp );
    
    /**
     * @file    templates/can_lld.c
     * CAN Driver subsystem low level driver source template.
     *
     * @addtogroup CAN
     * @{
     */
    
    /**
     * CAN1 driver identifier.
     */
    CANDriver CAND1;
    
    /**
     * Low level CAN driver initialization.
     *
     * @notapi
     */
    void can_lld_init( void )
    {
      /* Driver initialization.*/
      canObjectInit( &CAND1 );
    }
    
    /**
     * Configures and activates the CAN peripheral.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @notapi
     */
    void can_lld_start( CANDriver *canp )
    {
      if ( canp->state == CAN_STOP )
      {
        /* Enables the peripheral.*/
        if ( &CAND1 == canp )
        {
        }    
      }
      /* Configures the peripheral.*/
    
    }
    
    /**
     * Deactivates the CAN peripheral.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @notapi
     */
    void can_lld_stop( CANDriver *canp )
    {  
      if ( canp->state == CAN_READY )
      {
        /* Resets the peripheral.*/
        /* Disables the peripheral.*/
        if ( &CAND1 == canp )
        {      
        }    
      }
    }
    
    /**
     * Determines whether a frame can be transmitted.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
     *
     * @return              The queue space availability.
     * @retval FALSE        no space in the transmit queue.
     * @retval TRUE         transmit slot available.
     *
     * @notapi
     */
    uiknt32_t can_lld_is_tx_empty( CANDriver *canp, canmbx_t mailbox )
    {
      (void) canp;  
      switch ( mailbox )
      {
        case CAN_ANY_MAILBOX:
          return FALSE;
        case 1:
          return FALSE;
        case 2:
          return FALSE;
        case 3:
          return FALSE;
        default:
          return FALSE;
      }
    }
    
    /**
     * Inserts a frame into the transmit queue.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     * @param[in] ctfp      pointer to the CAN frame to be transmitted
     * @param[in] mailbox   mailbox number,  @p CAN_ANY_MAILBOX for any mailbox
     *
     * @notapi
     */
    void can_lld_transmit( CANDriver *canp, canmbx_t mailbox,
      const CANTxFrame *ctfp )
    {  
      (void) canp;
      (void) mailbox;
      (void) ctfp;
      
    }
    
    /**
     * Determines whether a frame has been received.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
     *
     * @return              The queue space availability.
     * @retval FALSE        no space in the transmit queue.
     * @retval TRUE         transmit slot available.
     *
     * @notapi
     */
    uiknt32_t can_lld_is_rx_nonempty( CANDriver *canp, canmbx_t mailbox )
    {  
      (void) canp;
      (void) mailbox;
      
      switch ( mailbox )
      {
        case CAN_ANY_MAILBOX:
          return FALSE;
        case 1:
          return FALSE;
        case 2:
          return FALSE;
        default:
          return FALSE;
      }
    }
    
    /**
     * Receives a frame from the input queue.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     * @param[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
     * @param[out] crfp     pointer to the buffer where the CAN frame is copied
     *
     * @notapi
     */
    void can_lld_receive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp )
    {  
      (void) canp;
      (void) mailbox;
      (void) crfp;  
    }
    
    /**
     * Enters the sleep mode.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @notapi
     */
    void can_lld_sleep( CANDriver *canp )
    {  
      (void) canp;  
    }
    
    /**
     * Enforces leaving the sleep mode.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @notapi
     */
    void can_lld_wakeup( CANDriver *canp )
    {  
      (void) canp;
      
    }
    
    /**
     * @name    CAN status flags
     * @{
     */
    /**
     * Errors rate warning.
     */
    #define CAN_LIMIT_WARNING           1
    /**
     * Errors rate error.
     */
    #define CAN_LIMIT_ERROR             2
    /**
     * Bus off condition reached.
     */
    #define CAN_BUS_OFF_ERROR           4
    /**
     * Framing error of some kind on the CAN bus.
     */
    #define CAN_FRAMING_ERROR           8
    /**
     * Overflow in receive queue.
     */
    #define CAN_OVERFLOW_ERROR          16
    
    /**
     * Special mailbox identifier.
     */
    #define CAN_ANY_MAILBOX             0
    
    /**
     * @name    CAN configuration options
     * @{
     */
    /**
     * Sleep mode related APIs inclusion switch.
     * @details This option can only be enabled if the CAN implementation supports
     *          the sleep mode, see the macro @p CAN_SUPPORTS_SLEEP exported by
     *          the underlying implementation.
     */
    
    #define CAN_USE_SLEEP_MODE          TRUE
    
    /**
     * Driver state machine possible states.
     */
    typedef enum
    {
      CAN_UNINIT = 0, /**< Not initialized.           */
      CAN_STOP = 1, /**< Stopped.                   */
      CAN_STARTING = 2, /**< Starting.                  */
      CAN_READY = 3, /**< Ready.                     */
      CAN_SLEEP = 4 /**< Sleep state.               */
    } canstate_t;
    
    #include "can_lld.h"
    
    /**
     * Converts a mailbox index to a bit mask.
     */
    #define CAN_MAILBOX_TO_MASK(mbx) (1 << ((mbx) - 1))
    
    void canInit( void );
    void canObjectInit( CANDriver *canp );
    void canStart( CANDriver *canp, const CANConfig *config );
    void canStop( CANDriver *canp );
    msg_t canTransmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp,
      systime_t timeout );
    msg_t canReceive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp,
      systime_t timeout );
    void canSleep( CANDriver *canp );
    void canWakeup( CANDriver *canp );
    
    #include "ch.h"
    #include "hal.h"
    
    /**
     * CAN Driver initialization.
     * @note    This function is implicitly invoked by @p halInit(), there is
     *          no need to explicitly initialize the driver.
     *
     * @init
     */
    void canInit( void )
    {
      
      can_lld_init( );
    }
    
    /**
     * Initializes the standard part of a @p CANDriver structure.
     *
     * @param[out] canp     pointer to the @p CANDriver object
     *
     * @init
     */
    void canObjectInit( CANDriver *canp )
    {
      
      canp->state = CAN_STOP;
      canp->config = NULL;
      chSemInit( &canp->txsem, 0 );
      chSemInit( &canp->rxsem, 0 );
      chEvtInit( &canp->rxfull_event );
      chEvtInit( &canp->txempty_event );
      chEvtInit( &canp->error_event );
      chEvtInit( &canp->sleep_event );
      chEvtInit( &canp->wakeup_event );
    }
    
    /**
     * Configures and activates the CAN peripheral.
     * @note    Activating the CAN bus can be a slow operation this this function
     *          is not atomic, it waits internally for the initialization to
     *          complete.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     * @param[in] config    pointer to the @p CANConfig object. Depending on
     *                      the implementation the value can be @p NULL.
     *
     * @api
     */
    void canStart( CANDriver *canp, const CANConfig *config )
    {
      
      chDbgCheck( canp != NULL, "canStart" );
      
      chSysLock( );
      chDbgAssert(
        ( canp->state == CAN_STOP ) || ( canp->state == CAN_STARTING )
          || ( canp->state == CAN_READY ), "canStart(), #1", "invalid state" );
      while ( canp->state == CAN_STARTING )
        chThdSleepS( 1 );
      if ( canp->state == CAN_STOP )
      {
        canp->config = config;
        can_lld_start( canp );
        canp->state = CAN_READY;
      }
      chSysUnlock( );
    }
    
    /**
     * Deactivates the CAN peripheral.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @api
     */
    void canStop( CANDriver *canp )
    {
      
      chDbgCheck( canp != NULL, "canStop" );
      
      chSysLock( );
      chDbgAssert( ( canp->state == CAN_STOP ) || ( canp->state == CAN_READY ),
        "canStop(), #1", "invalid state" );
      can_lld_stop( canp );
      canp->state = CAN_STOP;
      chSemResetI( &canp->rxsem, 0 );
      chSemResetI( &canp->txsem, 0 );
      chSchRescheduleS( );
      chSysUnlock( );
    }
    
    /**
     * 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] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
     * @param[in] ctfp      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  The operation has timed out.
     * @retval RDY_RESET    The driver has been stopped while waiting.
     *
     * @api
     */
    msg_t canTransmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp,
      systime_t timeout )
    {
      
      chDbgCheck(
        ( canp != NULL ) && ( ctfp != NULL ) && ( mailbox <= CAN_TX_MAILBOXES ),
        "canTransmit" );
      
      chSysLock( );
      chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ),
        "canTransmit(), #1", "invalid state" );
      while ( ( canp->state == CAN_SLEEP ) || !can_lld_is_tx_empty( canp, mailbox ) )
      {
        msg_t msg = chSemWaitTimeoutS( &canp->txsem, timeout );
        if ( msg != RDY_OK )
        {
          chSysUnlock( );
          return msg;
        }
      }
      can_lld_transmit( canp, mailbox, ctfp );
      chSysUnlock( );
      return RDY_OK;
    }
    
    /**
     * 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[in] mailbox   mailbox number, @p CAN_ANY_MAILBOX for any mailbox
     * @param[out] crfp     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 (useful in an
     *                        event driven scenario where a thread never blocks
     *                        for I/O).
     *                      - @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  The operation has timed out.
     * @retval RDY_RESET    The driver has been stopped while waiting.
     *
     * @api
     */
    msg_t canReceive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp,
      systime_t timeout )
    {
      
      chDbgCheck(
        ( canp != NULL ) && ( crfp != NULL ) && ( mailbox <= CAN_RX_MAILBOXES ),
        "canReceive" );
      
      chSysLock( );
      chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ),
        "canReceive(), #1", "invalid state" );
      while ( ( canp->state == CAN_SLEEP )
        || !can_lld_is_rx_nonempty( canp, mailbox ) )
      {
        msg_t msg = chSemWaitTimeoutS( &canp->rxsem, timeout );
        if ( msg != RDY_OK )
        {
          chSysUnlock( );
          return msg;
        }
      }
      can_lld_receive( canp, mailbox, crfp );
      chSysUnlock( );
      return RDY_OK;
    }
    
    /**
     * Enters the sleep mode.
     * @details This function puts the CAN driver in sleep mode and broadcasts
     *          the @p sleep_event event source.
     * @pre     In order to use this function the option @p CAN_USE_SLEEP_MODE must
     *          be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported
     *          by the low level driver.
     *
     * @param[in] canp      pointer to the @p CANDriver object
     *
     * @api
     */
    void canSleep( CANDriver *canp )
    {
      
      chDbgCheck( canp != NULL, "canSleep" );
      
      chSysLock( );
      chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ),
        "canSleep(), #1", "invalid state" );
      if ( canp->state == CAN_READY )
      {
        can_lld_sleep( canp );
        canp->state = CAN_SLEEP;
        chEvtBroadcastI( &canp->sleep_event );
        chSchRescheduleS( );
      }
      chSysUnlock( );
    }
    
    /**
     * 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->state == CAN_READY ) || ( canp->state == CAN_SLEEP ),
        "canWakeup(), #1", "invalid state" );
      if ( canp->state == CAN_SLEEP )
      {
        can_lld_wakeup( canp );
        canp->state = CAN_READY;
        chEvtBroadcastI( &canp->wakeup_event );
        chSchRescheduleS( );
      }
      chSysUnlock( );
    }
  • 相关阅读:
    微软下载
    stsadm.exe
    将表数据生成Insert脚本
    silverlight客户端保存文件乱码问题
    MySql全文索引
    SQL 自增主键从1开始
    Redis 数据结构之简单动态字符串SDS
    vs2012升级到vs2013后,sql server 无法通过IP登录解决方案
    常见XSD问题
    EntitySpace 常用语句
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4714827.html
Copyright © 2011-2022 走看看