/**
 * Main CANopenNode file.
 *
 * @file        CANopen.h
 * @ingroup     CO_CANopen
 * @author      Janez Paternoster
 * @author      Uwe Kindler
 * @copyright   2010 - 2023 Janez Paternoster
 *
 * This file is part of <https://github.com/CANopenNode/CANopenNode>, 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 CANopen_H
#define CANopen_H

#include "301/CO_driver.h"
#include "301/CO_ODinterface.h"
#include "301/CO_NMT_Heartbeat.h"
#include "301/CO_HBconsumer.h"
#include "301/CO_Node_Guarding.h"
#include "301/CO_Emergency.h"
#include "301/CO_SDOserver.h"
#include "301/CO_SDOclient.h"
#include "301/CO_SYNC.h"
#include "301/CO_PDO.h"
#include "301/CO_TIME.h"
#include "303/CO_LEDs.h"
#include "304/CO_GFC.h"
#include "304/CO_SRDO.h"
#include "305/CO_LSSslave.h"
#include "305/CO_LSSmaster.h"
#include "309/CO_gateway_ascii.h"
#include "extra/CO_trace.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @defgroup CO_CANopen CANopen
 * @{
 *
 * CANopenNode is free and open source CANopen communication protocol stack.
 *
 * CANopen is the internationally standardized (EN 50325-4) (CiA DS-301) CAN-based higher-layer protocol for embedded
 * control system. For more information on CANopen see http://www.can-cia.org/
 *
 * CANopenNode homepage is https://github.com/CANopenNode/CANopenNode
 *
 * CANopen.h file combines all CANopenNode source files. @ref CO_STACK_CONFIG is first defined in "CO_config.h" file.
 * Number of different CANopenNode objects used is configured with @ref CO_config_t structure or is read directly from
 * "OD.h" file, if single object dictionary definition is used. "OD.h" and "OD.c" files defines CANopen Object
 * Dictionary and are generated by external tool.
 *
 * 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
 *
 * https://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.
 * @}
 */

/**
 * @defgroup CO_CANopen_301 CANopen_301
 * @{
 *
 * CANopen application layer and communication profile (CiA 301 v4.2.0)
 *
 * Definitions of data types, encoding rules, object dictionary objects and CANopen communication services and
 * protocols.
 * @}
 */

/**
 * @defgroup CO_CANopen_303 CANopen_303
 * @{
 *
 * CANopen recommendation for indicator specification (CiA 303-3 v1.4.0)
 *
 * Description of communication related indicators - green and red LED diodes.
 * @}
 */

/**
 * @defgroup CO_CANopen_304 CANopen_304
 * @{
 *
 * CANopen Safety (EN 50325­-5:2010 (formerly CiA 304))
 *
 * Standard defines the usage of Safety Related Data Objects (SRDO) and the GFC. This is an additional protocol (to SDO,
 * PDO) to exchange data. The meaning of "security" here refers not to security (crypto) but to data consistency.
 * @}
 */

/**
 * @defgroup CO_CANopen_305 CANopen_305
 * @{
 *
 * CANopen layer setting services (LSS) and protocols (CiA 305 DSP v3.0.0)
 *
 * Inquire or change three parameters on a CANopen device with LSS slave capability by a CANopen device with LSS master
 * capability via the CAN network: the settings of Node-ID of the CANopen device, bit timing parameters of the physical
 * layer (bit rate) or LSS address compliant to the identity object (1018h).
 * @}
 */

/**
 * @defgroup CO_CANopen_309 CANopen_309
 * @{
 *
 * CANopen access from other networks (CiA 309)
 *
 * Standard defines the services and protocols to interface CANopen networks to other networks. Standard is organized as
 * follows:
 * - Part 1: General principles and services
 * - Part 2: Modbus/TCP mapping
 * - Part 3: ASCII mapping
 * - Part 4: Amendment 7 to Fieldbus Integration into PROFINET IO
 * @}
 */

