1
0
Fork 0

301/CO_PDO.h/c updated to newOD.

This commit is contained in:
Janez 2021-03-18 15:13:06 +01:00
parent 926b59f3fd
commit 66d0e14ef4
18 changed files with 1969 additions and 1445 deletions

View file

@ -63,7 +63,7 @@ static ODR_t OD_read_1014(OD_stream_t *stream, void *buf,
OD_size_t count, OD_size_t *countRead)
{
if (stream == NULL || stream->subIndex != 0 || buf == NULL
|| count != sizeof(uint32_t) || countRead == NULL
|| count < sizeof(uint32_t) || countRead == NULL
) {
return ODR_DEV_INCOMPAT;
}
@ -134,7 +134,7 @@ static ODR_t OD_read_1014_default(OD_stream_t *stream, void *buf,
OD_size_t count, OD_size_t *countRead)
{
if (stream == NULL || stream->subIndex != 0 || buf == NULL
|| count != sizeof(uint32_t) || countRead == NULL
|| count < sizeof(uint32_t) || countRead == NULL
) {
return ODR_DEV_INCOMPAT;
}

View file

@ -295,8 +295,8 @@ typedef enum {
CO_EM_TPDO_OUTSIDE_WINDOW = 0x15U,
/** 0x16, communication, critical, (unused) */
CO_EM_16_unused = 0x16U,
/** 0x17, communication, critical, (unused) */
CO_EM_17_unused = 0x17U,
/** 0x17, communication, critical, RPDO message timeout */
CO_EM_RPDO_TIME_OUT = 0x17U,
/** 0x18, communication, critical, SYNC message timeout */
CO_EM_SYNC_TIME_OUT = 0x18U,
/** 0x19, communication, critical, Unexpected SYNC data length */

View file

@ -44,7 +44,10 @@ extern "C" {
typedef uint32_t OD_size_t;
/** Type (and size) of Object Dictionary attribute */
typedef uint8_t OD_attr_t;
/** Size of of flagsPDO variable inside OD_extension_t, from 1 to 64 */
#endif
#ifndef OD_FLAGS_PDO_SIZE
/** Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */
#define OD_FLAGS_PDO_SIZE 4
#endif
@ -252,6 +255,10 @@ typedef struct {
* not large enough. ("*returnCode" must not return 'ODR_PARTIAL', if there
* is still space in "buf".)
*
* @warning When accessing OD variables by calling the read() function, it
* may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros.
* See @ref CO_critical_sections for more information.
*
* @param stream Object Dictionary stream object.
* @param buf Pointer to external buffer, where to data will be copied.
* @param count Size of the external buffer in bytes.
@ -279,6 +286,10 @@ typedef struct {
* "write" function must always copy all available data from buf. If OD
* variable expect more data, then "*returnCode" must return 'ODR_PARTIAL'.
*
* @warning When accessing OD variables by calling the read() function, it
* may be necessary to use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros.
* See @ref CO_critical_sections for more information.
*
* @param stream Object Dictionary stream object.
* @param buf Pointer to external buffer, from where data will be copied.
* @param count Size of the external buffer in bytes.
@ -309,24 +320,19 @@ typedef struct {
* write function. For function description see @ref OD_IO_t. */
ODR_t (*write)(OD_stream_t *stream, const void *buf,
OD_size_t count, OD_size_t *countWritten);
/**
* PDO flags bit-field. If available, then each sub-element is coupled
* with own flagsPDO variable of size 8 to 512 bits (size is configurable
* by @ref OD_FLAGS_PDO_SIZE). Flag is useful, when variable is mapped to
* RPDO or TPDO.
#if OD_FLAGS_PDO_SIZE > 0
/**PDO flags bit-field provides one bit for each OD variable, which exist
* inside OD object at specific sub index. If application clears that bit,
* and OD variable is mapped to an event driven TPDO, then TPDO will be
* sent.
*
* If sub-element is mapped to RPDO, then bit0 is set to 1 each time, when
* any RPDO writes new data into variable. Application may clear bit0.
*
* If sub-element is mapped to TPDO, then TPDO will set one bit on the time,
* it is sent. First TPDO will set bit1, second TPDO will set bit2, etc.
*
* Another functionality is with asynchronous TPDOs, to which variable may
* be mapped. If corresponding bit is 0, TPDO will be sent. This means, that
* if application sets variable pointed by flagsPDO to zero, it will trigger
* sending all asynchronous TPDOs, to which variable is mapped.
*/
* @ref OD_FLAGS_PDO_SIZE can have a value from 0 to 32 bytes, which
* corresponds to 0 to 256 available bits. If, for example,
* @ref OD_FLAGS_PDO_SIZE has value 4, then OD variables with sub index up
* to 31 will have the TPDO requesting functionality.
* See also @ref OD_requestTPDO and @ref OD_TPDOtransmitted. */
uint8_t flagsPDO[OD_FLAGS_PDO_SIZE];
#endif
} OD_extension_t;
@ -462,6 +468,78 @@ static inline void OD_rwRestart(OD_stream_t *stream) {
}
/**
* Get TPDO request flags for OD entry.
*
* flagsPDO can be used for @ref OD_requestTPDO() or @ref OD_TPDOtransmitted().
*
* @param entry OD entry returned by @ref OD_find().
*
* @return pointer to flagsPDO
*/
static inline uint8_t *OD_getFlagsPDO(OD_entry_t *entry) {
#if OD_FLAGS_PDO_SIZE > 0
if (entry != NULL && entry->extension != NULL) {
return &entry->extension->flagsPDO[0];
}
#endif
return 0;
}
/**
* Request TPDO, to which OD variable is mapped
*
* Function clears the flagPDO bit, which corresponds to OD variable at specific
* OD index and subindex. For this functionality to work, @ref OD_extension_t
* must be enabled on OD variable. If OD variable is mapped to any TPDO with
* event driven transmission, then TPDO will be transmitted after this function
* call. If OD variable is mapped to more than one TPDO with event driven
* transmission, only the first matched TPDO will be transmitted.
*
* TPDO event driven transmission is enabled, if TPDO communication parameter,
* transmission type is set to 0, 254 or 255. For other transmission types
* (synchronous) flagPDO bit is ignored.
*
* @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO.
* @param subIndex subIndex of the OD variable.
*/
static inline void OD_requestTPDO(uint8_t *flagsPDO, uint8_t subIndex) {
#if OD_FLAGS_PDO_SIZE > 0
if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) {
/* clear subIndex-th bit */
uint8_t mask = ~(1 << (subIndex & 0x07));
flagsPDO[subIndex >> 3] &= mask;
}
#endif
}
/**
* Check if requested TPDO was transmitted
*
* @param flagsPDO TPDO request flags returned by @ref OD_getFlagsPDO.
* @param subIndex subIndex of the OD variable.
*
* @return Return true if event driven TPDO with mapping to OD variable,
* indicated by flagsPDO and subIndex, was transmitted since last
* @ref OD_requestTPDO call. If there was no @ref OD_requestTPDO call yet and
* TPDO was transmitted by other event, function also returns true.
*/
static inline bool_t OD_TPDOtransmitted(uint8_t *flagsPDO, uint8_t subIndex) {
#if OD_FLAGS_PDO_SIZE > 0
if (flagsPDO != NULL && subIndex < (OD_FLAGS_PDO_SIZE * 8)) {
/* return true, if subIndex-th bit is set */
uint8_t mask = 1 << (subIndex & 0x07);
if ((flagsPDO[subIndex >> 3] & mask) != 0) {
return true;
}
}
#endif
return false;
}
/**
* Get SDO abort code from returnCode
*

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
* @file CO_PDO.h
* @ingroup CO_PDO
* @author Janez Paternoster
* @copyright 2004 - 2020 Janez Paternoster
* @copyright 2021 Janez Paternoster
*
* This file is part of CANopenNode, an opensource CANopen Stack.
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
@ -26,18 +26,19 @@
#ifndef CO_PDO_H
#define CO_PDO_H
#include "301/CO_driver.h"
#include "301/CO_SDOserver.h"
#include "301/CO_ODinterface.h"
#include "301/CO_Emergency.h"
#include "301/CO_NMT_Heartbeat.h"
#include "301/CO_SYNC.h"
/* default configuration, see CO_config.h */
#ifndef CO_CONFIG_PDO
#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \
CO_CONFIG_TPDO_ENABLE | \
CO_CONFIG_RPDO_TIMERS_ENABLE | \
CO_CONFIG_TPDO_TIMERS_ENABLE | \
CO_CONFIG_PDO_SYNC_ENABLE | \
CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \
CO_CONFIG_PDO_OD_IO_ACCESS | \
CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \
CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \
CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
@ -60,249 +61,247 @@ extern "C" {
*
* TPDO with specific identifier is transmitted by one device and recieved by
* zero or more devices as RPDO. PDO communication parameters(COB-ID,
* transmission type, etc.) are in Object Dictionary at index 0x1400+ and
* 0x1800+. PDO mapping parameters (size and contents of the PDO) are in Object
* Dictionary at index 0x1600+ and 0x1A00+.
* transmission type, etc.) are in the Object Dictionary at index 0x1400+ and
* 0x1800+. PDO mapping parameters (size and contents of the PDO) are in the
* Object Dictionary at index 0x1600+ and 0x1A00+.
*
* Features of the PDO as implemented here, in CANopenNode:
* Features of the PDO as implemented in CANopenNode:
* - Dynamic PDO mapping.
* - Map granularity of one byte.
* - After RPDO is received from CAN bus, its data are copied to buffer.
* Function CO_RPDO_process() (called by application) copies data to
* mapped objects in Object Dictionary. Synchronous RPDOs are processed AFTER
* reception of the next SYNC message.
* - Function CO_TPDO_process() (called by application) sends TPDO if
* necessary. There are possible different transmission types, including
* automatic detection of Change of State of specific variable.
* - Data from OD variables are accessed via @ref OD_IO_t read()/write()
* functions, which gives a great usefulness to the application.
* - For systems with very low memory and processing capabilities there is a
* simplified @ref CO_CONFIG_PDO option, where instead of read()/write()
* access, PDO data are copied directly to/from memory locations of
* OD variables.
* - After RPDO is received from CAN bus, its data are copied to internal
* buffer (inside fast CAN receive interrupt). Function CO_RPDO_process()
* (called by application) copies data to the mapped objects in the Object
* Dictionary. Synchronous RPDOs are processed AFTER reception of the next
* SYNC message.
* - Function CO_TPDO_process() (called by application) sends TPDO when
* necessary. There are different transmission types possible, controlled by:
* SYNC message, event timer, @ref CO_TPDOsendRequest() by application or
* @ref OD_requestTPDO(), where application can request TPDO for OD
* variable mapped to any of them. In later case application may, for
* example, monitor change of state of the OD variable and indicate TPDO
* request on it.
*
* @anchor CO_PDO_CAN_ID
* ### CAN identifiers for PDO
* Each PDO can be configured with any valid 11-bit CAN identifier. Lower
* numbers have higher priorities on CAN bus. As a general rule, each CAN
* message is identified with own CAN-ID, which must be unique and produced by
* single source. The same is with PDO objects: Any TPDO produced on the CANopen
* network must have unique CAN-ID and there can be zero to many RPDOs (from
* different devices) configured to match the CAN-ID of the TPDO of interest.
*
* CANopen standard provides pre-defined connection sets for four RPDOs and four
* TPDOs on each device with specific 7-bit Node-ID. These are default values
* and are usable in configuration, where CANopen network contains a master
* device, which directly communicates with many slaves. In de-centralized
* systems, where devices operate without a master, it makes sense to configure
* CAN-IDs of the RPDOs to the non-default values.
*
* Default CAN identifiers for first four TPDOs on device with specific CANopen
* Node-Id are: 0x180+NodeId, 0x280+NodeId, 0x380+NodeId and 0x480+NodeId.
*
* Default CAN identifiers for first four RPDOs on device with specific CANopen
* Node-Id are: 0x200+NodeId, 0x300+NodeId, 0x400+NodeId and 0x500+NodeId.
*
* CANopenNode handles default (pre-defined) CAN-IDs. If it is detected, that
* PDO is configured with default CAN-ID (when writing to OD variable PDO
* communication parameter, COB-ID), then COB-ID is stored without Node-Id to
* the Object Dictionary. If Node-ID is changed, then COB-ID will always contain
* correct default CAN-ID (default CAN-ID + Node-ID). If PDO is configured with
* non-default CAN-ID, then it will be stored to the Object Dictionary as is.
*
* If configuration CO_CONFIG_FLAG_OD_DYNAMIC is enabled in @ref CO_CONFIG_PDO,
* then PDOs can be configured dynamically, also in NMT operational state.
* Otherwise PDOs are configured only in reset communication section and also
* default CAN-IDs are always stored to OD as is, no default node-id is handled.
*
* Configure PDO by writing to the OD variables in the following procedure:
* - Disable the PDO by setting bit-31 to 1 in PDO communication parameter,
* COB-ID
* - Node-Id can be configured only when PDO is disabled.
* - Disable mapping by setting PDO mapping parameter, sub index 0 to 0
* - Configure mapping
* - Enable mapping by setting PDO mapping param, sub 0 to number of mapped
* objects
* - Enable the PDO by setting bit-31 to 0 in PDO communication parameter,
* COB-ID
*/
/** Maximum size of PDO message, 8 for standard CAN */
#ifndef CO_PDO_MAX_SIZE
#define CO_PDO_MAX_SIZE 8
#endif
/** Maximum number of entries, which can be mapped to PDO, 8 for standard CAN,
* may be less to preserve RAM usage */
#ifndef CO_PDO_MAX_MAPPED_ENTRIES
#define CO_PDO_MAX_MAPPED_ENTRIES 8
#endif
#ifndef CO_PDO_OWN_TYPES
/** Variable of type CO_PDO_size_t contains data length in bytes of PDO */
typedef uint8_t CO_PDO_size_t;
#endif
/**
* RPDO communication parameter. The same as record from Object dictionary (index 0x1400+).
* PDO transmission Types
*/
typedef struct{
uint8_t maxSubIndex; /**< Equal to 2 */
/** Communication object identifier for message received. Meaning of the specific bits:
- Bit 0-10: COB-ID for PDO, to change it bit 31 must be set.
- Bit 11-29: set to 0 for 11 bit COB-ID.
- Bit 30: If true, rtr are NOT allowed for PDO.
- Bit 31: If true, node does NOT use the PDO. */
uint32_t COB_IDUsedByRPDO;
/** Transmission type. Values:
- 0-240: Reciving is synchronous, process after next reception of the SYNC object.
- 241-253: Not used.
- 254: Manufacturer specific.
- 255: Asynchronous. */
uint8_t transmissionType;
}CO_RPDOCommPar_t;
typedef enum {
CO_PDO_TRANSM_TYPE_SYNC_ACYCLIC = 0, /**< synchronous (acyclic) */
CO_PDO_TRANSM_TYPE_SYNC_1 = 1, /**< synchronous (cyclic every sync) */
CO_PDO_TRANSM_TYPE_SYNC_240 = 0xF0, /**< synchronous (cyclic every 240-th
sync) */
CO_PDO_TRANSM_TYPE_SYNC_EVENT_LO = 0xFE, /**< event-driven, lower value
(manufacturer specific), */
CO_PDO_TRANSM_TYPE_SYNC_EVENT_HI = 0xFF /**< event-driven, higher value
(device profile and application profile specific) */
} CO_PDO_transmissionTypes_t;
/**
* RPDO mapping parameter. The same as record from Object dictionary (index 0x1600+).
* PDO object, common properties
*/
typedef struct{
/** Actual number of mapped objects from 0 to 8. To change mapped object,
this value must be 0. */
uint8_t numberOfMappedObjects;
/** Location and size of the mapped object. Bit meanings `0xIIIISSLL`:
- Bit 0-7: Data Length in bits.
- Bit 8-15: Subindex from object distionary.
- Bit 16-31: Index from object distionary. */
uint32_t mappedObject1;
uint32_t mappedObject2; /**< Same */
uint32_t mappedObject3; /**< Same */
uint32_t mappedObject4; /**< Same */
uint32_t mappedObject5; /**< Same */
uint32_t mappedObject6; /**< Same */
uint32_t mappedObject7; /**< Same */
uint32_t mappedObject8; /**< Same */
}CO_RPDOMapPar_t;
typedef struct {
/** From CO_xPDO_init() */
CO_EM_t *em;
/** From CO_xPDO_init() */
CO_CANmodule_t *CANdev;
/** True, if PDO is enabled and valid */
bool_t valid;
/** Data length of the received PDO message. Calculated from mapping */
CO_PDO_size_t dataLength;
/** Number of mapped objects in PDO */
uint8_t mappedObjectsCount;
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_OD_IO_ACCESS) || defined CO_DOXYGEN
/** Object dictionary interface for all mapped entries. OD_IO.dataOffset has
* special usage with PDO. It stores information about mappedLength of
* the variable. mappedLength can be less or equal to the OD_IO.dataLength.
* mappedLength greater than OD_IO.dataLength indicates erroneous mapping.
* OD_IO.dataOffset is set to 0 before read/write function call and after
* the call OD_IO.dataOffset is set back to mappedLength. */
OD_IO_t OD_IO[CO_PDO_MAX_MAPPED_ENTRIES];
#if OD_FLAGS_PDO_SIZE > 0
/** Pointer to byte, which contains PDO flag bit from @ref OD_extension_t */
uint8_t *flagPDObyte[CO_PDO_MAX_MAPPED_ENTRIES];
/** Bitmask for the flagPDObyte */
uint8_t flagPDObitmask[CO_PDO_MAX_MAPPED_ENTRIES];
#endif
#else
/* Pointers to data objects inside OD, where PDO will be copied */
uint8_t *mapPointer[CO_PDO_MAX_SIZE];
#if OD_FLAGS_PDO_SIZE > 0
uint8_t *flagPDObyte[CO_PDO_MAX_SIZE];
uint8_t flagPDObitmask[CO_PDO_MAX_SIZE];
#endif
#endif
#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_OD_DYNAMIC) || defined CO_DOXYGEN
/** True for RPDO, false for TPDO */
bool_t isRPDO;
/** From CO_xPDO_init() */
OD_t *OD;
/** From CO_xPDO_init() */
uint16_t CANdevIdx;
/** From CO_xPDO_init() */
uint16_t preDefinedCanId;
/** Currently configured CAN identifier */
uint16_t configuredCanId;
/** Extension for OD object */
OD_extension_t OD_communicationParam_ext;
/** Extension for OD object */
OD_extension_t OD_mappingParam_extension;
#endif
} CO_PDO_common_t;
/*******************************************************************************
* R P D O
******************************************************************************/
#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE) || defined CO_DOXYGEN
/**
* TPDO communication parameter. The same as record from Object dictionary (index 0x1800+).
* Number of buffers for received CAN message for RPDO
*/
typedef struct{
uint8_t maxSubIndex; /**< Equal to 6 */
/** Communication object identifier for transmitting message. Meaning of the specific bits:
- Bit 0-10: COB-ID for PDO, to change it bit 31 must be set.
- Bit 11-29: set to 0 for 11 bit COB-ID.
- Bit 30: If true, rtr are NOT allowed for PDO.
- Bit 31: If true, node does NOT use the PDO. */
uint32_t COB_IDUsedByTPDO;
/** Transmission type. Values:
- 0: Transmiting is synchronous, specification in device profile.
- 1-240: Transmiting is synchronous after every N-th SYNC object.
- 241-251: Not used.
- 252-253: Transmited only on reception of Remote Transmission Request.
- 254: Manufacturer specific.
- 255: Asinchronous, specification in device profile. */
uint8_t transmissionType;
/** Minimum time between transmissions of the PDO in 100micro seconds.
Zero disables functionality. */
uint16_t inhibitTime;
/** Not used */
uint8_t compatibilityEntry;
/** Time between periodic transmissions of the PDO in milliseconds.
Zero disables functionality. */
uint16_t eventTimer;
/** Used with numbered SYNC messages. Values:
- 0: Counter of the SYNC message shall not be processed.
- 1-240: The SYNC message with the counter value equal to this value
shall be regarded as the first received SYNC message. */
uint8_t SYNCStartValue;
}CO_TPDOCommPar_t;
/**
* TPDO mapping parameter. The same as record from Object dictionary (index 0x1A00+).
*/
typedef struct{
/** Actual number of mapped objects from 0 to 8. To change mapped object,
this value must be 0. */
uint8_t numberOfMappedObjects;
/** Location and size of the mapped object. Bit meanings `0xIIIISSLL`:
- Bit 0-7: Data Length in bits.
- Bit 8-15: Subindex from object distionary.
- Bit 16-31: Index from object distionary. */
uint32_t mappedObject1;
uint32_t mappedObject2; /**< Same */
uint32_t mappedObject3; /**< Same */
uint32_t mappedObject4; /**< Same */
uint32_t mappedObject5; /**< Same */
uint32_t mappedObject6; /**< Same */
uint32_t mappedObject7; /**< Same */
uint32_t mappedObject8; /**< Same */
}CO_TPDOMapPar_t;
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
#define CO_RPDO_CAN_BUFFERS_COUNT 2
#else
#define CO_RPDO_CAN_BUFFERS_COUNT 1
#endif
/**
* RPDO object.
*/
typedef struct{
CO_EM_t *em; /**< From CO_RPDO_init() */
CO_SDO_t *SDO; /**< From CO_RPDO_init() */
const CO_RPDOCommPar_t *RPDOCommPar;/**< From CO_RPDO_init() */
const CO_RPDOMapPar_t *RPDOMapPar; /**< From CO_RPDO_init() */
CO_NMT_internalState_t *operatingState; /**< From CO_RPDO_init() */
uint8_t nodeId; /**< From CO_RPDO_init() */
uint16_t defaultCOB_ID; /**< From CO_RPDO_init() */
uint8_t restrictionFlags;/**< From CO_RPDO_init() */
/** True, if PDO is enabled and valid */
bool_t valid;
/** Data length of the received PDO message. Calculated from mapping */
uint8_t dataLength;
/** Pointers to 8 data objects, where PDO will be copied */
uint8_t *mapPointer[8];
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
CO_SYNC_t *SYNC; /**< From CO_RPDO_init() */
/** True, if PDO synchronous (transmissionType <= 240) */
bool_t synchronous;
typedef struct {
/** PDO common properties, must be first element in this object */
CO_PDO_common_t PDO_common;
/** Variable indicates, if new PDO message received from CAN bus. */
volatile void *CANrxNew[2];
/** 8 data bytes of the received message. */
uint8_t CANrxData[2][8];
#else
volatile void *CANrxNew[1];
uint8_t CANrxData[1][8];
volatile void *CANrxNew[CO_RPDO_CAN_BUFFERS_COUNT];
/** CO_PDO_MAX_SIZE data bytes of the received message. */
uint8_t CANrxData[CO_RPDO_CAN_BUFFERS_COUNT][CO_PDO_MAX_SIZE];
/** Indication of RPDO length errors, use with CO_PDO_receiveErrors_t */
uint8_t receiveError;
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
/** From CO_RPDO_init() */
CO_SYNC_t *SYNC;
/** True if transmissionType <= 240 */
bool_t synchronous;
#endif
#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN
/** Maximum timeout time between received PDOs in microseconds. Configurable
* by OD variable RPDO communication parameter, event-timer. */
uint32_t timeoutTime_us;
/** Timeout timer variable in microseconds */
uint32_t timeoutTimer;
#endif
#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN
/** From CO_RPDO_initCallbackPre() or NULL */
void (*pFunctSignalPre)(void *object);
void (*pFunctSignalPre)(void *object);
/** From CO_RPDO_initCallbackPre() or NULL */
void *functSignalObjectPre;
void *functSignalObjectPre;
#endif
CO_CANmodule_t *CANdevRx; /**< From CO_RPDO_init() */
uint16_t CANdevRxIdx; /**< From CO_RPDO_init() */
}CO_RPDO_t;
/**
* TPDO object.
*/
typedef struct{
CO_EM_t *em; /**< From CO_TPDO_init() */
CO_SDO_t *SDO; /**< From CO_TPDO_init() */
const CO_TPDOCommPar_t *TPDOCommPar;/**< From CO_TPDO_init() */
const CO_TPDOMapPar_t *TPDOMapPar; /**< From CO_TPDO_init() */
CO_NMT_internalState_t *operatingState; /**< From CO_TPDO_init() */
uint8_t nodeId; /**< From CO_TPDO_init() */
uint16_t defaultCOB_ID; /**< From CO_TPDO_init() */
uint8_t restrictionFlags;/**< From CO_TPDO_init() */
bool_t valid; /**< True, if PDO is enabled and valid */
/** Data length of the transmitting PDO message. Calculated from mapping */
uint8_t dataLength;
/** If application set this flag, PDO will be later sent by
function CO_TPDO_process(). Depends on transmission type. */
uint8_t sendRequest;
/** Pointers to 8 data objects, where PDO will be copied */
uint8_t *mapPointer[8];
/** Inhibit timer used for inhibit PDO sending translated to microseconds */
uint32_t inhibitTimer;
/** Event timer used for PDO sending translated to microseconds */
uint32_t eventTimer;
/** Each flag bit is connected with one mapPointer. If flag bit
is true, CO_TPDO_process() functiuon will send PDO if
Change of State is detected on value pointed by that mapPointer */
uint8_t sendIfCOSFlags;
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
/** SYNC counter used for PDO sending */
uint8_t syncCounter;
CO_SYNC_t *SYNC; /**< From CO_TPDO_init() */
#endif
CO_CANmodule_t *CANdevTx; /**< From CO_TPDO_init() */
CO_CANtx_t *CANtxBuff; /**< CAN transmit buffer inside CANdev */
uint16_t CANdevTxIdx; /**< From CO_TPDO_init() */
}CO_TPDO_t;
} CO_RPDO_t;
/**
* Initialize RPDO object.
*
* Function must be called in the communication reset section.
* Function must be called in the end of the communication reset section, after
* all application initialization. Otherwise mapping to application OD variables
* will not be correct.
*
* @param RPDO This object will be initialized.
* @param OD Object Dictionary.
* @param em Emergency object.
* @param SDO SDO server object.
* @param SYNC void pointer to SYNC object or NULL.
* @param operatingState Pointer to variable indicating CANopen device NMT internal state.
* @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added.
* @param defaultCOB_ID Default COB ID for this PDO (without NodeId).
* See #CO_Default_CAN_ID_t
* @param restrictionFlags Flag bits indicates, how PDO communication
* and mapping parameters are handled:
* - Bit1: If true, communication parameters are writeable only in pre-operational NMT state.
* - Bit2: If true, mapping parameters are writeable only in pre-operational NMT state.
* - Bit3: If true, communication parameters are read-only.
* - Bit4: If true, mapping parameters are read-only.
* @param RPDOCommPar Pointer to _RPDO communication parameter_ record from Object
* dictionary (index 0x1400+).
* @param RPDOMapPar Pointer to _RPDO mapping parameter_ record from Object
* dictionary (index 0x1600+).
* @param idx_RPDOCommPar Index in Object Dictionary.
* @param idx_RPDOMapPar Index in Object Dictionary.
* @param SYNC SYNC object, may be NULL.
* @param preDefinedCanId CAN identifier from pre-defined connection set,
* including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID
* @param OD_14xx_RPDOCommPar OD entry for 0x1400+ - "RPDO communication
* parameter", entry is required.
* @param OD_16xx_RPDOMapPar OD entry for 0x1600+ - "RPDO mapping parameter",
* entry is required.
* @param CANdevRx CAN device for PDO reception.
* @param CANdevRxIdx Index of receive 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 or CO_ERROR_ILLEGAL_ARGUMENT.
* @return #CO_ReturnError_t CO_ERROR_NO on success.
*/
CO_ReturnError_t CO_RPDO_init(
CO_RPDO_t *RPDO,
CO_EM_t *em,
CO_SDO_t *SDO,
CO_ReturnError_t CO_RPDO_init(CO_RPDO_t *RPDO,
OD_t *OD,
CO_EM_t *em,
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
CO_SYNC_t *SYNC,
CO_SYNC_t *SYNC,
#endif
CO_NMT_internalState_t *operatingState,
uint8_t nodeId,
uint16_t defaultCOB_ID,
uint8_t restrictionFlags,
const CO_RPDOCommPar_t *RPDOCommPar,
const CO_RPDOMapPar_t *RPDOMapPar,
uint16_t idx_RPDOCommPar,
uint16_t idx_RPDOMapPar,
CO_CANmodule_t *CANdevRx,
uint16_t CANdevRxIdx);
uint16_t preDefinedCanId,
OD_entry_t *OD_14xx_RPDOCommPar,
OD_entry_t *OD_16xx_RPDOMapPar,
CO_CANmodule_t *CANdevRx,
uint16_t CANdevRxIdx,
uint32_t *errInfo);
#if ((CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE) || defined CO_DOXYGEN
@ -314,126 +313,150 @@ CO_ReturnError_t CO_RPDO_init(
* Callback is called after RPDO message is received from the CAN bus.
*
* @param RPDO This object.
* @param object Pointer to object, which will be passed to pFunctSignalPre(). Can be NULL
* @param object Pointer to object, which will be passed to pFunctSignalPre().
* @param pFunctSignalPre Pointer to the callback function. Not called if NULL.
*/
void CO_RPDO_initCallbackPre(
CO_RPDO_t *RPDO,
void *object,
void (*pFunctSignalPre)(void *object));
void CO_RPDO_initCallbackPre(CO_RPDO_t *RPDO,
void *object,
void (*pFunctSignalPre)(void *object));
#endif
/**
* Initialize TPDO object.
*
* Function must be called in the communication reset section.
*
* @param TPDO This object will be initialized.
* @param em Emergency object.
* @param SDO SDO object.
* @param SYNC void pointer to SYNC object or NULL.
* @param operatingState Pointer to variable indicating CANopen device NMT internal state.
* @param nodeId CANopen Node ID of this device. If default COB_ID is used, value will be added.
* @param defaultCOB_ID Default COB ID for this PDO (without NodeId).
* See #CO_Default_CAN_ID_t
* @param restrictionFlags Flag bits indicates, how PDO communication
* and mapping parameters are handled:
* - Bit1: If true, communication parameters are writeable only in pre-operational NMT state.
* - Bit2: If true, mapping parameters are writeable only in pre-operational NMT state.
* - Bit3: If true, communication parameters are read-only.
* - Bit4: If true, mapping parameters are read-only.
* @param TPDOCommPar Pointer to _TPDO communication parameter_ record from Object
* dictionary (index 0x1400+).
* @param TPDOMapPar Pointer to _TPDO mapping parameter_ record from Object
* dictionary (index 0x1600+).
* @param idx_TPDOCommPar Index in Object Dictionary.
* @param idx_TPDOMapPar Index in Object Dictionary.
* @param CANdevTx CAN device used for PDO transmission.
* @param CANdevTxIdx Index of transmit buffer in the above CAN device.
*
* @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
*/
CO_ReturnError_t CO_TPDO_init(
CO_TPDO_t *TPDO,
CO_EM_t *em,
CO_SDO_t *SDO,
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
CO_SYNC_t *SYNC,
#endif
CO_NMT_internalState_t *operatingState,
uint8_t nodeId,
uint16_t defaultCOB_ID,
uint8_t restrictionFlags,
const CO_TPDOCommPar_t *TPDOCommPar,
const CO_TPDOMapPar_t *TPDOMapPar,
uint16_t idx_TPDOCommPar,
uint16_t idx_TPDOMapPar,
CO_CANmodule_t *CANdevTx,
uint16_t CANdevTxIdx);
/**
* Verify Change of State of the PDO.
*
* Function verifies if variable mapped to TPDO has changed its value. Verified
* are only variables, which has set attribute _CO_ODA_TPDO_DETECT_COS_ in
* #CO_SDO_OD_attributes_t.
*
* Function may be called by application just before CO_TPDO_process() function,
* for example: `TPDOx->sendRequest = CO_TPDOisCOS(TPDOx); CO_TPDO_process(TPDOx, ....`
*
* @param TPDO TPDO object.
*
* @return True if COS was detected.
*/
uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO);
/**
* Send TPDO message.
*
* Function prepares TPDO data from Object Dictionary variables. It should not
* be called by application, it is called from CO_TPDO_process().
*
*
* @param TPDO TPDO object.
*
* @return Same as CO_CANsend().
*/
CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO);
/**
* Process received PDO messages.
*
* Function must be called cyclically in any NMT state. It copies data from RPDO
* to Object Dictionary variables if: new PDO receives and PDO is valid and NMT
* operating state is operational. It does not verify _transmission type_.
* operating state is operational. Synchronous RPDOs are processed after next
* SYNC message.
*
* @param RPDO This object.
* @param syncWas True, if CANopen SYNC message was just received or transmitted.
* @param timeDifference_us Time difference from previous function call.
* @param [out] timerNext_us info to OS - see CO_process().
* @param NMTisOperational True if this node is in NMT_OPERATIONAL state.
* @param syncWas True, if CANopen SYNC message was just received or
* transmitted.
*/
void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas);
void CO_RPDO_process(CO_RPDO_t *RPDO,
#if ((CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE) || defined CO_DOXYGEN
uint32_t timeDifference_us,
uint32_t *timerNext_us,
#endif
bool_t NMTisOperational,
bool_t syncWas);
#endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */
/*******************************************************************************
* T P D O
******************************************************************************/
#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE) || defined CO_DOXYGEN
/**
* TPDO object.
*/
typedef struct {
/** PDO common properties, must be first element in this object */
CO_PDO_common_t PDO_common;
/** CAN transmit buffer inside CANdev */
CO_CANtx_t *CANtxBuff;
/** Copy of the variable from object dictionary */
uint8_t transmissionType;
/** If this flag is set and TPDO is event driven (transmission type is 0,
* 254 or 255), then PDO will be sent by CO_TPDO_process(). */
bool_t sendRequest;
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
/** From CO_TPDO_init() */
CO_SYNC_t *SYNC;
/** Copy of the variable from object dictionary */
uint8_t syncStartValue;
/** SYNC counter used for PDO sending */
uint8_t syncCounter;
#endif
#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN
/** Inhibit time from object dictionary translated to microseconds */
uint32_t inhibitTime_us;
/** Event time from object dictionary translated to microseconds */
uint32_t eventTime_us;
/** Inhibit timer variable in microseconds */
uint32_t inhibitTimer;
/** Event timer variable in microseconds */
uint32_t eventTimer;
#endif
} CO_TPDO_t;
/**
* Initialize TPDO object.
*
* Function must be called in the end of the communication reset section, after
* all application initialization. Otherwise mapping to application OD variables
* will not be correct.
*
* @param TPDO This object will be initialized.
* @param OD Object Dictionary.
* @param em Emergency object.
* @param SYNC SYNC object, may be NULL.
* @param preDefinedCanId CAN identifier from pre-defined connection set,
* including node-id for first four PDOs, or 0 otherwise, see @ref CO_PDO_CAN_ID
* @param OD_18xx_TPDOCommPar OD entry for 0x1800+ - "TPDO communication
* parameter", entry is required.
* @param OD_1Axx_TPDOMapPar OD entry for 0x1A00+ - "TPDO mapping parameter",
* entry is required.
* @param CANdevTx CAN device used for PDO 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_TPDO_init(CO_TPDO_t *TPDO,
OD_t *OD,
CO_EM_t *em,
#if ((CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE) || defined CO_DOXYGEN
CO_SYNC_t *SYNC,
#endif
uint16_t preDefinedCanId,
OD_entry_t *OD_18xx_TPDOCommPar,
OD_entry_t *OD_1Axx_TPDOMapPar,
CO_CANmodule_t *CANdevTx,
uint16_t CANdevTxIdx,
uint32_t *errInfo);
/**
* Request transmission of TPDO message.
*
* If TPDO transmission type is 0, 254 or 255, then TPDO will be sent by
* @ref CO_TPDO_process() after inhibit timer expires. See also
* @ref OD_requestTPDO() and @ref OD_TPDOtransmitted().
*
* @param TPDO TPDO object.
*/
static inline void CO_TPDOsendRequest(CO_TPDO_t *TPDO) {
if (TPDO != NULL) TPDO->sendRequest = true;
}
/**
* Process transmitting PDO messages.
*
* Function must be called cyclically in any NMT state. It prepares and sends
* TPDO if necessary. If Change of State needs to be detected, function
* CO_TPDOisCOS() must be called before.
* TPDO if necessary.
*
* @param TPDO This 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 timeDifference_us Time difference from previous function call.
* @param [out] timerNext_us info to OS - see CO_process().
* @param NMTisOperational True if this node is in NMT_OPERATIONAL state.
* @param syncWas True, if CANopen SYNC message was just received or
* transmitted.
*/
void CO_TPDO_process(
CO_TPDO_t *TPDO,
bool_t syncWas,
uint32_t timeDifference_us,
uint32_t *timerNext_us);
void CO_TPDO_process(CO_TPDO_t *TPDO,
#if ((CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE) || defined CO_DOXYGEN
uint32_t timeDifference_us,
uint32_t *timerNext_us,
#endif
bool_t NMTisOperational,
bool_t syncWas);
#endif /* (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE */
/** @} */ /* CO_PDO */

View file

@ -360,7 +360,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
{
(void)timerNext_us; /* may be unused */
CO_SYNC_status_t ret = CO_SYNC_NONE;
CO_SYNC_status_t syncStatus = CO_SYNC_NONE;
if (NMTisPreOrOperational) {
/* update sync timer, no overflow */
@ -370,7 +370,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
/* was SYNC just received */
if (CO_FLAG_READ(SYNC->CANrxNew)) {
SYNC->timer = 0;
ret = CO_SYNC_RX_TX;
syncStatus = CO_SYNC_RX_TX;
CO_FLAG_CLEAR(SYNC->CANrxNew);
}
@ -381,7 +381,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER
if (SYNC->isProducer) {
if (SYNC->timer >= OD_1006_period) {
ret = CO_SYNC_RX_TX;
syncStatus = CO_SYNC_RX_TX;
CO_SYNCsend(SYNC);
}
#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT
@ -398,7 +398,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_PRODUCER */
/* Verify timeout of SYNC */
{
if (SYNC->timeoutError == 1) {
/* periodTimeout is 1,5 * OD_1006_period, no overflow */
uint32_t periodTimeout = OD_1006_period + (OD_1006_period >> 1);
if (periodTimeout < OD_1006_period) periodTimeout = 0xFFFFFFFF;
@ -406,7 +406,7 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
if (SYNC->timer > periodTimeout) {
CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT,
CO_EMC_COMMUNICATION, SYNC->timer);
SYNC->timeoutError = true;
SYNC->timeoutError = 2;
}
#if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT
else if (timerNext_us != NULL) {
@ -420,12 +420,11 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
} /* if (OD_1006_period > 0) */
/* Synchronous PDOs are allowed only inside time window */
uint32_t OD_1007_window = SYNC->OD_1007_window != NULL
? *SYNC->OD_1007_window : 0;
if (OD_1007_window > 0 && SYNC->timer > OD_1007_window) {
if (SYNC->OD_1007_window != NULL && *SYNC->OD_1007_window > 0
&& SYNC->timer > *SYNC->OD_1007_window
) {
if (!SYNC->syncIsOutsideWindow) {
ret = CO_SYNC_PASSED_WINDOW;
syncStatus = CO_SYNC_PASSED_WINDOW;
}
SYNC->syncIsOutsideWindow = true;
}
@ -447,12 +446,14 @@ CO_SYNC_status_t CO_SYNC_process(CO_SYNC_t *SYNC,
SYNC->timer = 0;
}
if (SYNC->timeoutError && SYNC->timer == 0) {
CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0);
SYNC->timeoutError = false;
if (syncStatus == CO_SYNC_RX_TX) {
if (SYNC->timeoutError == 2) {
CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, 0);
}
SYNC->timeoutError = 1;
}
return ret;
return syncStatus;
}
#endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */

View file

@ -35,7 +35,7 @@
#ifndef CO_CONFIG_SYNC
#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | \
CO_CONFIG_SYNC_PRODUCER | \
CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \
CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | \
CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | \
CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
@ -88,8 +88,9 @@ typedef struct {
uint8_t receiveError;
/** Variable toggles, if new SYNC message received from CAN bus */
bool_t CANrxToggle;
/** True in sync timeout error state */
bool_t timeoutError;
/** Sync timeout monitoring: 0 = not started; 1 = started; 2 = sync timeout
* error state */
uint8_t timeoutError;
/** Value from _Synchronous counter overflow value_ variable from Object
dictionary (index 0x1019) */
uint8_t counterOverflowValue;

View file

@ -99,11 +99,18 @@ extern "C" {
*/
#define CO_CONFIG_FLAG_OD_DYNAMIC 0x4000
/** This flag may be set globally to @ref CO_CONFIG_FLAG_CALLBACK_PRE */
/** This flag may be set globally for mainline objects to
* @ref CO_CONFIG_FLAG_CALLBACK_PRE */
#ifdef CO_DOXYGEN
#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0)
#endif
/** This flag may be set globally for Real-Time objects (SYNC, PDO) to
* @ref CO_CONFIG_FLAG_CALLBACK_PRE */
#ifdef CO_DOXYGEN
#define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0)
#endif
/** This flag may be set globally to @ref CO_CONFIG_FLAG_TIMERNEXT */
#ifdef CO_DOXYGEN
#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0)
@ -450,7 +457,7 @@ extern "C" {
* - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of SYNC.
*/
#ifdef CO_DOXYGEN
#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#define CO_CONFIG_SYNC (CO_CONFIG_SYNC_ENABLE | CO_CONFIG_SYNC_PRODUCER | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
#define CO_CONFIG_SYNC_ENABLE 0x01
#define CO_CONFIG_SYNC_PRODUCER 0x02
@ -461,11 +468,16 @@ extern "C" {
* Possible flags, can be ORed:
* - CO_CONFIG_RPDO_ENABLE - Enable receive PDO objects.
* - CO_CONFIG_TPDO_ENABLE - Enable transmit PDO objects.
* - CO_CONFIG_RPDO_TIMERS_ENABLE - Enable RPDO timers: RPDO timeout monitoring
* with event timer.
* - CO_CONFIG_TPDO_TIMERS_ENABLE - Enable TPDO timers: TPDO inhibit and event
* timers.
* - CO_CONFIG_PDO_SYNC_ENABLE - Enable SYNC in PDO objects.
* - CO_CONFIG_RPDO_CALLS_EXTENSION - Enable calling configured extension
* callbacks when received RPDO CAN message modifies OD entries.
* - CO_CONFIG_TPDO_CALLS_EXTENSION - Enable calling configured extension
* callbacks before TPDO CAN message is sent.
* - CO_CONFIG_PDO_OD_IO_ACCESS - For OD variables mapped to PDO use read/write
* function access with @ref OD_IO_t. This option enables much more
* flexibility for application program, but consumes some additional memory
* and processor resources. If this option is not enabled, then data from OD
* variables are fetched directly from memory allocated by Object dictionary.
* - #CO_CONFIG_FLAG_CALLBACK_PRE - Enable custom callback after preprocessing
* received RPDO CAN message.
* Callback is configured by CO_RPDO_initCallbackPre().
@ -474,13 +486,14 @@ extern "C" {
* - #CO_CONFIG_FLAG_OD_DYNAMIC - Enable dynamic configuration of PDO.
*/
#ifdef CO_DOXYGEN
#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_RPDO_TIMERS_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE | CO_CONFIG_PDO_SYNC_ENABLE | CO_CONFIG_PDO_OD_IO_ACCESS | CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE | CO_CONFIG_GLOBAL_FLAG_TIMERNEXT | CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
#define CO_CONFIG_RPDO_ENABLE 0x01
#define CO_CONFIG_TPDO_ENABLE 0x02
#define CO_CONFIG_PDO_SYNC_ENABLE 0x04
#define CO_CONFIG_RPDO_CALLS_EXTENSION 0x08
#define CO_CONFIG_TPDO_CALLS_EXTENSION 0x10
#define CO_CONFIG_RPDO_TIMERS_ENABLE 0x04
#define CO_CONFIG_TPDO_TIMERS_ENABLE 0x08
#define CO_CONFIG_PDO_SYNC_ENABLE 0x10
#define CO_CONFIG_PDO_OD_IO_ACCESS 0x20
/** @} */ /* CO_STACK_CONFIG_SYNC_PDO */

View file

@ -40,6 +40,9 @@ extern "C" {
#ifndef CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE
#define CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE (0)
#endif
#ifndef CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE
#define CO_CONFIG_GLOBAL_RT_FLAG_CALLBACK_PRE (0)
#endif
#ifndef CO_CONFIG_GLOBAL_FLAG_TIMERNEXT
#define CO_CONFIG_GLOBAL_FLAG_TIMERNEXT (0)
#endif

150
CANopen.c
View file

@ -1090,58 +1090,6 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co,
}
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE
if (CO_GET_CNT(RPDO) > 0) {
OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM);
OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING);
for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) {
err = CO_RPDO_init(co->RPDO[i],
em,
co->SDO[0],
#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
co->SYNC,
#endif
&co->NMT->operatingState,
nodeId,
((i < 4) ? (CO_CAN_ID_RPDO_1 + i * 0x100) : 0),
0,
RPDOcomm++,
RPDOmap++,
OD_H1400_RXPDO_1_PARAM + i,
OD_H1600_RXPDO_1_MAPPING + i,
co->CANmodule,
CO_GET_CO(RX_IDX_RPDO) + i);
if (err) return err;
}
}
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE
if (CO_GET_CNT(TPDO) > 0) {
OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM);
OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING);
for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) {
err = CO_TPDO_init(co->TPDO[i],
em,
co->SDO[0],
#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
co->SYNC,
#endif
&co->NMT->operatingState,
nodeId,
((i < 4) ? (CO_CAN_ID_TPDO_1 + i * 0x100) : 0),
0,
TPDOcomm++,
TPDOmap++,
OD_H1800_TXPDO_1_PARAM + i,
OD_H1A00_TXPDO_1_MAPPING + i,
co->CANmodule,
CO_GET_CO(TX_IDX_TPDO) + i);
if (err) return err;
}
}
#endif
#if (CO_CONFIG_GFC) & CO_CONFIG_GFC_ENABLE
if (CO_GET_CNT(GFC) == 1) {
err = CO_GFC_init(co->GFC,
@ -1258,6 +1206,74 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co,
}
/******************************************************************************/
CO_ReturnError_t CO_CANopenInitPDO(CO_t *co,
CO_EM_t *em,
OD_t *od,
uint8_t nodeId,
uint32_t *errInfo)
{
if (co == NULL || nodeId < 1 || nodeId > 127 || co->nodeIdUnconfigured) {
return (co != NULL || co->nodeIdUnconfigured)
? CO_ERROR_NODE_ID_UNCONFIGURED_LSS : CO_ERROR_ILLEGAL_ARGUMENT;
}
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE
if (CO_GET_CNT(RPDO) > 0) {
OD_entry_t *RPDOcomm = OD_GET(H1400, OD_H1400_RXPDO_1_PARAM);
OD_entry_t *RPDOmap = OD_GET(H1600, OD_H1600_RXPDO_1_MAPPING);
for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) {
CO_ReturnError_t err;
uint16_t preDefinedCanId = i < 4
? (CO_CAN_ID_RPDO_1 + i * 0x100) + nodeId
: 0;
err = CO_RPDO_init(&co->RPDO[i],
od,
em,
#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
co->SYNC,
#endif
preDefinedCanId,
RPDOcomm++,
RPDOmap++,
co->CANmodule,
CO_GET_CO(RX_IDX_RPDO) + i,
errInfo);
if (err) return err;
}
}
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE
if (CO_GET_CNT(TPDO) > 0) {
OD_entry_t *TPDOcomm = OD_GET(H1800, OD_H1800_TXPDO_1_PARAM);
OD_entry_t *TPDOmap = OD_GET(H1A00, OD_H1A00_TXPDO_1_MAPPING);
for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) {
CO_ReturnError_t err;
uint16_t preDefinedCanId = i < 4
? (CO_CAN_ID_TPDO_1 + i * 0x100) + nodeId
: 0;
err = CO_TPDO_init(&co->TPDO[i],
od,
em,
#if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
co->SYNC,
#endif
preDefinedCanId,
TPDOcomm++,
TPDOmap++,
co->CANmodule,
CO_GET_CO(TX_IDX_TPDO) + i,
errInfo);
if (err) return err;
}
}
#endif
return CO_ERROR_NO;
}
/******************************************************************************/
CO_NMT_reset_cmd_t CO_process(CO_t *co,
bool_t enableGateway,
@ -1408,13 +1424,27 @@ bool_t CO_process_SYNC(CO_t *co,
/******************************************************************************/
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE
void CO_process_RPDO(CO_t *co, bool_t syncWas) {
void CO_process_RPDO(CO_t *co,
bool_t syncWas,
uint32_t timeDifference_us,
uint32_t *timerNext_us)
{
(void) timeDifference_us; (void) timerNext_us;
if (co->nodeIdUnconfigured) {
return;
}
bool_t NMTisOperational =
CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL;
for (int16_t i = 0; i < CO_GET_CNT(RPDO); i++) {
CO_RPDO_process(&co->RPDO[i], syncWas);
CO_RPDO_process(&co->RPDO[i],
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_TIMERS_ENABLE
timeDifference_us,
timerNext_us,
#endif
NMTisOperational,
syncWas);
}
}
#endif
@ -1427,12 +1457,22 @@ void CO_process_TPDO(CO_t *co,
uint32_t timeDifference_us,
uint32_t *timerNext_us)
{
(void) timeDifference_us; (void) timerNext_us;
if (co->nodeIdUnconfigured) {
return;
}
bool_t NMTisOperational =
CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL;
for (int16_t i = 0; i < CO_GET_CNT(TPDO); i++) {
CO_TPDO_process(&co->TPDO[i], syncWas, timeDifference_us, timerNext_us);
CO_TPDO_process(&co->TPDO[i],
#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_TIMERS_ENABLE
timeDifference_us,
timerNext_us,
#endif
NMTisOperational,
syncWas);
}
}
#endif

View file

@ -467,7 +467,7 @@ CO_ReturnError_t CO_LSSinit(CO_t *co,
/**
* Initialize CANopenNode.
* Initialize CANopenNode except PDO objects.
*
* Function must be called in the communication reset section.
*
@ -511,6 +511,30 @@ CO_ReturnError_t CO_CANopenInit(CO_t *co,
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);
/**
* Process CANopen objects.
*
@ -571,8 +595,14 @@ bool_t CO_process_SYNC(CO_t *co,
* @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);
void CO_process_RPDO(CO_t *co,
bool_t syncWas,
uint32_t timeDifference_us,
uint32_t *timerNext_us);
#endif

View file

@ -17,36 +17,42 @@ Dictionary and are accessible from both: C code and from CANopen network.
CANopenNode homepage is https://github.com/CANopenNode/CANopenNode
This is renewed version of CANopenNode with new Object Dictionary implementation.
For older versions see branches `v1.3-master` or `v2.0-master`.
This is version 4 of CANopenNode with new Object Dictionary implementation.
For older versions `git checkout` branches `v1.3-master` or `v2.0-master`.
Characteristics
---------------
### CANopen
- [Object Dictionary](https://www.can-cia.org/can-knowledge/canopen/device-architecture/)
offers clear and flexible organisation of any variables.
offers clear and flexible organisation of any variables. Variables can be accessed
directly or via read/write functions.
- [NMT](https://www.can-cia.org/can-knowledge/canopen/network-management/)
slave to start, stop, reset device. Simple NMT master.
- [Heartbeat](https://www.can-cia.org/can-knowledge/canopen/error-control-protocols/)
producer/consumer error control.
- [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) linking
and dynamic mapping for fast exchange of process variables from Object Dictionary.
- [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) expedited,
segmented and block transfer for service access to all Object Dictionary variables.
- [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client.
producer/consumer error control for monitoring of CANopen devices.
- [PDO](https://www.can-cia.org/can-knowledge/canopen/pdo-protocol/) for
broadcasting process data with high priority and no protocol overhead.
Variables from Object Dictionary can be dynamically mapped to the TPDO, which
is then transmitted according to communication rules and received as RPDO
by another device.
- [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) server
enables expedited, segmented and block transfer access to all Object
Dictionary variables inside CANopen device.
- [SDO](https://www.can-cia.org/can-knowledge/canopen/sdo-protocol/) client can
access any Object Dictionary variable on any CANopen device inside the network.
- [Emergency](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/)
producer/consumer.
message producer/consumer.
- [Sync](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/)
producer/consumer.
producer/consumer enables network synchronized transmission of the PDO objects, etc.
- [Time-stamp](https://www.can-cia.org/can-knowledge/canopen/special-function-protocols/)
protocol producer/consumer.
- [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) master and
slave, LSS fastscan.
producer/consumer enables date and time synchronization in millisecond resolution.
- [LSS](https://www.can-cia.org/can-knowledge/canopen/cia305/) CANopen node-id
and bitrate setup, master and slave, LSS fastscan.
- [CANopen gateway](https://www.can-cia.org/can-knowledge/canopen/cia309/),
CiA309-3 Ascii command interface for NMT master, LSS master and SDO client.
- CANopen Safety,
EN 50325-5 "PDO like" communication in safety-relevant networks
EN 50325-5, CiA304, "PDO like" communication in safety-relevant networks
### Other
- [Suitable for 16-bit microcontrollers and above](#device-support)
@ -61,8 +67,8 @@ Characteristics
Documentation, support and contributions
----------------------------------------
Documentation with [Getting started](doc/gettingStarted.md),
[LSS usage](doc/LSSusage.md) and [Trace usage](doc/traceUsage.md) is in `doc`
directory.
[Objec Dictionary](doc/objectDictionary.md) and [LSS usage](doc/LSSusage.md)
is in `doc` directory.
Code is documented in header files. Running [doxygen](http://www.doxygen.nl/)
in project base directory will produce complete html documentation.
Just open CANopenNode/doc/html/index.html in the browser. Alternatively browse
@ -99,43 +105,24 @@ Flowchart of a typical CANopenNode implementation
| | |
-------------------- | --------------------
| | |
----------------------- ----------------------- -----------------------
| CAN receive thread | | Timer interval thread | | Mainline thread |
| | | | | |
| - Fast response. | | - Realtime thread with| | - Processing of time |
| - Detect CAN ID. | | constant interval, | | consuming tasks |
| - Partially process | | typically 1ms. | | in CANopen objects: |
| messages and copy | | - Network synchronized| | - SDO server, |
| data to target | | - Copy inputs (RPDOs, | | - Emergency, |
| CANopen objects. | | HW) to Object Dict. | | - Network state, |
| | | - May call application| | - Heartbeat. |
| | | for some processing.| | - LSS slave |
| | | - Copy variables from | | - May cyclically call |
| | | Object Dictionary to| | application code. |
| | | outputs (TPDOs, HW).| | |
----------------------- ----------------------- -----------------------
-----------------------
| SDO client (optional) |
| |
| - Can be called by |
| external application|
| - Can read or write |
| any variable from |
| Object Dictionary |
| from any node in the|
| CANopen network. |
-----------------------
-----------------------
| LSS Master (optional) |
| |
| - Can be called by |
| external application|
| - Can do LSS requests |
| - Can request node |
| enumeration |
-----------------------
---------------------- ------------------------ -----------------------
| CAN receive thread | | Timer interval thread | | Mainline thread |
| | | | | |
| - Fast response. | | - Realtime thread with | | - Processing of time |
| - Detect CAN ID. | | constant interval, | | consuming tasks |
| - Partially process | | typically 1ms. | | in CANopen objects: |
| messages and copy | | - Network synchronized | | - SDO server, |
| data to target | | - Copy inputs (RPDOs, | | - Emergency, |
| CANopen objects. | | HW) to Object Dict. | | - Network state, |
| | | - May call application | | - Heartbeat. |
| | | for some processing. | | - LSS slave |
| | | - Copy variables from | | - Gateway (optional): |
| | | Object Dictionary to | | - NMT master |
| | | outputs (TPDOs, HW). | | - SDO client |
| | | | | - LSS master |
| | | | | - May cyclically call |
| | | | | application code. |
---------------------- ------------------------ -----------------------
~~~

View file

@ -5,12 +5,14 @@ Change Log
-------------------------
- [Full ChangeLog](https://github.com/CANopenNode/CANopenNode/compare/master...newOD)
### Changed
- New Object dictionary interface. It has very similar principles as before. All parts of CANopenNode objects, which works with OD entries, are rewritten.
- New Object dictionary interface. It has similar principles as before. Main access to OD variables is via fast read/write functions, but direct access to OD variables is also possible. OD entries are passed with pointers to CANopen objects. All parts of CANopenNode objects, which works with OD entries, are rewritten.
- [libedssharp](https://github.com/robincornelius/libedssharp) have new OD exporter, new project file format (standard CANopen XDD v1.1), new documentation generator, and many other improvements.
- New OD.h and OD.c files, replaces CO_OD files.
- CANopen.c and CANopen.h files redesigned. Integration of "OD.h" is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments.
- Rewritten SDO server. Object dictionary part is removed.
- CO_Emergency is mostly rewritten. Now is much easier customization.
- CO_NMT_Heartbeat is redesigned.
- CANopen.c and CANopen.h files redesigned. `#include OD.h` is optional. Configuration of multiple object dictionaries is possible with one CANopen device. Interface is the same, with some changes to function arguments.
- New CO_storage.h/c files enables easier integration to target system for storing OD variables.
- Rewritten SDO server. Object dictionary part is moved to CO_ODinterface.h/c files.
- Rewritten PDO. PDO mapped variables are accessed via fast read/write functions. New RPDO event timer (timeout).
- CO_Emergency is mostly rewritten. Now is much easier customization. All other objects has been adjusted to newOD, inspected and some parts were redesigned.
[Unreleased master]
-------------------------

View file

@ -30,7 +30,7 @@ Note that OD variables can be accessed from different threads. CANopenNode basic
extern OD_t *ODxyz;
void myFunc(OD_t *od) {
ODR_t ret;
ODR_t odRet;
OD_entry_t *entry;
OD_IO_t io1008;
char buf[50];
@ -39,15 +39,24 @@ void myFunc(OD_t *od) {
/* Init IO for "Manufacturer device name" at index 0x1008, sub-index 0x00 */
entry = OD_find(od, 0x1008);
ret = OD_getSub(entry, 0x00, &io1008, false);
odRet = OD_getSub(entry, 0x00, &io1008, false);
/* Read with io1008, subindex = 0x00 */
if (ret == ODR_OK)
bytesRd = io1008.read(&io1008.stream, 0x00, &buf[0], sizeof(buf), &ret);
if (ret != ODR_OK) error++;
if (odRet == ODR_OK) {
/* Locking is necessary from mainline thread, but must not be used from
* timer interval (real-time) thread. Locking is not necessary in the
* CANoopen initialization section. Locking is also not necessary, if
* OD variable is not mappable to PDO and not accessed from RT thread.*/
CO_LOCK_OD(CANmodule);
odRet = io1008.read(&io1008.stream, &buf[0], sizeof(buf), &bytesRd);
CO_UNLOCK_OD(CANmodule);
}
if (odRet != ODR_OK) error++;
/* Use helper and set "Producer heartbeat time" at index 0x1017, sub 0x00 */
ret = OD_set_u16(OD_find(od, 0x1017), 0x00, 500, false);
if (ret != ODR_OK) error++;
CO_LOCK_OD(CANmodule); /* may not be necessary, see comment above */
odRet = OD_set_u16(OD_find(od, 0x1017), 0x00, 500, false);
CO_UNLOCK_OD(CANmodule);
if (odRet != ODR_OK) error++;
}
```
There is no need to include ODxyt.h file, it is only necessary to know, we have ODxyz defined somewhere.

View file

@ -103,16 +103,6 @@ extern "C" {
CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
#ifndef CO_CONFIG_PDO
#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \
CO_CONFIG_TPDO_ENABLE | \
CO_CONFIG_PDO_SYNC_ENABLE | \
CO_CONFIG_RPDO_CALLS_EXTENSION | \
CO_CONFIG_TPDO_CALLS_EXTENSION | \
CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \
CO_CONFIG_GLOBAL_FLAG_TIMERNEXT)
#endif
#ifndef CO_CONFIG_GFC
#define CO_CONFIG_GFC (CO_CONFIG_GFC_ENABLE | \
CO_CONFIG_GFC_CONSUMER | \

View file

@ -54,10 +54,6 @@
extern "C" {
#endif
/* TODO some parts are disabled in non-finished pre-release */
#define CO_CONFIG_PDO (0)
#define CO_CONFIG_TRACE (0)
/* Stack configuration override default values.
* For more information see file CO_config.h. */
@ -123,16 +119,6 @@ extern "C" {
CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC)
#endif
#ifndef CO_CONFIG_PDO
#define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | \
CO_CONFIG_TPDO_ENABLE | \
CO_CONFIG_PDO_SYNC_ENABLE | \
CO_CONFIG_RPDO_CALLS_EXTENSION | \
CO_CONFIG_TPDO_CALLS_EXTENSION | \
CO_CONFIG_GLOBAL_FLAG_CALLBACK_PRE | \
CO_CONFIG_GLOBAL_FLAG_TIMERNEXT)
#endif
#ifndef CO_CONFIG_LSS
#define CO_CONFIG_LSS (CO_CONFIG_LSS_SLAVE | \
CO_CONFIG_LSS_SLAVE_FASTSCAN_DIRECT_RESPOND | \
@ -166,10 +152,6 @@ extern "C" {
CO_CONFIG_FIFO_ASCII_DATATYPES)
#endif
#ifndef CO_CONFIG_TRACE
#define CO_CONFIG_TRACE (CO_CONFIG_TRACE_ENABLE)
#endif
/* Print debug info from some internal parts of the stack */
#if (CO_CONFIG_DEBUG) & CO_CONFIG_DEBUG_COMMON

View file

@ -338,7 +338,8 @@ void CO_epoll_processRT(CO_epoll_t *ep,
pTimerNext_us);
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE
CO_process_RPDO(co, syncWas);
CO_process_RPDO(co, syncWas, ep->timeDifference_us,
pTimerNext_us);
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE
CO_process_TPDO(co, syncWas, ep->timeDifference_us,

View file

@ -67,9 +67,9 @@
#ifndef NMT_CONTROL
#define NMT_CONTROL \
CO_NMT_STARTUP_TO_OPERATIONAL \
|| CO_NMT_ERR_ON_ERR_REG \
|| CO_ERR_REG_GENERIC_ERR \
|| CO_ERR_REG_COMMUNICATION
| CO_NMT_ERR_ON_ERR_REG \
| CO_ERR_REG_GENERIC_ERR \
| CO_ERR_REG_COMMUNICATION
#endif
#ifndef FIRST_HB_TIME
#define FIRST_HB_TIME 500
@ -665,6 +665,24 @@ int main (int argc, char *argv[]) {
app_communicationReset(!CO->nodeIdUnconfigured);
#endif
errInfo = 0;
err = CO_CANopenInitPDO(CO, /* CANopen object */
CO->em, /* emergency object */
OD, /* Object dictionary */
CO_activeNodeId,
&errInfo);
if(err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) {
if (err == CO_ERROR_OD_PARAMETERS) {
log_printf(LOG_CRIT, DBG_OD_ENTRY, errInfo);
}
else {
log_printf(LOG_CRIT, DBG_CAN_OPEN, "CO_CANopenInitPDO()", err);
}
programExit = EXIT_FAILURE;
CO_endProgram = 1;
continue;
}
/* start CAN */
CO_CANsetNormalMode(CO->CANmodule);