/** * CANopen Time-stamp protocol. * * @file CO_TIME.h * @ingroup CO_TIME * @author Julien PEYREGNE * @copyright 2019 - 2020 Janez Paternoster * * This file is part of , a CANopen Stack. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ #ifndef CO_TIME_H #define CO_TIME_H #include "301/CO_driver.h" #include "301/CO_ODinterface.h" #include "301/CO_NMT_Heartbeat.h" /* default configuration, see CO_config.h */ #ifndef CO_CONFIG_TIME #define CO_CONFIG_TIME (CO_CONFIG_TIME_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC) #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN #ifdef __cplusplus extern "C" { #endif /** * @defgroup CO_TIME TIME * CANopen Time-stamp protocol. * * @ingroup CO_CANopen_301 * @{ * For CAN identifier see @ref CO_Default_CAN_ID_t * * TIME message is used for time synchronization of the nodes on the network. One node should be TIME producer, others * can be TIME consumers. This is configured by COB_ID_TIME object 0x1012: * * - bit 31 should be set for a consumer * - bit 30 should be set for a producer * - bits 0..10 is CAN-ID, 0x100 by default * * Current time can be read from @p CO_TIME_t->ms (milliseconds after midnight) and @p CO_TIME_t->days (number of days * since January 1, 1984). Those values are updated on each @ref CO_TIME_process() call, either from internal timer or * from received time stamp message. * * Current time can be set with @ref CO_TIME_set() function, which is necessary at least once, if time producer. If * configured, time stamp message is send from @ref CO_TIME_process() in intervals specified by @ref CO_TIME_set() */ #define CO_TIME_MSG_LENGTH 6U /**< Length of the TIME message */ /** * TIME producer and consumer object. */ typedef struct { uint8_t timeStamp[CO_TIME_MSG_LENGTH]; /**< Received timestamp data */ uint32_t ms; /**< Milliseconds after midnight */ uint16_t days; /**< Number of days since January 1, 1984 */ uint16_t residual_us; /**< Residual microseconds calculated inside CO_TIME_process() */ bool_t isConsumer; /**< True, if device is TIME consumer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ bool_t isProducer; /**< True, if device is TIME producer. Calculated from _COB ID TIME Message_ variable from Object dictionary (index 0x1012). */ volatile void* CANrxNew; /**< Variable indicates, if new TIME message received from CAN bus */ #if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN uint32_t producerInterval_ms; /**< Interval for time producer in milli seconds */ uint32_t producerTimer_ms; /**< Sync producer timer */ CO_CANmodule_t* CANdevTx; /**< From CO_TIME_init() */ CO_CANtx_t* CANtxBuff; /**< CAN transmit buffer */ #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN void (*pFunctSignalPre)(void* object); /**< From CO_TIME_initCallbackPre() or NULL */ void* functSignalObjectPre; /**< From CO_TIME_initCallbackPre() or NULL */ #endif #if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_OD_DYNAMIC) != 0) || defined CO_DOXYGEN OD_extension_t OD_1012_extension; /**< Extension for OD object */ #endif } CO_TIME_t; /** * Initialize TIME object. * * Function must be called in the communication reset section. * * @param TIME This object will be initialized. * @param OD_1012_cobIdTimeStamp OD entry for 0x1012 - "COB-ID time stamp", entry is required. * @param CANdevRx CAN device for TIME reception. * @param CANdevRxIdx Index of receive buffer in the above CAN device. * @param CANdevTx CAN device for TIME transmission. * @param CANdevTxIdx Index of transmit buffer in the above CAN device. * @param [out] errInfo Additional information in case of error, may be NULL. * * @return #CO_ReturnError_t CO_ERROR_NO on success. */ CO_ReturnError_t CO_TIME_init(CO_TIME_t* TIME, OD_entry_t* OD_1012_cobIdTimeStamp, CO_CANmodule_t* CANdevRx, uint16_t CANdevRxIdx, #if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0) || defined CO_DOXYGEN CO_CANmodule_t* CANdevTx, uint16_t CANdevTxIdx, #endif uint32_t* errInfo); #if (((CO_CONFIG_TIME)&CO_CONFIG_FLAG_CALLBACK_PRE) != 0) || defined CO_DOXYGEN /** * Initialize TIME callback function. * * Function initializes optional callback function, which should immediately start processing of CO_TIME_process() * function. Callback is called after TIME message is received from the CAN bus. * * @param TIME This object. * @param object Pointer to object, which will be passed to pFunctSignalPre(). * @param pFunctSignalPre Pointer to the callback function. Not called if NULL. */ void CO_TIME_initCallbackPre(CO_TIME_t* TIME, void* object, void (*pFunctSignalPre)(void* object)); #endif /** * Set current time * * @param TIME This object. * @param ms Milliseconds after midnight * @param days Number of days since January 1, 1984 * @param producerInterval_ms Interval time for time producer in milliseconds */ static inline void CO_TIME_set(CO_TIME_t* TIME, uint32_t ms, uint16_t days, uint32_t producerInterval_ms) { (void)producerInterval_ms; /* may be unused */ if (TIME != NULL) { TIME->residual_us = 0; TIME->ms = ms; TIME->days = days; #if ((CO_CONFIG_TIME)&CO_CONFIG_TIME_PRODUCER) != 0 TIME->producerTimer_ms = TIME->producerInterval_ms = producerInterval_ms; #endif } } /** * Process TIME object. * * Function must be called cyclically. It updates internal time from received time stamp message or from * timeDifference_us. It also sends produces timestamp message, if producer and producerInterval_ms is set. * * @param TIME This object. * @param timeDifference_us Time difference from previous function call in [microseconds]. * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL state. * * @return True if new TIME stamp message recently received (consumer). */ bool_t CO_TIME_process(CO_TIME_t* TIME, bool_t NMTisPreOrOperational, uint32_t timeDifference_us); /** @} */ /* CO_TIME */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */ #endif /* CO_TIME_H */