/**
 * @defgroup CO_CANopen_storage CANopen_storage
 * @{
 *
 * CANopen Object Dictionary and other data storage.
 * @}
 */

/**
 * @defgroup CO_CANopen_extra CANopen_extra
 * @{
 *
 * Additional non-standard objects related to CANopenNode.
 * @}
 */

/**
 * @addtogroup CO_CANopen
 * @{
 */

/**
 * If macro is defined externally, then configuration with multiple object dictionaries will be possible. If macro is
 * not defined, default "OD.h" file with necessary definitions, such as OD_CNT_xxx, will be used, and also memory
 * consumption and startup time will be lower.
 */
#ifdef CO_DOXYGEN
#define CO_MULTIPLE_OD
#endif

/**
 * If macro is defined externally, then global variables for CANopen objects
 * will be used instead of heap. This is possible only if CO_MULTIPLE_OD is not
 * defined.
 */
#ifdef CO_DOXYGEN
#define CO_USE_GLOBALS
#endif

#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
/**
 * CANopen configuration, used with @ref CO_new()
 *
 * This structure is used only, if @ref CO_MULTIPLE_OD is enabled. Otherwise parameters are retrieved from default
 * "OD.h" file.
 */
typedef struct {
    uint8_t CNT_NMT;         /**< Number of NMT objects, 0 or 1: NMT slave (CANrx) + Heartbeat producer (CANtx) +
                                optional NMT master (CANtx), configurable by @ref CO_CONFIG_NMT. Start indexes inside
                                CANrx and CANtx are always 0. There must be one NMT object in the device. */
    OD_entry_t* ENTRY_H1017; /**< OD entry for @ref CO_NMT_init() */
    uint8_t CNT_HB_CONS;     /**< Number of Heartbeat consumer objects, 0 or 1 */
    uint8_t CNT_ARR_1016; /**< Number of internal consumers (CANrx), used inside Heartbeat consumer object, 1 to 127. */
    OD_entry_t* ENTRY_H1016; /**< OD entry for @ref CO_HBconsumer_init() */
    OD_entry_t* ENTRY_H100C; /**< OD entry for @ref CO_nodeGuardingSlave_init() */
    OD_entry_t* ENTRY_H100D; /**< OD entry for @ref CO_nodeGuardingSlave_init() */
    uint8_t CNT_EM; /**< Number of Emergency objects, 0 or 1: optional producer (CANtx) + optional consumer (CANrx),
                       configurable by @ref CO_CONFIG_EM. There must be one Emergency object in the device. */
    const OD_entry_t* ENTRY_H1001; /**< OD entry for @ref CO_EM_init() */
    OD_entry_t* ENTRY_H1014;       /**< OD entry for @ref CO_EM_init() */
    OD_entry_t* ENTRY_H1015;       /**< OD entry for @ref CO_EM_init() */
    uint8_t CNT_ARR_1003;    /**< Size of the fifo buffer, which is used for intermediate storage of emergency messages.
                                Fifo is used by emergency producer and by error history (OD object 0x1003). Size is usually
                                equal to size of array in OD object 0x1003. If later is not used, CNT_ARR_1003 must also be
                                set to value greater than 0, or emergency producer will not work. */
    OD_entry_t* ENTRY_H1003; /**< OD entry for @ref CO_EM_init() */
    uint8_t CNT_SDO_SRV;     /**< Number of SDO server objects, from 0 to 128 (CANrx + CANtx). There must be at least
                                one SDO server object in the device. */
    OD_entry_t* ENTRY_H1200; /**< OD entry for @ref CO_SDOserver_init() */
    uint8_t CNT_SDO_CLI;     /**< Number of SDO client objects, from 0 to 128 (CANrx + CANtx). */
    OD_entry_t* ENTRY_H1280; /**< OD entry for @ref CO_SDOclient_init() */
    uint8_t CNT_TIME;        /**< Number of TIME objects, 0 or 1: consumer (CANrx) + optional producer (CANtx),
                                configurable by @ref CO_CONFIG_TIME. */
    OD_entry_t* ENTRY_H1012; /**< OD entry for @ref CO_TIME_init() */
    uint8_t CNT_SYNC;        /**< Number of SYNC objects, 0 or 1:  consumer (CANrx) + optional producer (CANtx),
                                configurable by @ref CO_CONFIG_SYNC. */
    OD_entry_t* ENTRY_H1005; /**< OD entry for @ref CO_SYNC_init() */
    OD_entry_t* ENTRY_H1006; /**< OD entry for @ref CO_SYNC_init() */
    OD_entry_t* ENTRY_H1007; /**< OD entry for @ref CO_SYNC_init() */
    OD_entry_t* ENTRY_H1019; /**< OD entry for @ref CO_SYNC_init() */
    uint16_t CNT_RPDO;       /**< Number of RPDO objects, from 0 to 512 consumers (CANrx) */
    OD_entry_t* ENTRY_H1400; /**< OD entry for @ref CO_RPDO_init() */
    OD_entry_t* ENTRY_H1600; /**< OD entry for @ref CO_RPDO_init() */
    uint16_t CNT_TPDO;       /**< Number of TPDO objects, from 0 to 512 producers (CANtx) */
    OD_entry_t* ENTRY_H1800; /**< OD entry for @ref CO_TPDO_init() */
    OD_entry_t* ENTRY_H1A00; /**< OD entry for @ref CO_TPDO_init() */
    uint8_t CNT_LEDS;        /**< Number of LEDs objects, 0 or 1. */
    uint8_t CNT_GFC;         /**< Number of GFC objects, 0 or 1 (CANrx + CANtx). */
    OD_entry_t* ENTRY_H1300; /**< OD entry for @ref CO_GFC_init() */
    uint8_t CNT_SRDO;        /**< Number of SRDO objects, from 0 to 64 (2*CANrx + 2*CANtx). */
    OD_entry_t* ENTRY_H1301; /**< OD entry for @ref CO_SRDO_init() */
    OD_entry_t* ENTRY_H1381; /**< OD entry for @ref CO_SRDO_init() */
    OD_entry_t* ENTRY_H13FE; /**< OD entry for @ref CO_SRDO_init() */
    OD_entry_t* ENTRY_H13FF; /**< OD entry for @ref CO_SRDO_init() */
    uint8_t CNT_LSS_SLV;     /**< Number of LSSslave objects, 0 or 1 (CANrx + CANtx). */
    uint8_t CNT_LSS_MST;     /**< Number of LSSmaster objects, 0 or 1 (CANrx + CANtx). */
    uint8_t CNT_GTWA;        /**< Number of gateway ascii objects, 0 or 1. */
    uint16_t CNT_TRACE;      /**< Number of trace objects, 0 or more. */
} CO_config_t;
#else
typedef void CO_config_t;
#endif /* CO_MULTIPLE_OD */

