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