1 /**
2  * CANopen TIME object protocol.
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 
27 #ifndef CO_TIME_H
28 #define CO_TIME_H
29 
30 #include "CO_OD.h"
31 
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 /**
38  * @defgroup CO_TIME TIME
39  * @ingroup CO_CANopen
40  * @{
41  *
42  * CANopen TIME object protocol.
43  *
44  * For CAN identifier see #CO_Default_CAN_ID_t
45  *
46  * TIME message is used for time synchronization of the nodes on network. One node
47  * should be TIME producer, others can be TIME consumers. This is configured with
48  * COB_ID_TIME object 0x1012 :
49  *
50  * - bit 31 should be set for a consumer
51  * - bit 30 should be set for a producer
52  *
53  *
54  * ###TIME CONSUMER
55  *
56  * CO_TIME_init() configuration :
57  * - COB_ID_TIME : 0x80000100L -> TIME consumer with TIME_COB_ID = 0x100
58  * - TIMECyclePeriod :
59  *      - 0 -> no EMCY will be transmitted in case of TIME timeout
60  *      - X -> an EMCY will be transmitted in case of TIME timeout (X * 1.5) ms
61  *
62  * Latest time value is stored in \p CO->TIME->Time variable.
63  *
64  *
65  * ###TIME PRODUCER
66  *
67  * CO_TIME_init() configuration :
68  * - COB_ID_TIME : 0x40000100L -> TIME producer with TIME_COB_ID = 0x100
69  * - TIMECyclePeriod : Time transmit period in ms
70  *
71  * Write time value in \p CO->TIME->Time variable, this will be sent at TIMECyclePeriod.
72  */
73 
74 #define TIME_MSG_LENGTH 6U
75 
76 /**
77  * TIME producer and consumer object.
78  */
79 typedef struct{
80     CO_EM_t            *em;             /**< From CO_TIME_init() */
81     uint8_t            *operatingState; /**< From CO_TIME_init() */
82 	/** True, if device is TIME consumer. Calculated from _COB ID TIME Message_
83     variable from Object dictionary (index 0x1012). */
84     bool_t              isConsumer;
85 	/** True, if device is TIME producer. Calculated from _COB ID TIME Message_
86     variable from Object dictionary (index 0x1012). */
87     bool_t              isProducer;
88     uint16_t            COB_ID;         /**< From CO_TIME_init() */
89     /** TIME period time in [milliseconds]. Set to TIME period to enable
90     timeout detection */
91     uint32_t            periodTime;
92     /** TIME period timeout time in [milliseconds].
93     (periodTimeoutTime = periodTime * 1,5) */
94     uint32_t            periodTimeoutTime;
95     /** Variable indicates, if new TIME message received from CAN bus */
96     volatile void      *CANrxNew;
97     /** Timer for the TIME message in [microseconds].
98     Set to zero after received or transmitted TIME message */
99     uint32_t            timer;
100     /** Set to nonzero value, if TIME with wrong data length is received from CAN */
101     uint16_t            receiveError;
102     CO_CANmodule_t     *CANdevRx;       /**< From CO_TIME_init() */
103     uint16_t            CANdevRxIdx;    /**< From CO_TIME_init() */
104 	CO_CANmodule_t     *CANdevTx;       /**< From CO_TIME_init() */
105     uint16_t            CANdevTxIdx;    /**< From CO_TIME_init() */
106     CO_CANtx_t         *TXbuff;         /**< CAN transmit buffer */
107     TIME_OF_DAY         Time;
108 }CO_TIME_t;
109 
110 /**
111  * Initialize TIME object.
112  *
113  * Function must be called in the communication reset section.
114  *
115  * @param TIME This object will be initialized.
116  * @param em Emergency object.
117  * @param SDO SDO server object.
118  * @param operatingState Pointer to variable indicating CANopen device NMT internal state.
119  * @param COB_ID_TIMEMessage Should be intialized with CO_CAN_ID_TIME_STAMP
120  * @param TIMECyclePeriod TIME period in ms (may also be used in consumer mode for timeout detection (1.5x period)).
121  * @param CANdevRx CAN device for TIME reception.
122  * @param CANdevRxIdx Index of receive buffer in the above CAN device.
123  *
124  * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
125  */
126 CO_ReturnError_t CO_TIME_init(
127         CO_TIME_t              *TIME,
128         CO_EM_t                *em,
129         CO_SDO_t               *SDO,
130         uint8_t                *operatingState,
131         uint32_t                COB_ID_TIMEMessage,
132         uint32_t                TIMECyclePeriod,
133         CO_CANmodule_t         *CANdevRx,
134         uint16_t                CANdevRxIdx,
135         CO_CANmodule_t         *CANdevTx,
136         uint16_t                CANdevTxIdx);
137 
138 /**
139  * Process TIME communication.
140  *
141  * Function must be called cyclically.
142  *
143  * @param TIME This object.
144  * @param timeDifference_ms Time difference from previous function call in [milliseconds].
145  *
146  * @return 0: No special meaning.
147  * @return 1: New TIME message recently received (consumer) / transmited (producer).
148  */
149 uint8_t CO_TIME_process(
150         CO_TIME_t              *TIME,
151         uint32_t                timeDifference_ms);
152 
153 #ifdef __cplusplus
154 }
155 #endif /*__cplusplus*/
156 
157 /** @} */
158 #endif
159