/**
 * CANopen object - collection of all CANopenNode objects
 */
typedef struct {
    bool_t nodeIdUnconfigured; /**< True in un-configured LSS slave */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    CO_config_t* config; /**< Remember the configuration parameters */
#endif
    CO_CANmodule_t* CANmodule; /**< One CAN module object, initialised by @ref CO_CANmodule_init() */
    CO_CANrx_t* CANrx;         /**< CAN receive message objects */
    CO_CANtx_t* CANtx;         /**< CAN transmit message objects */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t CNT_ALL_RX_MSGS; /**< Number of all CAN receive message objects. */
    uint16_t CNT_ALL_TX_MSGS; /**< Number of all CAN transmit message objects. */
#endif
    CO_NMT_t* NMT; /**< NMT and heartbeat object, initialised by @ref CO_NMT_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_NMT_SLV; /**< Start index in CANrx. */
    uint16_t TX_IDX_NMT_MST; /**< Start index in CANtx. */
    uint16_t TX_IDX_HB_PROD; /**< Start index in CANtx. */
#endif
#if (((CO_CONFIG_HB_CONS)&CO_CONFIG_HB_CONS_ENABLE) != 0) || defined CO_DOXYGEN
    CO_HBconsumer_t* HBcons;               /**< Heartbeat consumer object, initialised by @ref CO_HBconsumer_init() */
    CO_HBconsNode_t* HBconsMonitoredNodes; /**< Object for monitored nodes, initialised by @ref CO_HBconsumer_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_HB_CONS; /**< Start index in CANrx. */
#endif
#endif
#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_SLAVE_ENABLE) != 0) || defined CO_DOXYGEN
    CO_nodeGuardingSlave_t* NGslave; /**< Node guarding slave object, initialised by @ref CO_nodeGuardingSlave_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_NG_SLV; /**< Start index in CANrx. */
    uint16_t TX_IDX_NG_SLV; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_NODE_GUARDING)&CO_CONFIG_NODE_GUARDING_MASTER_ENABLE) != 0) || defined CO_DOXYGEN
    CO_nodeGuardingMaster_t*
        NGmaster; /**< Node guarding master object, initialised by @ref CO_nodeGuardingMaster_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_NG_MST; /**< Start index in CANrx. */
    uint16_t TX_IDX_NG_MST; /**< Start index in CANtx. */
