1 /**
2  * CAN module object for generic microcontroller.
3  *
4  * This file is a template for other microcontrollers.
5  *
6  * @file        CO_driver_target.h
7  * @ingroup     CO_driver
8  * @author      Janez Paternoster
9  * @copyright   2004 - 2020 Janez Paternoster
10  *
11  * This file is part of CANopenNode, an opensource CANopen Stack.
12  * Project home page is <https://github.com/CANopenNode/CANopenNode>.
13  * For more information on CANopen see <http://www.can-cia.org/>.
14  *
15  * Licensed under the Apache License, Version 2.0 (the "License");
16  * you may not use this file except in compliance with the License.
17  * You may obtain a copy of the License at
18  *
19  *     http://www.apache.org/licenses/LICENSE-2.0
20  *
21  * Unless required by applicable law or agreed to in writing, software
22  * distributed under the License is distributed on an "AS IS" BASIS,
23  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24  * See the License for the specific language governing permissions and
25  * limitations under the License.
26  */
27 
28 
29 #ifndef CO_DRIVER_TARGET_H
30 #define CO_DRIVER_TARGET_H
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 /* Include processor header file */
37 #include <stddef.h>         /* for 'NULL' */
38 #include <stdint.h>         /* for 'int8_t' to 'uint64_t' */
39 #include <stdbool.h>        /* for 'true', 'false' */
40 
41 
42 /**
43  * Endianness.
44  *
45  * Depending on processor or compiler architecture, one of the two macros must
46  * be defined: CO_LITTLE_ENDIAN or CO_BIG_ENDIAN. CANopen itself is little endian.
47  */
48 #define CO_LITTLE_ENDIAN
49 
50 
51 /**
52  * @defgroup CO_driver Driver
53  * @ingroup CO_CANopen
54  * @{
55  *
56  * Microcontroller specific code for CANopenNode.
57  *
58  * This file contains type definitions, functions and macros for:
59  *  - Basic data types.
60  *  - Receive and transmit buffers for CANopen messages.
61  *  - Interaction with CAN module on the microcontroller.
62  *  - CAN receive and transmit interrupts.
63  *
64  * This file is not only a CAN driver. There are no classic CAN queues for CAN
65  * messages. This file provides direct connection with other CANopen
66  * objects. It tries to provide fast responses and tries to avoid unnecessary
67  * calculations and memory consumptions.
68  *
69  * CO_CANmodule_t contains an array of _Received message objects_ (of type
70  * CO_CANrx_t) and an array of _Transmit message objects_ (of type CO_CANtx_t).
71  * Each CANopen communication object owns one member in one of the arrays.
72  * For example Heartbeat producer generates one CANopen transmitting object,
73  * so it has reserved one member in CO_CANtx_t array.
74  * SYNC module may produce sync or consume sync, so it has reserved one member
75  * in CO_CANtx_t and one member in CO_CANrx_t array.
76  *
77  * ###Reception of CAN messages.
78  * Before CAN messages can be received, each member in CO_CANrx_t must be
79  * initialized. CO_CANrxBufferInit() is called by CANopen module, which
80  * uses specific member. For example @ref CO_HBconsumer uses multiple members
81  * in CO_CANrx_t array. (It monitors multiple heartbeat messages from remote
82  * nodes.) It must call CO_CANrxBufferInit() multiple times.
83  *
84  * Main arguments to the CO_CANrxBufferInit() function are CAN identifier
85  * and a pointer to callback function. Those two arguments (and some others)
86  * are copied to the member of the CO_CANrx_t array.
87  *
88  * Callback function is a function, specified by specific CANopen module
89  * (for example by @ref CO_HBconsumer). Each CANopen module defines own
90  * callback function. Callback function will process the received CAN message.
91  * It will copy the necessary data from CAN message to proper place. It may
92  * also trigger additional task, which will further process the received message.
93  * Callback function must be fast and must only make the necessary calculations
94  * and copying.
95  *
96  * Received CAN messages are processed by CAN receive interrupt function.
97  * After CAN message is received, function first tries to find matching CAN
98  * identifier from CO_CANrx_t array. If found, then a corresponding callback
99  * function is called.
100  *
101  * Callback function accepts two parameters:
102  *  - object is pointer to object registered by CO_CANrxBufferInit().
103  *  - msg  is pointer to CAN message of type CO_CANrxMsg_t.
104  *
105  * Callback function must return #CO_ReturnError_t: CO_ERROR_NO,
106  * CO_ERROR_RX_OVERFLOW, CO_ERROR_RX_PDO_OVERFLOW, CO_ERROR_RX_MSG_LENGTH or
107  * CO_ERROR_RX_PDO_LENGTH.
108  *
109  *
110  * ###Transmission of CAN messages.
111  * Before CAN messages can be transmitted, each member in CO_CANtx_t must be
112  * initialized. CO_CANtxBufferInit() is called by CANopen module, which
113  * uses specific member. For example Heartbeat producer must initialize it's
114  * member in CO_CANtx_t array.
115  *
116  * CO_CANtxBufferInit() returns a pointer of type CO_CANtx_t, which contains buffer
117  * where CAN message data can be written. CAN message is send with calling
118  * CO_CANsend() function. If at that moment CAN transmit buffer inside
119  * microcontroller's CAN module is free, message is copied directly to CAN module.
120  * Otherwise CO_CANsend() function sets _bufferFull_ flag to true. Message will be
121  * then sent by CAN TX interrupt as soon as CAN module is freed. Until message is
122  * not copied to CAN module, its contents must not change. There may be multiple
123  * _bufferFull_ flags in CO_CANtx_t array set to true. In that case messages with
124  * lower index inside array will be sent first.
125  */
126 
127 
128 /**
129  * @name Critical sections
130  * CANopenNode is designed to run in different threads, as described in README.
131  * Threads are implemented differently in different systems. In microcontrollers
132  * threads are interrupts with different priorities, for example.
133  * It is necessary to protect sections, where different threads access to the
134  * same resource. In simple systems interrupts or scheduler may be temporary
135  * disabled between access to the shared resource. Otherwise mutexes or
136  * semaphores can be used.
137  *
138  * ####Reentrant functions.
139  * Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h
140  * and CO_errorReset() from CO_Emergency.h may be called from different threads.
141  * Critical sections must be protected. Eather by disabling scheduler or
142  * interrupts or by mutexes or semaphores.
143  *
144  * ####Object Dictionary variables.
145  * In general, there are two threads, which accesses OD variables: mainline and
146  * timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs
147  * in faster timer thread. Processing of PDOs must not be interrupted by
148  * mainline. Mainline thread must protect sections, which accesses the same OD
149  * variables as timer thread. This care must also take the application. Note
150  * that not all variables are allowed to be mapped to PDOs, so they may not need
151  * to be protected. SDO server protects sections with access to OD variables.
152  *
153  * ####CAN receive thread.
154  * It partially processes received CAN data and puts them into appropriate
155  * objects. Objects are later processed. It does not need protection of
156  * critical sections. There is one circumstance, where CANrx should be disabled:
157  * After presence of SYNC message on CANopen bus, CANrx should be temporary
158  * disabled until all receive PDOs are processed. See also CO_SYNC.h file and
159  * CO_SYNC_initCallback() function.
160  * @{
161  */
162 #define CO_LOCK_CAN_SEND()  /**< Lock critical section in CO_CANsend() */
163 #define CO_UNLOCK_CAN_SEND()/**< Unlock critical section in CO_CANsend() */
164 
165 #define CO_LOCK_EMCY()      /**< Lock critical section in CO_errorReport() or CO_errorReset() */
166 #define CO_UNLOCK_EMCY()    /**< Unlock critical section in CO_errorReport() or CO_errorReset() */
167 
168 #define CO_LOCK_OD()        /**< Lock critical section when accessing Object Dictionary */
169 #define CO_UNLOCK_OD()      /**< Unock critical section when accessing Object Dictionary */
170 /** @} */
171 
172 /**
173  * @name Synchronization functions
174  * synchronization for message buffer for communication between CAN receive and
175  * message processing threads.
176  *
177  * If receive function runs inside IRQ, no further synchronization is needed.
178  * Otherwise, some kind of synchronization has to be included. The following
179  * example uses GCC builtin memory barrier __sync_synchronize(). A comprehensive
180  * list can be found here: https://gist.github.com/leo-yuriev/ba186a6bf5cf3a27bae7
181  * \code{.c}
182     #define CANrxMemoryBarrier() __sync_synchronize()
183  * \endcode
184  * @{
185  */
186 /** Memory barrier */
187 #define CANrxMemoryBarrier()
188 /** Check if new message has arrived */
189 #define IS_CANrxNew(rxNew) ((uintptr_t)rxNew)
190 /** Set new message flag */
191 #define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;}
192 /** Clear new message flag */
193 #define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;}
194 /** @} */
195 
196 /**
197  * @defgroup CO_dataTypes Data types
198  * @{
199  *
200  * According to Misra C
201  */
202 /* int8_t to uint64_t are defined in stdint.h */
203 typedef unsigned char           bool_t;     /**< bool_t */
204 typedef float                   float32_t;  /**< float32_t */
205 typedef long double             float64_t;  /**< float64_t */
206 typedef char                    char_t;     /**< char_t */
207 typedef unsigned char           oChar_t;    /**< oChar_t */
208 typedef unsigned char           domain_t;   /**< domain_t */
209 /** @} */
210 
211 
212 /**
213  * CAN receive message structure as aligned in CAN module. It is different in
214  * different microcontrollers. It usually contains other variables.
215  */
216 typedef struct{
217     /** CAN identifier. It must be read through CO_CANrxMsg_readIdent() function. */
218     uint32_t            ident;
219     uint8_t             DLC ;           /**< Length of CAN message */
220     uint8_t             data[8];        /**< 8 data bytes */
221 }CO_CANrxMsg_t;
222 
223 
224 /**
225  * Received message object
226  */
227 typedef struct{
228     uint16_t            ident;          /**< Standard CAN Identifier (bits 0..10) + RTR (bit 11) */
229     uint16_t            mask;           /**< Standard Identifier mask with same alignment as ident */
230     void               *object;         /**< From CO_CANrxBufferInit() */
231     void              (*pFunct)(void *object, const CO_CANrxMsg_t *message);  /**< From CO_CANrxBufferInit() */
232 }CO_CANrx_t;
233 
234 
235 /**
236  * Transmit message object.
237  */
238 typedef struct{
239     uint32_t            ident;          /**< CAN identifier as aligned in CAN module */
240     uint8_t             DLC ;           /**< Length of CAN message. (DLC may also be part of ident) */
241     uint8_t             data[8];        /**< 8 data bytes */
242     volatile bool_t     bufferFull;     /**< True if previous message is still in buffer */
243     /** Synchronous PDO messages has this flag set. It prevents them to be sent outside the synchronous window */
244     volatile bool_t     syncFlag;
245 }CO_CANtx_t;
246 
247 
248 /**
249  * CAN module object. It may be different in different microcontrollers.
250  */
251 typedef struct{
252     void               *CANdriverState; /**< From CO_CANmodule_init() */
253     CO_CANrx_t         *rxArray;        /**< From CO_CANmodule_init() */
254     uint16_t            rxSize;         /**< From CO_CANmodule_init() */
255     CO_CANtx_t         *txArray;        /**< From CO_CANmodule_init() */
256     uint16_t            txSize;         /**< From CO_CANmodule_init() */
257     volatile bool_t     CANnormal;      /**< CAN module is in normal mode */
258     /** Value different than zero indicates, that CAN module hardware filters
259       * are used for CAN reception. If there is not enough hardware filters,
260       * they won't be used. In this case will be *all* received CAN messages
261       * processed by software. */
262     volatile bool_t     useCANrxFilters;
263     /** If flag is true, then message in transmitt buffer is synchronous PDO
264       * message, which will be aborted, if CO_clearPendingSyncPDOs() function
265       * will be called by application. This may be necessary if Synchronous
266       * window time was expired. */
267     volatile bool_t     bufferInhibitFlag;
268     /** Equal to 1, when the first transmitted message (bootup message) is in CAN TX buffers */
269     volatile bool_t     firstCANtxMessage;
270     /** Number of messages in transmit buffer, which are waiting to be copied to the CAN module */
271     volatile uint16_t   CANtxCount;
272     uint32_t            errOld;         /**< Previous state of CAN errors */
273     void               *em;             /**< Emergency object */
274 }CO_CANmodule_t;
275 
276 
277 /**
278  * Receives and transmits CAN messages.
279  *
280  * Function must be called directly from high priority CAN interrupt.
281  *
282  * @param CANmodule This object.
283  */
284 void CO_CANinterrupt(CO_CANmodule_t *CANmodule);
285 
286 #ifdef __cplusplus
287 }
288 #endif /* __cplusplus */
289 
290 /** @} */
291 #endif /* CO_DRIVER_TARGET_H */
292