1 /**
2  * CANopen SYNC object protocol.
3  *
4  * @file        CO_SYNC.h
5  * @ingroup     CO_SYNC
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 #ifndef CO_SYNC_H
28 #define CO_SYNC_H
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /**
35  * @defgroup CO_SYNC SYNC
36  * @ingroup CO_CANopen
37  * @{
38  *
39  * CANopen SYNC object protocol.
40  *
41  * For CAN identifier see #CO_Default_CAN_ID_t
42  *
43  * SYNC message is used for synchronization of the nodes on network. One node
44  * can be SYNC producer, others can be SYNC consumers. Synchronous TPDOs are
45  * transmitted after the CANopen SYNC message. Synchronous received PDOs are
46  * accepted(copied to OD) immediatelly after the reception of the next SYNC
47  * message.
48  *
49  * ####Contents of SYNC message
50  * By default SYNC message has no data. If _Synchronous counter overflow value_
51  * from Object dictionary (index 0x1019) is different than 0, SYNC message has
52  * one data byte: _counter_ incremented by 1 with every SYNC transmission.
53  *
54  * ####SYNC in CANopenNode
55  * According to CANopen, synchronous RPDOs must be processed after reception of
56  * the next sync messsage. For that reason, there is a double receive buffer
57  * for each synchronous RPDO. At the moment, when SYNC is received or
58  * transmitted, internal variable CANrxToggle toggles. That variable is then
59  * used by synchronous RPDO to determine, which of the two buffers is used for
60  * RPDO reception and which for RPDO processing.
61  */
62 
63 
64 /**
65  * SYNC producer and consumer object.
66  */
67 typedef struct{
68     CO_EM_t            *em;             /**< From CO_SYNC_init() */
69     uint8_t            *operatingState; /**< From CO_SYNC_init() */
70     /** True, if device is SYNC producer. Calculated from _COB ID SYNC Message_
71     variable from Object dictionary (index 0x1005). */
72     bool_t              isProducer;
73     /** COB_ID of SYNC message. Calculated from _COB ID SYNC Message_
74     variable from Object dictionary (index 0x1005). */
75     uint16_t            COB_ID;
76     /** Sync period time in [microseconds]. Calculated from _Communication cycle period_
77     variable from Object dictionary (index 0x1006). */
78     uint32_t            periodTime;
79     /** Sync period timeout time in [microseconds].
80     (periodTimeoutTime = periodTime * 1,5) */
81     uint32_t            periodTimeoutTime;
82     /** Value from _Synchronous counter overflow value_ variable from Object
83     dictionary (index 0x1019) */
84     uint8_t             counterOverflowValue;
85     /** True, if current time is inside synchronous window.
86     In this case synchronous PDO may be sent. */
87     bool_t              curentSyncTimeIsInsideWindow;
88     /** Indicates, if new SYNC message received from CAN bus */
89     volatile void      *CANrxNew;
90     /** Variable toggles, if new SYNC message received from CAN bus */
91     bool_t              CANrxToggle;
92     /** Counter of the SYNC message if counterOverflowValue is different than zero */
93     uint8_t             counter;
94     /** Timer for the SYNC message in [microseconds].
95     Set to zero after received or transmitted SYNC message */
96     uint32_t            timer;
97     /** Set to nonzero value, if SYNC with wrong data length is received from CAN */
98     uint16_t            receiveError;
99     CO_CANmodule_t     *CANdevRx;       /**< From CO_SYNC_init() */
100     uint16_t            CANdevRxIdx;    /**< From CO_SYNC_init() */
101     CO_CANmodule_t     *CANdevTx;       /**< From CO_SYNC_init() */
102     CO_CANtx_t         *CANtxBuff;      /**< CAN transmit buffer inside CANdevTx */
103     uint16_t            CANdevTxIdx;    /**< From CO_SYNC_init() */
104 }CO_SYNC_t;
105 
106 
107 /**
108  * Initialize SYNC object.
109  *
110  * Function must be called in the communication reset section.
111  *
112  * @param SYNC This object will be initialized.
113  * @param em Emergency object.
114  * @param SDO SDO server object.
115  * @param operatingState Pointer to variable indicating CANopen device NMT internal state.
116  * @param COB_ID_SYNCMessage From Object dictionary (index 0x1005).
117  * @param communicationCyclePeriod From Object dictionary (index 0x1006).
118  * @param synchronousCounterOverflowValue From Object dictionary (index 0x1019).
119  * @param CANdevRx CAN device for SYNC reception.
120  * @param CANdevRxIdx Index of receive buffer in the above CAN device.
121  * @param CANdevTx CAN device for SYNC transmission.
122  * @param CANdevTxIdx Index of transmit 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_SYNC_init(
127         CO_SYNC_t              *SYNC,
128         CO_EM_t                *em,
129         CO_SDO_t               *SDO,
130         uint8_t                *operatingState,
131         uint32_t                COB_ID_SYNCMessage,
132         uint32_t                communicationCyclePeriod,
133         uint8_t                 synchronousCounterOverflowValue,
134         CO_CANmodule_t         *CANdevRx,
135         uint16_t                CANdevRxIdx,
136         CO_CANmodule_t         *CANdevTx,
137         uint16_t                CANdevTxIdx);
138 
139 
140 /**
141  * Process SYNC communication.
142  *
143  * Function must be called cyclically.
144  *
145  * @param SYNC This object.
146  * @param timeDifference_us Time difference from previous function call in [microseconds].
147  * @param ObjDict_synchronousWindowLength _Synchronous window length_ variable from
148  * Object dictionary (index 0x1007).
149  *
150  * @return 0: No special meaning.
151  * @return 1: New SYNC message recently received or was just transmitted.
152  * @return 2: SYNC time was just passed out of window.
153  */
154 uint8_t CO_SYNC_process(
155         CO_SYNC_t              *SYNC,
156         uint32_t                timeDifference_us,
157         uint32_t                ObjDict_synchronousWindowLength);
158 
159 #ifdef __cplusplus
160 }
161 #endif /*__cplusplus*/
162 
163 /** @} */
164 #endif
165