#endif
#endif
    CO_EM_t* em; /**< Emergency object, initialised by @ref CO_EM_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_EM_CONS; /**< Start index in CANrx. */
    uint16_t TX_IDX_EM_PROD; /**< Start index in CANtx. */
#endif
#if (((CO_CONFIG_EM) & (CO_CONFIG_EM_PRODUCER | CO_CONFIG_EM_HISTORY)) != 0) || defined CO_DOXYGEN
    CO_EM_fifo_t* em_fifo; /**< FIFO for emergency object, initialised by @ref CO_EM_init() */
#endif
    CO_SDOserver_t* SDOserver; /**< SDO server objects, initialised by @ref CO_SDOserver_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_SDO_SRV; /**< Start index in CANrx. */
    uint16_t TX_IDX_SDO_SRV; /**< Start index in CANtx. */
#endif
#if (((CO_CONFIG_SDO_CLI)&CO_CONFIG_SDO_CLI_ENABLE) != 0) || defined CO_DOXYGEN
    CO_SDOclient_t* SDOclient; /**< SDO client objects, initialised by @ref CO_SDOclient_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_SDO_CLI; /**< Start index in CANrx. */
    uint16_t TX_IDX_SDO_CLI; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_TIME)&CO_CONFIG_TIME_ENABLE) != 0) || defined CO_DOXYGEN
    CO_TIME_t* TIME; /**< TIME object, initialised by @ref CO_TIME_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_TIME; /**< Start index in CANrx. */
    uint16_t TX_IDX_TIME; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN
    CO_SYNC_t* SYNC; /**< SYNC object, initialised by @ref CO_SYNC_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_SYNC; /**< Start index in CANrx. */
    uint16_t TX_IDX_SYNC; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN
    CO_RPDO_t* RPDO; /**< RPDO objects, initialised by @ref CO_RPDO_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_RPDO; /**< Start index in CANrx. */
#endif
#endif
#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN
    CO_TPDO_t* TPDO; /**< TPDO objects, initialised by @ref CO_TPDO_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t TX_IDX_TPDO; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_LEDS)&CO_CONFIG_LEDS_ENABLE) != 0) || defined CO_DOXYGEN
    CO_LEDs_t* LEDs; /**< LEDs object, initialised by @ref CO_LEDs_init() */
