1 /*
2 * CANopen TIME object.
3 *
4 * @file CO_TIME.c
5 * @ingroup CO_TIME
6 * @author Julien PEYREGNE
7 * @copyright 2019 - 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 #include "CANopen.h"
27
28 /*
29 * Read received message from CAN module.
30 *
31 * Function will be called (by CAN receive interrupt) every time, when CAN
32 * message with correct identifier will be received.
33 */
CO_TIME_receive(void * object,const CO_CANrxMsg_t * msg)34 static void CO_TIME_receive(void *object, const CO_CANrxMsg_t *msg){
35 CO_TIME_t *TIME;
36 uint8_t operState;
37
38 TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */
39 operState = *TIME->operatingState;
40
41 if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
42 SET_CANrxNew(TIME->CANrxNew);
43 // Process Time from msg buffer
44 CO_memcpy((uint8_t*)&TIME->Time.ullValue, msg->data, msg->DLC);
45 }
46 else{
47 TIME->receiveError = (uint16_t)msg->DLC;
48 }
49 }
50
51 /******************************************************************************/
CO_TIME_init(CO_TIME_t * TIME,CO_EM_t * em,CO_SDO_t * SDO,uint8_t * operatingState,uint32_t COB_ID_TIMEMessage,uint32_t TIMECyclePeriod,CO_CANmodule_t * CANdevRx,uint16_t CANdevRxIdx,CO_CANmodule_t * CANdevTx,uint16_t CANdevTxIdx)52 CO_ReturnError_t CO_TIME_init(
53 CO_TIME_t *TIME,
54 CO_EM_t *em,
55 CO_SDO_t *SDO,
56 uint8_t *operatingState,
57 uint32_t COB_ID_TIMEMessage,
58 uint32_t TIMECyclePeriod,
59 CO_CANmodule_t *CANdevRx,
60 uint16_t CANdevRxIdx,
61 CO_CANmodule_t *CANdevTx,
62 uint16_t CANdevTxIdx)
63 {
64 /* verify arguments */
65 if(TIME==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
66 CANdevRx==NULL || CANdevTx==NULL){
67 return CO_ERROR_ILLEGAL_ARGUMENT;
68 }
69
70 /* Configure object variables */
71 TIME->isConsumer = (COB_ID_TIMEMessage&0x80000000L) ? true : false;
72 TIME->isProducer = (COB_ID_TIMEMessage&0x40000000L) ? true : false;
73 TIME->COB_ID = COB_ID_TIMEMessage&0x7FF; // 11 bit ID
74
75 TIME->periodTime = TIMECyclePeriod;
76 TIME->periodTimeoutTime = TIMECyclePeriod / 2 * 3;
77 /* overflow? */
78 if(TIME->periodTimeoutTime < TIMECyclePeriod)
79 TIME->periodTimeoutTime = 0xFFFFFFFFL;
80
81 CLEAR_CANrxNew(TIME->CANrxNew);
82 TIME->timer = 0;
83 TIME->receiveError = 0U;
84
85 TIME->em = em;
86 TIME->operatingState = operatingState;
87
88
89 /* configure TIME consumer message reception */
90 TIME->CANdevRx = CANdevRx;
91 TIME->CANdevRxIdx = CANdevRxIdx;
92 if(TIME->isConsumer)
93 CO_CANrxBufferInit(
94 CANdevRx, /* CAN device */
95 CANdevRxIdx, /* rx buffer index */
96 TIME->COB_ID, /* CAN identifier */
97 0x7FF, /* mask */
98 0, /* rtr */
99 (void*)TIME, /* object passed to receive function */
100 CO_TIME_receive); /* this function will process received message */
101
102
103 /* configure TIME producer message transmission */
104 TIME->CANdevTx = CANdevTx;
105 TIME->CANdevTxIdx = CANdevTxIdx;
106 if(TIME->isProducer)
107 TIME->TXbuff = CO_CANtxBufferInit(
108 CANdevTx, /* CAN device */
109 CANdevTxIdx, /* index of specific buffer inside CAN module */
110 TIME->COB_ID, /* CAN identifier */
111 0, /* rtr */
112 TIME_MSG_LENGTH, /* number of data bytes */
113 0); /* synchronous message flag bit */
114
115 return CO_ERROR_NO;
116 }
117
118 /******************************************************************************/
CO_TIME_process(CO_TIME_t * TIME,uint32_t timeDifference_ms)119 uint8_t CO_TIME_process(
120 CO_TIME_t *TIME,
121 uint32_t timeDifference_ms)
122 {
123 uint8_t ret = 0;
124 uint32_t timerNew;
125
126 if(*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){
127 /* update TIME timer, no overflow */
128 timerNew = TIME->timer + timeDifference_ms;
129 if(timerNew > TIME->timer)
130 TIME->timer = timerNew;
131
132 /* was TIME just received */
133 if(TIME->CANrxNew){
134 TIME->timer = 0;
135 ret = 1;
136 CLEAR_CANrxNew(TIME->CANrxNew);
137 }
138
139 /* TIME producer */
140 if(TIME->isProducer && TIME->periodTime){
141 if(TIME->timer >= TIME->periodTime){
142 TIME->timer = 0;
143 ret = 1;
144 CO_memcpy(TIME->TXbuff->data, (const uint8_t*)&TIME->Time.ullValue, TIME_MSG_LENGTH);
145 CO_CANsend(TIME->CANdevTx, TIME->TXbuff);
146 }
147 }
148
149 /* Verify TIME timeout if node is consumer */
150 if(TIME->isConsumer && TIME->periodTime && TIME->timer > TIME->periodTimeoutTime
151 && *TIME->operatingState == CO_NMT_OPERATIONAL)
152 CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer);
153 }
154 else {
155 CLEAR_CANrxNew(TIME->CANrxNew);
156 }
157
158 /* verify error from receive function */
159 if(TIME->receiveError != 0U){
160 CO_errorReport(TIME->em, CO_EM_TIME_LENGTH, CO_EMC_TIME_DATA_LENGTH, (uint32_t)TIME->receiveError);
161 TIME->receiveError = 0U;
162 }
163
164 return ret;
165 }
166