1 /*
2 * CANopen Emergency object.
3 *
4 * @file CO_Emergency.c
5 * @ingroup CO_Emergency
6 * @author Janez Paternoster
7 * @copyright 2004 - 2020 Janez Paternoster
8 *
9 * This file is part of CANopenNode, an opensource CANopen Stack.
10 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
11 * For more information on CANopen see <http://www.can-cia.org/>.
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 */
25
26
27 #include "CO_driver.h"
28 #include "CO_SDO.h"
29 #include "CO_Emergency.h"
30 #include "CANopen.h"
31
32
33 /*
34 * Read received message from CAN module.
35 *
36 * Function will be called (by CAN receive interrupt) every time, when CAN
37 * message with correct identifier will be received. For more information and
38 * description of parameters see file CO_driver.h.
39 */
CO_EM_receive(void * object,const CO_CANrxMsg_t * msg)40 static void CO_EM_receive(void *object, const CO_CANrxMsg_t *msg){
41 CO_EM_t *em;
42 uint16_t errorCode;
43 uint32_t infoCode;
44
45 em = (CO_EM_t*)object;
46
47 if(em!=NULL && em->pFunctSignalRx!=NULL){
48 CO_memcpySwap2(&errorCode, &msg->data[0]);
49 CO_memcpySwap4(&infoCode, &msg->data[4]);
50 em->pFunctSignalRx(CO_CANrxMsg_readIdent(msg),
51 errorCode,
52 msg->data[2],
53 msg->data[3],
54 infoCode);
55 }
56 }
57
58 /*
59 * Function for accessing _Pre-Defined Error Field_ (index 0x1003) from SDO server.
60 *
61 * For more information see file CO_SDO.h.
62 */
63 static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg);
CO_ODF_1003(CO_ODF_arg_t * ODF_arg)64 static CO_SDO_abortCode_t CO_ODF_1003(CO_ODF_arg_t *ODF_arg){
65 CO_EMpr_t *emPr;
66 uint8_t value;
67 CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
68
69 emPr = (CO_EMpr_t*) ODF_arg->object;
70 value = ODF_arg->data[0];
71
72 if(ODF_arg->reading){
73 uint8_t noOfErrors;
74 noOfErrors = emPr->preDefErrNoOfErrors;
75
76 if(ODF_arg->subIndex == 0U){
77 ODF_arg->data[0] = noOfErrors;
78 }
79 else if(ODF_arg->subIndex > noOfErrors){
80 ret = CO_SDO_AB_NO_DATA;
81 }
82 else{
83 ret = CO_SDO_AB_NONE;
84 }
85 }
86 else{
87 /* only '0' may be written to subIndex 0 */
88 if(ODF_arg->subIndex == 0U){
89 if(value == 0U){
90 emPr->preDefErrNoOfErrors = 0U;
91 }
92 else{
93 ret = CO_SDO_AB_INVALID_VALUE;
94 }
95 }
96 else{
97 ret = CO_SDO_AB_READONLY;
98 }
99 }
100
101 return ret;
102 }
103
104
105 /*
106 * Function for accessing _COB ID EMCY_ (index 0x1014) from SDO server.
107 *
108 * For more information see file CO_SDO.h.
109 */
110 static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg);
CO_ODF_1014(CO_ODF_arg_t * ODF_arg)111 static CO_SDO_abortCode_t CO_ODF_1014(CO_ODF_arg_t *ODF_arg){
112 uint8_t *nodeId;
113 uint32_t value;
114 CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
115
116 nodeId = (uint8_t*) ODF_arg->object;
117 value = CO_getUint32(ODF_arg->data);
118
119 /* add nodeId to the value */
120 if(ODF_arg->reading){
121 CO_setUint32(ODF_arg->data, value + *nodeId);
122 }
123
124 return ret;
125 }
126
127
128 /******************************************************************************/
CO_EM_init(CO_EM_t * em,CO_EMpr_t * emPr,CO_SDO_t * SDO,uint8_t * errorStatusBits,uint8_t errorStatusBitsSize,uint8_t * errorRegister,uint32_t * preDefErr,uint8_t preDefErrSize,CO_CANmodule_t * CANdevRx,uint16_t CANdevRxIdx,CO_CANmodule_t * CANdevTx,uint16_t CANdevTxIdx,uint16_t CANidTxEM)129 CO_ReturnError_t CO_EM_init(
130 CO_EM_t *em,
131 CO_EMpr_t *emPr,
132 CO_SDO_t *SDO,
133 uint8_t *errorStatusBits,
134 uint8_t errorStatusBitsSize,
135 uint8_t *errorRegister,
136 uint32_t *preDefErr,
137 uint8_t preDefErrSize,
138 CO_CANmodule_t *CANdevRx,
139 uint16_t CANdevRxIdx,
140 CO_CANmodule_t *CANdevTx,
141 uint16_t CANdevTxIdx,
142 uint16_t CANidTxEM)
143 {
144 uint8_t i;
145
146 /* verify arguments */
147 if(em==NULL || emPr==NULL || SDO==NULL || errorStatusBits==NULL || errorStatusBitsSize<6U ||
148 errorRegister==NULL || preDefErr==NULL || CANdevTx==NULL || CANdevRx==NULL){
149 return CO_ERROR_ILLEGAL_ARGUMENT;
150 }
151
152 /* Configure object variables */
153 em->errorStatusBits = errorStatusBits;
154 em->errorStatusBitsSize = errorStatusBitsSize;
155 em->bufEnd = em->buf + (CO_EM_INTERNAL_BUFFER_SIZE * 8);
156 em->bufWritePtr = em->buf;
157 em->bufReadPtr = em->buf;
158 em->bufFull = 0U;
159 em->wrongErrorReport = 0U;
160 em->pFunctSignal = NULL;
161 em->pFunctSignalRx = NULL;
162 emPr->em = em;
163 emPr->errorRegister = errorRegister;
164 emPr->preDefErr = preDefErr;
165 emPr->preDefErrSize = preDefErrSize;
166 emPr->preDefErrNoOfErrors = 0U;
167 emPr->inhibitEmTimer = 0U;
168
169 /* clear error status bits */
170 for(i=0U; i<errorStatusBitsSize; i++){
171 em->errorStatusBits[i] = 0U;
172 }
173
174 /* Configure Object dictionary entry at index 0x1003 and 0x1014 */
175 CO_OD_configure(SDO, OD_H1003_PREDEF_ERR_FIELD, CO_ODF_1003, (void*)emPr, 0, 0U);
176 CO_OD_configure(SDO, OD_H1014_COBID_EMERGENCY, CO_ODF_1014, (void*)&SDO->nodeId, 0, 0U);
177
178 /* configure SDO server CAN reception */
179 CO_CANrxBufferInit(
180 CANdevRx, /* CAN device */
181 CANdevRxIdx, /* rx buffer index */
182 CO_CAN_ID_EMERGENCY, /* CAN identifier */
183 0x780, /* mask */
184 0, /* rtr */
185 (void*)em, /* object passed to receive function */
186 CO_EM_receive); /* this function will process received message */
187
188 /* configure emergency message CAN transmission */
189 emPr->CANdev = CANdevTx;
190 emPr->CANdev->em = (void*)em; /* update pointer inside CAN device. */
191 emPr->CANtxBuff = CO_CANtxBufferInit(
192 CANdevTx, /* CAN device */
193 CANdevTxIdx, /* index of specific buffer inside CAN module */
194 CANidTxEM, /* CAN identifier */
195 0, /* rtr */
196 8U, /* number of data bytes */
197 0); /* synchronous message flag bit */
198
199 return CO_ERROR_NO;
200 }
201
202
203 /******************************************************************************/
CO_EM_initCallback(CO_EM_t * em,void (* pFunctSignal)(void))204 void CO_EM_initCallback(
205 CO_EM_t *em,
206 void (*pFunctSignal)(void))
207 {
208 if(em != NULL){
209 em->pFunctSignal = pFunctSignal;
210 }
211 }
212
213
214 /******************************************************************************/
CO_EM_initCallbackRx(CO_EM_t * em,void (* pFunctSignalRx)(const uint16_t ident,const uint16_t errorCode,const uint8_t errorRegister,const uint8_t errorBit,const uint32_t infoCode))215 void CO_EM_initCallbackRx(
216 CO_EM_t *em,
217 void (*pFunctSignalRx)(const uint16_t ident,
218 const uint16_t errorCode,
219 const uint8_t errorRegister,
220 const uint8_t errorBit,
221 const uint32_t infoCode))
222 {
223 if(em != NULL){
224 em->pFunctSignalRx = pFunctSignalRx;
225 }
226 }
227
228
229 /******************************************************************************/
CO_EM_process(CO_EMpr_t * emPr,bool_t NMTisPreOrOperational,uint16_t timeDifference_100us,uint16_t emInhTime,uint16_t * timerNext_ms)230 void CO_EM_process(
231 CO_EMpr_t *emPr,
232 bool_t NMTisPreOrOperational,
233 uint16_t timeDifference_100us,
234 uint16_t emInhTime,
235 uint16_t *timerNext_ms)
236 {
237
238 CO_EM_t *em = emPr->em;
239 uint8_t errorRegister;
240 uint8_t errorMask;
241 uint8_t i;
242
243 /* verify errors from driver and other */
244 CO_CANverifyErrors(emPr->CANdev);
245 if(em->wrongErrorReport != 0U){
246 CO_errorReport(em, CO_EM_WRONG_ERROR_REPORT, CO_EMC_SOFTWARE_INTERNAL, (uint32_t)em->wrongErrorReport);
247 em->wrongErrorReport = 0U;
248 }
249
250
251 /* calculate Error register */
252 errorRegister = 0U;
253 errorMask = (uint8_t)~(CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMM_ERR | CO_ERR_REG_MANUFACTURER);
254 /* generic error */
255 if(em->errorStatusBits[5]){
256 errorRegister |= CO_ERR_REG_GENERIC_ERR;
257 }
258 /* communication error (overrun, error state) */
259 if(em->errorStatusBits[2] || em->errorStatusBits[3]){
260 errorRegister |= CO_ERR_REG_COMM_ERR;
261 }
262 /* Manufacturer */
263 for(i=6; i<em->errorStatusBitsSize; i++) {
264 if (em->errorStatusBits[i]) {
265 errorRegister |= CO_ERR_REG_MANUFACTURER;
266 }
267 }
268 *emPr->errorRegister = (*emPr->errorRegister & errorMask) | errorRegister;
269
270 /* inhibit time */
271 if(emPr->inhibitEmTimer < emInhTime){
272 emPr->inhibitEmTimer += timeDifference_100us;
273 }
274
275 /* send Emergency message. */
276 if( NMTisPreOrOperational &&
277 !emPr->CANtxBuff->bufferFull &&
278 (em->bufReadPtr != em->bufWritePtr || em->bufFull))
279 {
280 uint32_t preDEF; /* preDefinedErrorField */
281 uint16_t diff;
282
283 if (emPr->inhibitEmTimer >= emInhTime) {
284 /* inhibit time elapsed, send message */
285
286 /* add error register */
287 em->bufReadPtr[2] = *emPr->errorRegister;
288
289 /* copy data to CAN emergency message */
290 CO_memcpy(emPr->CANtxBuff->data, em->bufReadPtr, 8U);
291 CO_memcpy((uint8_t*)&preDEF, em->bufReadPtr, 4U);
292 em->bufReadPtr += 8;
293
294 /* Update read buffer pointer and reset inhibit timer */
295 if(em->bufReadPtr == em->bufEnd){
296 em->bufReadPtr = em->buf;
297 }
298 emPr->inhibitEmTimer = 0U;
299
300 /* verify message buffer overflow, then clear full flag */
301 if(em->bufFull == 2U){
302 em->bufFull = 0U; /* will be updated below */
303 CO_errorReport(em, CO_EM_EMERGENCY_BUFFER_FULL, CO_EMC_GENERIC, 0U);
304 }
305 else{
306 em->bufFull = 0;
307 CO_errorReset(em, CO_EM_EMERGENCY_BUFFER_FULL, 0);
308 }
309
310 /* write to 'pre-defined error field' (object dictionary, index 0x1003) */
311 if(emPr->preDefErr){
312 uint8_t j;
313
314 if(emPr->preDefErrNoOfErrors < emPr->preDefErrSize)
315 emPr->preDefErrNoOfErrors++;
316 for(j=emPr->preDefErrNoOfErrors-1; j>0; j--)
317 emPr->preDefErr[j] = emPr->preDefErr[j-1];
318 emPr->preDefErr[0] = preDEF;
319 }
320
321 /* send CAN message */
322 CO_CANsend(emPr->CANdev, emPr->CANtxBuff);
323 }
324
325 /* check again after inhibit time elapsed */
326 diff = (emInhTime + 9) / 10; /* time difference in ms, always round up */
327 if (timerNext_ms != NULL && *timerNext_ms > diff) {
328 *timerNext_ms = diff;
329 }
330 }
331
332 return;
333 }
334
335
336 /******************************************************************************/
CO_errorReport(CO_EM_t * em,const uint8_t errorBit,const uint16_t errorCode,const uint32_t infoCode)337 void CO_errorReport(CO_EM_t *em, const uint8_t errorBit, const uint16_t errorCode, const uint32_t infoCode){
338 uint8_t index = errorBit >> 3;
339 uint8_t bitmask = 1 << (errorBit & 0x7);
340 uint8_t *errorStatusBits = 0;
341 bool_t sendEmergency = true;
342
343 if(em == NULL){
344 sendEmergency = false;
345 }
346 else if(index >= em->errorStatusBitsSize){
347 /* if errorBit value not supported, send emergency 'CO_EM_WRONG_ERROR_REPORT' */
348 em->wrongErrorReport = errorBit;
349 sendEmergency = false;
350 }
351 else{
352 errorStatusBits = &em->errorStatusBits[index];
353 /* if error was already reported, do nothing */
354 if((*errorStatusBits & bitmask) != 0){
355 sendEmergency = false;
356 }
357 }
358
359 if(sendEmergency){
360 /* set error bit */
361 if(errorBit){
362 /* any error except NO_ERROR */
363 *errorStatusBits |= bitmask;
364 }
365
366 /* verify buffer full, set overflow */
367 if(em->bufFull){
368 em->bufFull = 2;
369 }
370 else{
371 uint8_t bufCopy[8];
372
373 /* prepare data for emergency message */
374 CO_memcpySwap2(&bufCopy[0], &errorCode);
375 bufCopy[2] = 0; /* error register will be set later */
376 bufCopy[3] = errorBit;
377 CO_memcpySwap4(&bufCopy[4], &infoCode);
378
379 /* copy data to the buffer, increment writePtr and verify buffer full */
380 CO_LOCK_EMCY();
381 CO_memcpy(em->bufWritePtr, &bufCopy[0], 8);
382 em->bufWritePtr += 8;
383
384 if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf;
385 if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1;
386 CO_UNLOCK_EMCY();
387
388 /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */
389 if(em->pFunctSignal != NULL) {
390 em->pFunctSignal();
391 }
392 }
393 }
394 }
395
396
397 /******************************************************************************/
CO_errorReset(CO_EM_t * em,const uint8_t errorBit,const uint32_t infoCode)398 void CO_errorReset(CO_EM_t *em, const uint8_t errorBit, const uint32_t infoCode){
399 uint8_t index = errorBit >> 3;
400 uint8_t bitmask = 1 << (errorBit & 0x7);
401 uint8_t *errorStatusBits = 0;
402 bool_t sendEmergency = true;
403
404 if(em == NULL){
405 sendEmergency = false;
406 }
407 else if(index >= em->errorStatusBitsSize){
408 /* if errorBit value not supported, send emergency 'CO_EM_WRONG_ERROR_REPORT' */
409 em->wrongErrorReport = errorBit;
410 sendEmergency = false;
411 }
412 else{
413 errorStatusBits = &em->errorStatusBits[index];
414 /* if error was allready cleared, do nothing */
415 if((*errorStatusBits & bitmask) == 0){
416 sendEmergency = false;
417 }
418 }
419
420 if(sendEmergency){
421 /* erase error bit */
422 *errorStatusBits &= ~bitmask;
423
424 /* verify buffer full */
425 if(em->bufFull){
426 em->bufFull = 2;
427 }
428 else{
429 uint8_t bufCopy[8];
430
431 /* prepare data for emergency message */
432 bufCopy[0] = 0;
433 bufCopy[1] = 0;
434 bufCopy[2] = 0; /* error register will be set later */
435 bufCopy[3] = errorBit;
436 CO_memcpySwap4(&bufCopy[4], &infoCode);
437
438 /* copy data to the buffer, increment writePtr and verify buffer full */
439 CO_LOCK_EMCY();
440 CO_memcpy(em->bufWritePtr, &bufCopy[0], 8);
441 em->bufWritePtr += 8;
442
443 if(em->bufWritePtr == em->bufEnd) em->bufWritePtr = em->buf;
444 if(em->bufWritePtr == em->bufReadPtr) em->bufFull = 1;
445 CO_UNLOCK_EMCY();
446
447 /* Optional signal to RTOS, which can resume task, which handles CO_EM_process */
448 if(em->pFunctSignal != NULL) {
449 em->pFunctSignal();
450 }
451 }
452 }
453 }
454
455
456 /******************************************************************************/
CO_isError(CO_EM_t * em,const uint8_t errorBit)457 bool_t CO_isError(CO_EM_t *em, const uint8_t errorBit){
458 uint8_t index = errorBit >> 3;
459 uint8_t bitmask = 1 << (errorBit & 0x7);
460 bool_t ret = false;
461
462 if(em != NULL && index < em->errorStatusBitsSize){
463 if((em->errorStatusBits[index] & bitmask) != 0){
464 ret = true;
465 }
466 }
467
468 return ret;
469 }
470