#endif
#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || defined CO_DOXYGEN
    CO_GFC_t* GFC; /**< GFC object, initialised by @ref CO_GFC_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_GFC; /**< Start index in CANrx. */
    uint16_t TX_IDX_GFC; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN
    CO_SRDOGuard_t* SRDOGuard; /**< SRDO guard object, initialised by CO_SRDOGuard_init(), single SRDOGuard object is
                                  included inside all SRDO objects */
    CO_SRDO_t* SRDO;           /**< SRDO objects, initialised by @ref CO_SRDO_init() */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_SRDO; /**< Start index in CANrx. */
    uint16_t TX_IDX_SRDO; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN
    CO_LSSslave_t* LSSslave; /**< LSS slave object, initialised by @ref CO_LSSslave_init(). */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_LSS_SLV; /**< Start index in CANrx. */
    uint16_t TX_IDX_LSS_SLV; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_MASTER) != 0) || defined CO_DOXYGEN
    CO_LSSmaster_t* LSSmaster; /**< LSS master object, initialised by @ref CO_LSSmaster_init(). */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
    uint16_t RX_IDX_LSS_MST; /**< Start index in CANrx. */
    uint16_t TX_IDX_LSS_MST; /**< Start index in CANtx. */
#endif
#endif
#if (((CO_CONFIG_GTW)&CO_CONFIG_GTW_ASCII) != 0) || defined CO_DOXYGEN
    CO_GTWA_t* gtwa; /**< Gateway-ascii object, initialised by @ref CO_GTWA_init(). */
#if defined CO_MULTIPLE_OD || defined CO_DOXYGEN
#endif
#endif
#if ((CO_CONFIG_TRACE)&CO_CONFIG_TRACE_ENABLE) || defined CO_DOXYGEN
    CO_trace_t* trace; /**< Trace object, initialised by @ref CO_trace_init(). */
#endif
} CO_t;

/**
 * Create new CANopen object
 *
 * If CO_USE_GLOBALS is defined, then function uses global static variables for all the CANopenNode objects. Otherwise
 * it allocates all objects from heap.
 *
 * @remark
 * With some microcontrollers it is necessary to specify Heap size within linker configuration, if heap is used.
 *
 * @param config Configuration structure, used if @ref CO_MULTIPLE_OD is defined. It must stay in memory permanently. If
 * CO_MULTIPLE_OD is not defined, config should be NULL and parameters are retrieved from default "OD.h" file.
 * @param [out] heapMemoryUsed Information about heap memory used. Ignored if NULL.
 *
 * @return Successfully allocated and configured CO_t object or NULL.
 */
CO_t* CO_new(CO_config_t* config, uint32_t* heapMemoryUsed);

/**
 * Delete CANopen object and free memory. Must be called at program exit.
 *
 * @param co CANopen object.
 */
void CO_delete(CO_t* co);

/**
 * Test if LSS slave is enabled
 *
 * @param co CANopen object.
 *
 * @return True if enabled
 */
bool_t CO_isLSSslaveEnabled(CO_t* co);

/**
 * Initialize CAN driver
 *
 * Function must be called in the communication reset section.
 *
 * @param co CANopen object.
 * @param CANptr Pointer to the user-defined CAN base structure, passed to CO_CANmodule_init().
 * @param bitRate CAN bit rate.
 * @return CO_ERROR_NO in case of success.
 */
CO_ReturnError_t CO_CANinit(CO_t* co, void* CANptr, uint16_t bitRate);

#if (((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0) || defined CO_DOXYGEN
/**
 * Initialize CANopen LSS slave
 *
 * Function must be called before CO_CANopenInit.
 *
 * See @ref CO_LSSslave_init() for description of parameters.
 *
 * @param co CANopen object.
 * @param lssAddress LSS slave address, from OD object 0x1018
 * @param [in,out] pendingNodeID Pending node ID or 0xFF (unconfigured)
 * @param [in,out] pendingBitRate Pending bit rate of the CAN interface
 *
 * @return CO_ERROR_NO in case of success.
 */
