1 /*
2  * CAN module object for generic microcontroller.
3  *
4  * This file is a template for other microcontrollers.
5  *
6  * @file        CO_driver.c
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 #include "CO_driver.h"
30 #include "CO_Emergency.h"
31 
32 
33 /******************************************************************************/
CO_CANsetConfigurationMode(void * CANdriverState)34 void CO_CANsetConfigurationMode(void *CANdriverState){
35     /* Put CAN module in configuration mode */
36 }
37 
38 
39 /******************************************************************************/
CO_CANsetNormalMode(CO_CANmodule_t * CANmodule)40 void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){
41     /* Put CAN module in normal mode */
42 
43     CANmodule->CANnormal = true;
44 }
45 
46 
47 /******************************************************************************/
CO_CANmodule_init(CO_CANmodule_t * CANmodule,void * CANdriverState,CO_CANrx_t rxArray[],uint16_t rxSize,CO_CANtx_t txArray[],uint16_t txSize,uint16_t CANbitRate)48 CO_ReturnError_t CO_CANmodule_init(
49         CO_CANmodule_t         *CANmodule,
50         void                   *CANdriverState,
51         CO_CANrx_t              rxArray[],
52         uint16_t                rxSize,
53         CO_CANtx_t              txArray[],
54         uint16_t                txSize,
55         uint16_t                CANbitRate)
56 {
57     uint16_t i;
58 
59     /* verify arguments */
60     if(CANmodule==NULL || rxArray==NULL || txArray==NULL){
61         return CO_ERROR_ILLEGAL_ARGUMENT;
62     }
63 
64     /* Configure object variables */
65     CANmodule->CANdriverState = CANdriverState;
66     CANmodule->rxArray = rxArray;
67     CANmodule->rxSize = rxSize;
68     CANmodule->txArray = txArray;
69     CANmodule->txSize = txSize;
70     CANmodule->CANnormal = false;
71     CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false;/* microcontroller dependent */
72     CANmodule->bufferInhibitFlag = false;
73     CANmodule->firstCANtxMessage = true;
74     CANmodule->CANtxCount = 0U;
75     CANmodule->errOld = 0U;
76     CANmodule->em = NULL;
77 
78     for(i=0U; i<rxSize; i++){
79         rxArray[i].ident = 0U;
80         rxArray[i].mask = (uint16_t)0xFFFFFFFFU;
81         rxArray[i].object = NULL;
82         rxArray[i].pFunct = NULL;
83     }
84     for(i=0U; i<txSize; i++){
85         txArray[i].bufferFull = false;
86     }
87 
88 
89     /* Configure CAN module registers */
90 
91 
92     /* Configure CAN timing */
93 
94 
95     /* Configure CAN module hardware filters */
96     if(CANmodule->useCANrxFilters){
97         /* CAN module filters are used, they will be configured with */
98         /* CO_CANrxBufferInit() functions, called by separate CANopen */
99         /* init functions. */
100         /* Configure all masks so, that received message must match filter */
101     }
102     else{
103         /* CAN module filters are not used, all messages with standard 11-bit */
104         /* identifier will be received */
105         /* Configure mask 0 so, that all messages with standard identifier are accepted */
106     }
107 
108 
109     /* configure CAN interrupt registers */
110 
111 
112     return CO_ERROR_NO;
113 }
114 
115 
116 /******************************************************************************/
CO_CANmodule_disable(CO_CANmodule_t * CANmodule)117 void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){
118     /* turn off the module */
119 }
120 
121 
122 /******************************************************************************/
CO_CANrxMsg_readIdent(const CO_CANrxMsg_t * rxMsg)123 uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){
124     return (uint16_t) rxMsg->ident;
125 }
126 
127 
128 /******************************************************************************/
CO_CANrxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,uint16_t mask,bool_t rtr,void * object,void (* pFunct)(void * object,const CO_CANrxMsg_t * message))129 CO_ReturnError_t CO_CANrxBufferInit(
130         CO_CANmodule_t         *CANmodule,
131         uint16_t                index,
132         uint16_t                ident,
133         uint16_t                mask,
134         bool_t                  rtr,
135         void                   *object,
136         void                  (*pFunct)(void *object, const CO_CANrxMsg_t *message))
137 {
138     CO_ReturnError_t ret = CO_ERROR_NO;
139 
140     if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){
141         /* buffer, which will be configured */
142         CO_CANrx_t *buffer = &CANmodule->rxArray[index];
143 
144         /* Configure object variables */
145         buffer->object = object;
146         buffer->pFunct = pFunct;
147 
148         /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */
149         buffer->ident = ident & 0x07FFU;
150         if(rtr){
151             buffer->ident |= 0x0800U;
152         }
153         buffer->mask = (mask & 0x07FFU) | 0x0800U;
154 
155         /* Set CAN hardware module filter and mask. */
156         if(CANmodule->useCANrxFilters){
157 
158         }
159     }
160     else{
161         ret = CO_ERROR_ILLEGAL_ARGUMENT;
162     }
163 
164     return ret;
165 }
166 
167 
168 /******************************************************************************/
CO_CANtxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,bool_t rtr,uint8_t noOfBytes,bool_t syncFlag)169 CO_CANtx_t *CO_CANtxBufferInit(
170         CO_CANmodule_t         *CANmodule,
171         uint16_t                index,
172         uint16_t                ident,
173         bool_t                  rtr,
174         uint8_t                 noOfBytes,
175         bool_t                  syncFlag)
176 {
177     CO_CANtx_t *buffer = NULL;
178 
179     if((CANmodule != NULL) && (index < CANmodule->txSize)){
180         /* get specific buffer */
181         buffer = &CANmodule->txArray[index];
182 
183         /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer.
184          * Microcontroller specific. */
185         buffer->ident = ((uint32_t)ident & 0x07FFU)
186                       | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 12U))
187                       | ((uint32_t)(rtr ? 0x8000U : 0U));
188 
189         buffer->bufferFull = false;
190         buffer->syncFlag = syncFlag;
191     }
192 
193     return buffer;
194 }
195 
196 
197 /******************************************************************************/
CO_CANsend(CO_CANmodule_t * CANmodule,CO_CANtx_t * buffer)198 CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
199     CO_ReturnError_t err = CO_ERROR_NO;
200 
201     /* Verify overflow */
202     if(buffer->bufferFull){
203         if(!CANmodule->firstCANtxMessage){
204             /* don't set error, if bootup message is still on buffers */
205             CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident);
206         }
207         err = CO_ERROR_TX_OVERFLOW;
208     }
209 
210     CO_LOCK_CAN_SEND();
211     /* if CAN TX buffer is free, copy message to it */
212     if(1 && CANmodule->CANtxCount == 0){
213         CANmodule->bufferInhibitFlag = buffer->syncFlag;
214         /* copy message and txRequest */
215     }
216     /* if no buffer is free, message will be sent by interrupt */
217     else{
218         buffer->bufferFull = true;
219         CANmodule->CANtxCount++;
220     }
221     CO_UNLOCK_CAN_SEND();
222 
223     return err;
224 }
225 
226 
227 /******************************************************************************/
CO_CANclearPendingSyncPDOs(CO_CANmodule_t * CANmodule)228 void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){
229     uint32_t tpdoDeleted = 0U;
230 
231     CO_LOCK_CAN_SEND();
232     /* Abort message from CAN module, if there is synchronous TPDO.
233      * Take special care with this functionality. */
234     if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){
235         /* clear TXREQ */
236         CANmodule->bufferInhibitFlag = false;
237         tpdoDeleted = 1U;
238     }
239     /* delete also pending synchronous TPDOs in TX buffers */
240     if(CANmodule->CANtxCount != 0U){
241         uint16_t i;
242         CO_CANtx_t *buffer = &CANmodule->txArray[0];
243         for(i = CANmodule->txSize; i > 0U; i--){
244             if(buffer->bufferFull){
245                 if(buffer->syncFlag){
246                     buffer->bufferFull = false;
247                     CANmodule->CANtxCount--;
248                     tpdoDeleted = 2U;
249                 }
250             }
251             buffer++;
252         }
253     }
254     CO_UNLOCK_CAN_SEND();
255 
256 
257     if(tpdoDeleted != 0U){
258         CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted);
259     }
260 }
261 
262 
263 /******************************************************************************/
CO_CANverifyErrors(CO_CANmodule_t * CANmodule)264 void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){
265     uint16_t rxErrors, txErrors, overflow;
266     CO_EM_t* em = (CO_EM_t*)CANmodule->em;
267     uint32_t err;
268 
269     /* get error counters from module. Id possible, function may use different way to
270      * determine errors. */
271     rxErrors = CANmodule->txSize;
272     txErrors = CANmodule->txSize;
273     overflow = CANmodule->txSize;
274 
275     err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow;
276 
277     if(CANmodule->errOld != err){
278         CANmodule->errOld = err;
279 
280         if(txErrors >= 256U){                               /* bus off */
281             CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err);
282         }
283         else{                                               /* not bus off */
284             CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err);
285 
286             if((rxErrors >= 96U) || (txErrors >= 96U)){     /* bus warning */
287                 CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err);
288             }
289 
290             if(rxErrors >= 128U){                           /* RX bus passive */
291                 CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
292             }
293             else{
294                 CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err);
295             }
296 
297             if(txErrors >= 128U){                           /* TX bus passive */
298                 if(!CANmodule->firstCANtxMessage){
299                     CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
300                 }
301             }
302             else{
303                 bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE);
304                 if(isError){
305                     CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err);
306                     CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err);
307                 }
308             }
309 
310             if((rxErrors < 96U) && (txErrors < 96U)){       /* no error */
311                 CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err);
312             }
313         }
314 
315         if(overflow != 0U){                                 /* CAN RX bus overflow */
316             CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err);
317         }
318     }
319 }
320 
321 
322 /******************************************************************************/
CO_CANinterrupt(CO_CANmodule_t * CANmodule)323 void CO_CANinterrupt(CO_CANmodule_t *CANmodule){
324 
325     /* receive interrupt */
326     if(1){
327         CO_CANrxMsg_t *rcvMsg;      /* pointer to received message in CAN module */
328         uint16_t index;             /* index of received message */
329         uint32_t rcvMsgIdent;       /* identifier of the received message */
330         CO_CANrx_t *buffer = NULL;  /* receive message buffer from CO_CANmodule_t object. */
331         bool_t msgMatched = false;
332 
333         rcvMsg = 0; /* get message from module here */
334         rcvMsgIdent = rcvMsg->ident;
335         if(CANmodule->useCANrxFilters){
336             /* CAN module filters are used. Message with known 11-bit identifier has */
337             /* been received */
338             index = 0;  /* get index of the received message here. Or something similar */
339             if(index < CANmodule->rxSize){
340                 buffer = &CANmodule->rxArray[index];
341                 /* verify also RTR */
342                 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){
343                     msgMatched = true;
344                 }
345             }
346         }
347         else{
348             /* CAN module filters are not used, message with any standard 11-bit identifier */
349             /* has been received. Search rxArray form CANmodule for the same CAN-ID. */
350             buffer = &CANmodule->rxArray[0];
351             for(index = CANmodule->rxSize; index > 0U; index--){
352                 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){
353                     msgMatched = true;
354                     break;
355                 }
356                 buffer++;
357             }
358         }
359 
360         /* Call specific function, which will process the message */
361         if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){
362             buffer->pFunct(buffer->object, rcvMsg);
363         }
364 
365         /* Clear interrupt flag */
366     }
367 
368 
369     /* transmit interrupt */
370     else if(0){
371         /* Clear interrupt flag */
372 
373         /* First CAN message (bootup) was sent successfully */
374         CANmodule->firstCANtxMessage = false;
375         /* clear flag from previous message */
376         CANmodule->bufferInhibitFlag = false;
377         /* Are there any new messages waiting to be send */
378         if(CANmodule->CANtxCount > 0U){
379             uint16_t i;             /* index of transmitting message */
380 
381             /* first buffer */
382             CO_CANtx_t *buffer = &CANmodule->txArray[0];
383             /* search through whole array of pointers to transmit message buffers. */
384             for(i = CANmodule->txSize; i > 0U; i--){
385                 /* if message buffer is full, send it. */
386                 if(buffer->bufferFull){
387                     buffer->bufferFull = false;
388                     CANmodule->CANtxCount--;
389 
390                     /* Copy message to CAN buffer */
391                     CANmodule->bufferInhibitFlag = buffer->syncFlag;
392                     /* canSend... */
393                     break;                      /* exit for loop */
394                 }
395                 buffer++;
396             }/* end of for loop */
397 
398             /* Clear counter if no more messages */
399             if(i == 0U){
400                 CANmodule->CANtxCount = 0U;
401             }
402         }
403     }
404     else{
405         /* some other interrupt reason */
406     }
407 }
408