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( );
}

 

posted @ 2015-08-09 11:29  IAmAProgrammer  阅读(1095)  评论(0编辑  收藏  举报