CO_ReturnError_t CO_LSSinit(CO_t* co, CO_LSS_address_t* lssAddress, uint8_t* pendingNodeID, uint16_t* pendingBitRate);
#endif

/**
 * Initialize CANopenNode except PDO objects.
 *
 * Function must be called in the communication reset section.
 *
 * @param co CANopen object.
 * @param em Emergency object, which is used inside different CANopen objects, usually for error reporting. If NULL,
 * then 'co->em' will be used. if NULL and 'co->CNT_EM' is 0, then function returns with error.
 * @param NMT If 'co->CNT_NMT' is 0, this object must be specified, If 'co->CNT_NMT' is 1,then it is ignored and can be
 * NULL. NMT object is used for retrieving NMT internal state inside CO_process().
 * @param od CANopen Object dictionary
 * @param OD_statusBits Argument passed to @ref CO_EM_init(). May be NULL.
 * @param NMTcontrol Argument passed to @ref CO_NMT_init().
 * @param firstHBTime_ms Argument passed to @ref CO_NMT_init().
 * @param SDOserverTimeoutTime_ms Argument passed to @ref CO_SDOserver_init().
 * @param SDOclientTimeoutTime_ms Default timeout in milliseconds for SDO client, 500 typically. SDO client is
 * configured from CO_GTWA_init().
 * @param SDOclientBlockTransfer If true, block transfer will be set in SDO client by default. SDO client is configured
 * from by CO_GTWA_init().
 * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). In the CANopen initialization it is the same as
 * pendingBitRate from CO_LSSinit(). If it is unconfigured, then some CANopen objects will not be initialized nor
 * processed.
 * @param [out] errInfo Additional information in case of error, may be NULL. errInfo can also be set in noncritical
 * errors, where function returns CO_ERROR_NO. For example, if OD parameter contains wrong value.
 *
 * @return CO_ERROR_NO in case of success.
 */
CO_ReturnError_t CO_CANopenInit(CO_t* co, CO_NMT_t* NMT, CO_EM_t* em, OD_t* od, OD_entry_t* OD_statusBits,
                                uint16_t NMTcontrol, uint16_t firstHBTime_ms, uint16_t SDOserverTimeoutTime_ms,
                                uint16_t SDOclientTimeoutTime_ms, bool_t SDOclientBlockTransfer, uint8_t nodeId,
                                uint32_t* errInfo);

/**
 * Initialize CANopenNode PDO objects.
 *
 * Function must be called in the end of communication reset section after all CANopen and application initialization,
 * otherwise some OD variables wont be mapped into PDO correctly.
 *
 * @param co CANopen object.
 * @param em Emergency object, which is used inside PDO objects for error reporting.
 * @param od CANopen Object dictionary
 * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If unconfigured, then PDO will not be initialized
 * nor processed.
 * @param [out] errInfo Additional information in case of error, may be NULL.
 *
 * @return CO_ERROR_NO in case of success.
 */
CO_ReturnError_t CO_CANopenInitPDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo);

/**
 * Initialize Safety related Data Objects.
 *
 * Function must be called in the end of communication reset section after all CANopen and application initialization,
 * otherwise some OD variables wont be mapped into SRDO correctly.
 *
 * @param co CANopen object.
 * @param em Emergency object, which is used inside PDO objects for error reporting.
 * @param od CANopen Object dictionary
 * @param nodeId CANopen Node ID (1 ... 127) or 0xFF(unconfigured). If unconfigured, then PDO will not be initialized
 * nor processed.
 * @param [out] errInfo Additional information in case of error, may be NULL.
 *
 * @return #CO_ERROR_NO in case of success.
 */
#if (((CO_CONFIG_GFC)&CO_CONFIG_GFC_ENABLE) != 0) || (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0)                   \
    || defined CO_DOXYGEN
CO_ReturnError_t CO_CANopenInitSRDO(CO_t* co, CO_EM_t* em, OD_t* od, uint8_t nodeId, uint32_t* errInfo);
#endif

/**
 * Process CANopen objects.
 *
 * Function must be called cyclically. It processes all "asynchronous" CANopen objects.
 *
 * @param co CANopen object.
 * @param enableGateway If true, gateway to external world will be enabled.
 * @param timeDifference_us Time difference from previous function call in microseconds.
 * @param [out] timerNext_us info to OS - maximum delay time after this function should be called next time in
 * [microseconds]. Value can be used for OS sleep time. Initial value must be set to maximum interval time. Output will
 * be equal or lower to initial value. Calculation is based on various timers which expire in known time. Parameter
 * should be used in combination with callbacks configured with CO_***_initCallbackPre() functions. Those callbacks
 * should also trigger calling of CO_process() function. Parameter is ignored if NULL. See also @ref
 * CO_CONFIG_FLAG_CALLBACK_PRE configuration macro.
 *
 * @return Node or communication reset request, from @ref CO_NMT_process().
 */
CO_NMT_reset_cmd_t CO_process(CO_t* co, bool_t enableGateway, uint32_t timeDifference_us, uint32_t* timerNext_us);

#if (((CO_CONFIG_SYNC)&CO_CONFIG_SYNC_ENABLE) != 0) || defined CO_DOXYGEN
/**
 * Process CANopen SYNC objects.
 *
 * Function must be called cyclically. For time critical applications it may be called from real time thread with
 * constant interval (1ms typically). It processes SYNC CANopen objects.
 *
 * @param co CANopen object.
 * @param timeDifference_us Time difference from previous function call in microseconds.
 * @param [out] timerNext_us info to OS - see CO_process().
 *
 * @return True, if CANopen SYNC message was just received or transmitted.
 */
bool_t CO_process_SYNC(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us);
#endif

#if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_ENABLE) != 0) || defined CO_DOXYGEN
/**
 * Process CANopen RPDO objects.
 *
 * Function must be called cyclically. For time critical applications it may be called from real time thread with
 * constant interval (1ms typically). It processes receive PDO CANopen objects.
 *
 * @param co CANopen object.
 * @param syncWas True, if CANopen SYNC message was just received or transmitted.
 * @param timeDifference_us Time difference from previous function call in microseconds.
 * @param [out] timerNext_us info to OS - see CO_process().
 */
void CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us);
#endif

#if (((CO_CONFIG_PDO)&CO_CONFIG_TPDO_ENABLE) != 0) || defined CO_DOXYGEN
/**
 * Process CANopen TPDO objects.
 *
 * Function must be called cyclically. For time critical applications it may be called from real time thread with
 * constant interval (1ms typically). It processes transmit PDO CANopen objects.
 *
 * @param co CANopen object.
 * @param syncWas True, if CANopen SYNC message was just received or transmitted.
 * @param timeDifference_us Time difference from previous function call in microseconds.
 * @param [out] timerNext_us info to OS - see CO_process().
 */
void CO_process_TPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* timerNext_us);
#endif

#if (((CO_CONFIG_SRDO)&CO_CONFIG_SRDO_ENABLE) != 0) || defined CO_DOXYGEN
/**
 * Process CANopen SRDO objects.
 *
 * Function must be called cyclically. For time critical applications it may be called from real time thread with
 * constant interval (1ms typically). It processes SRDO CANopen objects.
 *
 * @param co CANopen object.
 * @param timeDifference_us Time difference from previous function call in microseconds.
 * @param [out] timerNext_us info to OS - see CO_process().
 *
 * @return #CO_SRDO_state_t: lowest state of the SRDO objects.
 */
CO_SRDO_state_t CO_process_SRDO(CO_t* co, uint32_t timeDifference_us, uint32_t* timerNext_us);
#endif

/** @} */ /* CO_CANopen */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* CANopen_H */
