712 lines
33 KiB
C
712 lines
33 KiB
C
|
|
/**
|
||
|
|
* CANopen Object Dictionary interface
|
||
|
|
*
|
||
|
|
* @file CO_ODinterface.h
|
||
|
|
* @ingroup CO_ODinterface
|
||
|
|
* @author Janez Paternoster
|
||
|
|
* @copyright 2020 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 CO_OD_INTERFACE_H
|
||
|
|
#define CO_OD_INTERFACE_H
|
||
|
|
|
||
|
|
#include "301/CO_driver.h"
|
||
|
|
|
||
|
|
#ifdef __cplusplus
|
||
|
|
extern "C" {
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup CO_ODinterface OD interface
|
||
|
|
* CANopen Object Dictionary interface.
|
||
|
|
*
|
||
|
|
* @ingroup CO_CANopen_301
|
||
|
|
* @{
|
||
|
|
* See @ref md_doc_2objectDictionary
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef CO_OD_OWN_TYPES
|
||
|
|
typedef uint32_t OD_size_t; /**< Variable of type OD_size_t contains data length in bytes of OD variable */
|
||
|
|
typedef uint8_t OD_attr_t; /**< Type (and size) of Object Dictionary attribute */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef OD_FLAGS_PDO_SIZE
|
||
|
|
#define OD_FLAGS_PDO_SIZE 4U /**< Size of of flagsPDO variable inside @ref OD_extension_t, from 0 to 32. */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef CO_PROGMEM
|
||
|
|
/** Modifier for OD objects. This is large amount of data and is specified in Object Dictionary (OD.c file usually) */
|
||
|
|
#define CO_PROGMEM const
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Common DS301 object dictionary entries.
|
||
|
|
*/
|
||
|
|
typedef enum {
|
||
|
|
OD_H1000_DEV_TYPE = 0x1000U, /**< Device type */
|
||
|
|
OD_H1001_ERR_REG = 0x1001U, /**< Error register */
|
||
|
|
OD_H1002_MANUF_STATUS_REG = 0x1002U, /**< Manufacturer status register */
|
||
|
|
OD_H1003_PREDEF_ERR_FIELD = 0x1003U, /**< Predefined error field */
|
||
|
|
OD_H1004_RSV = 0x1004U, /**< Reserved */
|
||
|
|
OD_H1005_COBID_SYNC = 0x1005U, /**< Sync message cob-id */
|
||
|
|
OD_H1006_COMM_CYCL_PERIOD = 0x1006U, /**< Communication cycle period */
|
||
|
|
OD_H1007_SYNC_WINDOW_LEN = 0x1007U, /**< Sync windows length */
|
||
|
|
OD_H1008_MANUF_DEV_NAME = 0x1008U, /**< Manufacturer device name */
|
||
|
|
OD_H1009_MANUF_HW_VERSION = 0x1009U, /**< Manufacturer hardware version */
|
||
|
|
OD_H100A_MANUF_SW_VERSION = 0x100AU, /**< Manufacturer software version */
|
||
|
|
OD_H100B_RSV = 0x100BU, /**< Reserved */
|
||
|
|
OD_H100C_GUARD_TIME = 0x100CU, /**< Guard time */
|
||
|
|
OD_H100D_LIFETIME_FACTOR = 0x100DU, /**< Life time factor */
|
||
|
|
OD_H100E_RSV = 0x100EU, /**< Reserved */
|
||
|
|
OD_H100F_RSV = 0x100FU, /**< Reserved */
|
||
|
|
OD_H1010_STORE_PARAMETERS = 0x1010U, /**< Store params in persistent mem. */
|
||
|
|
OD_H1011_RESTORE_DEFAULT = 0x1011U, /**< Restore default parameters */
|
||
|
|
OD_H1012_COBID_TIME = 0x1012U, /**< Timestamp message cob-id */
|
||
|
|
OD_H1013_HIGH_RES_TIMESTAMP = 0x1013U, /**< High resolution timestamp */
|
||
|
|
OD_H1014_COBID_EMERGENCY = 0x1014U, /**< Emergency message cob-id */
|
||
|
|
OD_H1015_INHIBIT_TIME_EMCY = 0x1015U, /**< Inhibit time emergency message */
|
||
|
|
OD_H1016_CONSUMER_HB_TIME = 0x1016U, /**< Consumer heartbeat time */
|
||
|
|
OD_H1017_PRODUCER_HB_TIME = 0x1017U, /**< Producer heartbeat time */
|
||
|
|
OD_H1018_IDENTITY_OBJECT = 0x1018U, /**< Identity object */
|
||
|
|
OD_H1019_SYNC_CNT_OVERFLOW = 0x1019U, /**< Sync counter overflow value */
|
||
|
|
OD_H1020_VERIFY_CONFIG = 0x1020U, /**< Verify configuration */
|
||
|
|
OD_H1021_STORE_EDS = 0x1021U, /**< Store EDS */
|
||
|
|
OD_H1022_STORE_FORMAT = 0x1022U, /**< Store format */
|
||
|
|
OD_H1023_OS_CMD = 0x1023U, /**< OS command */
|
||
|
|
OD_H1024_OS_CMD_MODE = 0x1024U, /**< OS command mode */
|
||
|
|
OD_H1025_OS_DBG_INTERFACE = 0x1025U, /**< OS debug interface */
|
||
|
|
OD_H1026_OS_PROMPT = 0x1026U, /**< OS prompt */
|
||
|
|
OD_H1027_MODULE_LIST = 0x1027U, /**< Module list */
|
||
|
|
OD_H1028_EMCY_CONSUMER = 0x1028U, /**< Emergency consumer object */
|
||
|
|
OD_H1029_ERR_BEHAVIOR = 0x1029U, /**< Error behaviour */
|
||
|
|
OD_H1200_SDO_SERVER_1_PARAM = 0x1200U, /**< SDO server parameter */
|
||
|
|
OD_H1280_SDO_CLIENT_1_PARAM = 0x1280U, /**< SDO client parameter */
|
||
|
|
OD_H1300_GFC_PARAM = 0x1300U, /**< Global fail-safe command param */
|
||
|
|
OD_H1301_SRDO_1_PARAM = 0x1301U, /**< SRDO communication parameter */
|
||
|
|
OD_H1381_SRDO_1_MAPPING = 0x1381U, /**< SRDO mapping parameter */
|
||
|
|
OD_H13FE_SRDO_VALID = 0x13FEU, /**< SRDO Configuration valid */
|
||
|
|
OD_H13FF_SRDO_CHECKSUM = 0x13FFU, /**< SRDO configuration checksum */
|
||
|
|
OD_H1400_RXPDO_1_PARAM = 0x1400U, /**< RXPDO communication parameter */
|
||
|
|
OD_H1600_RXPDO_1_MAPPING = 0x1600U, /**< RXPDO mapping parameters */
|
||
|
|
OD_H1800_TXPDO_1_PARAM = 0x1800U, /**< TXPDO communication parameter */
|
||
|
|
OD_H1A00_TXPDO_1_MAPPING = 0x1A00U, /**< TXPDO mapping parameters */
|
||
|
|
} OD_ObjDicId_30x_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Attributes (bit masks) for OD sub-object.
|
||
|
|
*/
|
||
|
|
typedef enum {
|
||
|
|
ODA_SDO_R = 0x01U, /**< SDO server may read from the variable */
|
||
|
|
ODA_SDO_W = 0x02U, /**< SDO server may write to the variable */
|
||
|
|
ODA_SDO_RW = 0x03U, /**< SDO server may read from or write to the variable */
|
||
|
|
ODA_TPDO = 0x04U, /**< Variable is mappable into TPDO (can be read) */
|
||
|
|
ODA_RPDO = 0x08U, /**< Variable is mappable into RPDO (can be written) */
|
||
|
|
ODA_TRPDO = 0x0CU, /**< Variable is mappable into TPDO or RPDO */
|
||
|
|
ODA_TSRDO = 0x10U, /**< Variable is mappable into transmitting SRDO */
|
||
|
|
ODA_RSRDO = 0x20U, /**< Variable is mappable into receiving SRDO */
|
||
|
|
ODA_TRSRDO = 0x30U, /**< Variable is mappable into tx or rx SRDO */
|
||
|
|
ODA_MB = 0x40U, /**< Variable is multi-byte ((u)int16_t to (u)int64_t) */
|
||
|
|
ODA_STR = 0x80U /**< Shorter value, than specified variable size, may be written to the variable. SDO write will
|
||
|
|
fill remaining memory with zeroes. Attribute is used for VISIBLE_STRING and UNICODE_STRING. */
|
||
|
|
} OD_attributes_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return codes from OD access functions.
|
||
|
|
*
|
||
|
|
* @ref OD_getSDOabCode() can be used to retrieve corresponding SDO abort code.
|
||
|
|
*/
|
||
|
|
typedef enum {
|
||
|
|
/* !!!! WARNING !!!! If changing these values, change also OD_getSDOabCode() function! */
|
||
|
|
ODR_PARTIAL = -1, /**< Read/write is only partial, make more calls */
|
||
|
|
ODR_OK = 0, /**< SDO abort 0x00000000 - Read/write successfully finished */
|
||
|
|
ODR_OUT_OF_MEM = 1, /**< SDO abort 0x05040005 - Out of memory */
|
||
|
|
ODR_UNSUPP_ACCESS = 2, /**< SDO abort 0x06010000 - Unsupported access to an object */
|
||
|
|
ODR_WRITEONLY = 3, /**< SDO abort 0x06010001 - Attempt to read a write only object */
|
||
|
|
ODR_READONLY = 4, /**< SDO abort 0x06010002 - Attempt to write a read only object */
|
||
|
|
ODR_IDX_NOT_EXIST = 5, /**< SDO abort 0x06020000 - Object does not exist in the object dict. */
|
||
|
|
ODR_NO_MAP = 6, /**< SDO abort 0x06040041 - Object cannot be mapped to the PDO */
|
||
|
|
ODR_MAP_LEN = 7, /**< SDO abort 0x06040042 - PDO length exceeded */
|
||
|
|
ODR_PAR_INCOMPAT = 8, /**< SDO abort 0x06040043 - General parameter incompatibility reasons */
|
||
|
|
ODR_DEV_INCOMPAT = 9, /**< SDO abort 0x06040047 - General internal incompatibility in device */
|
||
|
|
ODR_HW = 10, /**< SDO abort 0x06060000 - Access failed due to hardware error */
|
||
|
|
ODR_TYPE_MISMATCH = 11, /**< SDO abort 0x06070010 - Data type does not match */
|
||
|
|
ODR_DATA_LONG = 12, /**< SDO abort 0x06070012 - Data type does not match, length too high */
|
||
|
|
ODR_DATA_SHORT = 13, /**< SDO abort 0x06070013 - Data type does not match, length too short */
|
||
|
|
ODR_SUB_NOT_EXIST = 14, /**< SDO abort 0x06090011 - Sub index does not exist */
|
||
|
|
ODR_INVALID_VALUE = 15, /**< SDO abort 0x06090030 - Invalid value for parameter (download only) */
|
||
|
|
ODR_VALUE_HIGH = 16, /**< SDO abort 0x06090031 - Value range of parameter written too high */
|
||
|
|
ODR_VALUE_LOW = 17, /**< SDO abort 0x06090032 - Value range of parameter written too low */
|
||
|
|
ODR_MAX_LESS_MIN = 18, /**< SDO abort 0x06090036 - Maximum value is less than minimum value */
|
||
|
|
ODR_NO_RESOURCE = 19, /**< SDO abort 0x060A0023 - Resource not available: SDO connection */
|
||
|
|
ODR_GENERAL = 20, /**< SDO abort 0x08000000 - General error */
|
||
|
|
ODR_DATA_TRANSF = 21, /**< SDO abort 0x08000020 - Data cannot be transferred or stored to app */
|
||
|
|
ODR_DATA_LOC_CTRL = 22, /**< SDO abort 0x08000021 - Data can't be transferred (local control) */
|
||
|
|
ODR_DATA_DEV_STATE = 23, /**< SDO abort 0x08000022 - Data can't be transf. (present device state) */
|
||
|
|
ODR_OD_MISSING = 24, /**< SDO abort 0x08000023 - Object dictionary not present */
|
||
|
|
ODR_NO_DATA = 25, /**< SDO abort 0x08000024 - No data available */
|
||
|
|
ODR_COUNT = 26 /**< Last element, number of responses */
|
||
|
|
} ODR_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* IO stream structure, used for read/write access to OD variable, part of @ref OD_IO_t.
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
void* dataOrig; /**< Pointer to original data object, defined by Object Dictionary. Default read/write functions
|
||
|
|
* operate on it. If memory for data object is not specified by Object Dictionary, then dataOrig is
|
||
|
|
* NULL. */
|
||
|
|
void* object; /**< Pointer to object, passed by @ref OD_extension_init(). Can be used inside read / write functions
|
||
|
|
* from IO extension. */
|
||
|
|
OD_size_t dataLength; /**< Data length in bytes or 0, if length is not specified */
|
||
|
|
OD_size_t dataOffset; /**< In case of large data, dataOffset indicates position of already transferred data */
|
||
|
|
OD_attr_t attribute; /**< Attribute bit-field of the OD sub-object, see @ref OD_attributes_t */
|
||
|
|
uint16_t index; /**< Index of the OD object, informative */
|
||
|
|
uint8_t subIndex; /**< Sub index of the OD sub-object, informative */
|
||
|
|
} OD_stream_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Structure for input / output on the OD variable. It is initialized with @ref OD_getSub() function. Access principle
|
||
|
|
* to OD variable is via read/write functions operating on stream, similar as standard read/write.
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
/** Object Dictionary stream object, passed to read or write */
|
||
|
|
OD_stream_t stream;
|
||
|
|
/**
|
||
|
|
* Function pointer for reading value from specified variable from Object Dictionary. If OD variable is larger than
|
||
|
|
* buf, then this function must be called several times. After completed successful read function returns 'ODR_OK'.
|
||
|
|
* If read is partial, it returns 'ODR_PARTIAL'. In case of errors function returns code similar to SDO abort code.
|
||
|
|
*
|
||
|
|
* Read can be restarted with @ref OD_rwRestart() function.
|
||
|
|
*
|
||
|
|
* At the moment, when Object Dictionary is initialized, every variable has assigned the same "read" function. This
|
||
|
|
* default function simply copies data from Object Dictionary variable. Application can bind its own "read" function
|
||
|
|
* for specific object. In that case application is able to calculate data for reading from own internal state at
|
||
|
|
* the moment of "read" function call. Own "read" function on OD object can be initialized with @ref
|
||
|
|
* OD_extension_init() function.
|
||
|
|
*
|
||
|
|
* "read" function must always copy all own data to buf, except if "buf" is not large enough. ("*returnCode" must
|
||
|
|
* not return 'ODR_PARTIAL', if there is still space in "buf".)
|
||
|
|
*
|
||
|
|
* @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros inside the read() function. See also @ref
|
||
|
|
* CO_critical_sections.
|
||
|
|
*
|
||
|
|
* @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.
|
||
|
|
* @param [out] countRead If return value is "ODR_OK" or "ODR_PARTIAL", then number of bytes successfully read must
|
||
|
|
* be returned here.
|
||
|
|
*
|
||
|
|
* @return Value from @ref ODR_t, "ODR_OK" in case of success.
|
||
|
|
*/
|
||
|
|
ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead);
|
||
|
|
/**
|
||
|
|
* Function pointer for writing value into specified variable inside Object Dictionary. If OD variable is larger
|
||
|
|
* than buf, then this function must be called several times. After completed successful write function returns
|
||
|
|
* 'ODR_OK'. If write is partial, it returns 'ODR_PARTIAL'. In case of errors function returns code similar to SDO
|
||
|
|
* abort code.
|
||
|
|
*
|
||
|
|
* Write can be restarted with @ref OD_rwRestart() function.
|
||
|
|
*
|
||
|
|
* At the moment, when Object Dictionary is initialized, every variable has assigned the same "write" function,
|
||
|
|
* which simply copies data to Object Dictionary variable. Application can bind its own "write" function, similar as
|
||
|
|
* it can bind "read" function.
|
||
|
|
*
|
||
|
|
* "write" function must always copy all available data from buf. If OD variable expect more data, then
|
||
|
|
* "*returnCode" must return 'ODR_PARTIAL'.
|
||
|
|
*
|
||
|
|
* @warning Do not use @ref CO_LOCK_OD() and @ref CO_UNLOCK_OD() macros inside the write() function. See also @ref
|
||
|
|
* CO_critical_sections.
|
||
|
|
*
|
||
|
|
* @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.
|
||
|
|
* @param [out] countWritten If return value is "ODR_OK" or "ODR_PARTIAL", then number of bytes successfully written
|
||
|
|
* must be returned here.
|
||
|
|
*
|
||
|
|
* @return Value from @ref ODR_t, "ODR_OK" in case of success.
|
||
|
|
*/
|
||
|
|
ODR_t (*write)(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten);
|
||
|
|
} OD_IO_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extension of OD object, which can optionally be specified by application in initialization phase with @ref
|
||
|
|
* OD_extension_init() function.
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
/** Object on which read and write will operate, part of @ref OD_stream_t */
|
||
|
|
void* object;
|
||
|
|
/** Application specified read function pointer. If NULL, then read will be disabled. @ref OD_readOriginal can be
|
||
|
|
* used here to keep the original read function. For function description see @ref OD_IO_t. */
|
||
|
|
ODR_t (*read)(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead);
|
||
|
|
/** Application specified write function pointer. If NULL, then write will be disabled. @ref OD_writeOriginal can be
|
||
|
|
* used here to keep the original 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);
|
||
|
|
#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.
|
||
|
|
*
|
||
|
|
* @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;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Object Dictionary entry for one OD object.
|
||
|
|
*
|
||
|
|
* OD entries are collected inside OD_t as array (list). Each OD entry contains basic information about OD object (index
|
||
|
|
* and subEntriesCount), pointer to odObject with additional information about var, array or record entry and pointer to
|
||
|
|
* extension, configurable by application.
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
uint16_t index; /**< Object Dictionary index */
|
||
|
|
uint8_t subEntriesCount; /**< Number of all sub-entries, including sub-entry at sub-index 0 */
|
||
|
|
uint8_t odObjectType; /**< Type of the odObject, indicated by @ref OD_objectTypes_t enumerator. */
|
||
|
|
CO_PROGMEM void* odObject; /**< OD object of type indicated by odObjectType, from which @ref OD_getSub() fetches the
|
||
|
|
information */
|
||
|
|
OD_extension_t* extension; /**< Extension to OD, specified by application */
|
||
|
|
} OD_entry_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Object Dictionary
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
uint16_t size; /**< Number of elements in the list, without last element, which is blank */
|
||
|
|
OD_entry_t* list; /**< List OD entries (table of contents), ordered by index */
|
||
|
|
} OD_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Read value from original OD location
|
||
|
|
*
|
||
|
|
* This function can be used inside read / write functions, specified by @ref OD_extension_init(). It reads data
|
||
|
|
* directly from memory location specified by Object dictionary. If no IO extension is used on OD entry, then io->read
|
||
|
|
* returned by @ref OD_getSub() equals to this function. See also @ref OD_IO_t.
|
||
|
|
*/
|
||
|
|
ODR_t OD_readOriginal(OD_stream_t* stream, void* buf, OD_size_t count, OD_size_t* countRead);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Write value to original OD location
|
||
|
|
*
|
||
|
|
* This function can be used inside read / write functions, specified by @ref OD_extension_init(). It writes data
|
||
|
|
* directly to memory location specified by Object dictionary. If no IO extension is used on OD entry, then io->write
|
||
|
|
* returned by @ref OD_getSub() equals to this function. See also @ref OD_IO_t.
|
||
|
|
*/
|
||
|
|
ODR_t OD_writeOriginal(OD_stream_t* stream, const void* buf, OD_size_t count, OD_size_t* countWritten);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Find OD entry in Object Dictionary
|
||
|
|
*
|
||
|
|
* @param od Object Dictionary
|
||
|
|
* @param index CANopen Object Dictionary index of object in Object Dictionary
|
||
|
|
*
|
||
|
|
* @return Pointer to OD entry or NULL if not found
|
||
|
|
*/
|
||
|
|
OD_entry_t* OD_find(OD_t* od, uint16_t index);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Find sub-object with specified sub-index on OD entry returned by OD_find. Function populates io structure with
|
||
|
|
* sub-object data.
|
||
|
|
*
|
||
|
|
* @warning
|
||
|
|
* Read and write functions may be called from different threads, so critical sections in custom functions must be
|
||
|
|
* observed, see @ref CO_critical_sections.
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param subIndex Sub-index of the variable from the OD object.
|
||
|
|
* @param [out] io Structure will be populated on success.
|
||
|
|
* @param odOrig If true, then potential IO extension on entry will be ignored and access to data entry in the original
|
||
|
|
* OD location will be returned
|
||
|
|
*
|
||
|
|
* @return Value from @ref ODR_t, "ODR_OK" in case of success.
|
||
|
|
*/
|
||
|
|
ODR_t OD_getSub(const OD_entry_t* entry, uint8_t subIndex, OD_IO_t* io, bool_t odOrig);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return index from OD entry
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
*
|
||
|
|
* @return OD index
|
||
|
|
*/
|
||
|
|
static inline uint16_t
|
||
|
|
OD_getIndex(const OD_entry_t* entry) {
|
||
|
|
return (entry != NULL) ? entry->index : 0U;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check, if OD variable is mappable to PDO or SRDO.
|
||
|
|
*
|
||
|
|
* If OD variable is mappable, then it may be necessary to protect read/write access from mainline function. See @ref
|
||
|
|
* CO_critical_sections.
|
||
|
|
*
|
||
|
|
* @param stream Object Dictionary stream object.
|
||
|
|
*
|
||
|
|
* @return true, if OD variable is mappable.
|
||
|
|
*/
|
||
|
|
static inline bool_t
|
||
|
|
OD_mappable(OD_stream_t* stream) {
|
||
|
|
return (stream != NULL) ? ((stream->attribute & ((OD_attr_t)ODA_TRPDO | (OD_attr_t)ODA_TRSRDO)) != 0U) : false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Restart read or write operation on OD variable
|
||
|
|
*
|
||
|
|
* It is not necessary to call this function, if stream was initialized by @ref OD_getSub(). It is also not necessary to
|
||
|
|
* call this function, if previous read or write was successfully finished.
|
||
|
|
*
|
||
|
|
* @param stream Object Dictionary stream object.
|
||
|
|
*/
|
||
|
|
static inline void
|
||
|
|
OD_rwRestart(OD_stream_t* stream) {
|
||
|
|
if (stream != NULL) {
|
||
|
|
stream->dataOffset = 0U;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 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 entry Object Dictionary entry.
|
||
|
|
* @param subIndex subIndex of the OD variable.
|
||
|
|
*/
|
||
|
|
static inline void
|
||
|
|
OD_requestTPDO(OD_entry_t* entry, uint8_t subIndex) {
|
||
|
|
#if OD_FLAGS_PDO_SIZE > 0
|
||
|
|
if ((entry != NULL) && (entry->extension != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) {
|
||
|
|
/* clear subIndex-th bit */
|
||
|
|
uint8_t mask = ~(1U << (subIndex & 0x07U));
|
||
|
|
entry->extension->flagsPDO[subIndex >> 3] &= mask;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if requested TPDO was transmitted
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param subIndex subIndex of the OD variable.
|
||
|
|
*
|
||
|
|
* @return Return true if event driven TPDO with mapping to OD variable, indicated by entry 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(OD_entry_t* entry, uint8_t subIndex) {
|
||
|
|
#if OD_FLAGS_PDO_SIZE > 0
|
||
|
|
if ((entry != NULL) && (entry->extension != NULL) && (subIndex < (OD_FLAGS_PDO_SIZE * 8U))) {
|
||
|
|
/* return true, if subIndex-th bit is set */
|
||
|
|
uint8_t mask = 1U << (subIndex & 0x07U);
|
||
|
|
if ((entry->extension->flagsPDO[subIndex >> 3] & mask) != 0U) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get SDO abort code from returnCode
|
||
|
|
*
|
||
|
|
* @param returnCode Returned from some OD access functions
|
||
|
|
*
|
||
|
|
* @return Corresponding @ref CO_SDO_abortCode_t
|
||
|
|
*/
|
||
|
|
uint32_t OD_getSDOabCode(ODR_t returnCode);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extend OD object with own read/write functions and/or flagsPDO
|
||
|
|
*
|
||
|
|
* This function gives application very powerful tool: definition of own IO access on OD object. Structure and
|
||
|
|
* attributes are the same as defined in original OD object, but data are read directly from (or written directly to)
|
||
|
|
* application specified object via custom function calls.
|
||
|
|
*
|
||
|
|
* Before this function specifies extension, OD variables are accessed from original OD location. After this function
|
||
|
|
* specifies extension OD variables are accessed from read/write functions specified by extension. (Except when "odOrig"
|
||
|
|
* argument to @ref OD_getSub() is set to true.)
|
||
|
|
*
|
||
|
|
* This function must also be used, when flagsPDO needs to be enabled for specific entry.
|
||
|
|
*
|
||
|
|
* @warning
|
||
|
|
* Object dictionary storage works only directly on OD variables. It does not access read function specified here. So,
|
||
|
|
* if extended OD objects needs to be preserved, then @ref OD_writeOriginal can be used inside custom write function.
|
||
|
|
*
|
||
|
|
* @warning
|
||
|
|
* Read and write functions may be called from different threads, so critical sections in custom functions must be
|
||
|
|
* observed, see @ref CO_critical_sections.
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param extension Extension object, which must be initialized externally. Extension object must exist permanently. If
|
||
|
|
* NULL, extension will be removed.
|
||
|
|
*
|
||
|
|
* @return "ODR_OK" on success, "ODR_IDX_NOT_EXIST" if OD object doesn't exist.
|
||
|
|
*/
|
||
|
|
static inline ODR_t
|
||
|
|
OD_extension_init(OD_entry_t* entry, OD_extension_t* extension) {
|
||
|
|
if (entry == NULL) {
|
||
|
|
return ODR_IDX_NOT_EXIST;
|
||
|
|
}
|
||
|
|
entry->extension = extension;
|
||
|
|
return ODR_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup CO_ODgetSetters Getters and setters
|
||
|
|
* @{
|
||
|
|
*
|
||
|
|
* Getter and setter helper functions for accessing different types of Object Dictionary variables.
|
||
|
|
*/
|
||
|
|
/**
|
||
|
|
* Get variable from Object Dictionary
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param subIndex Sub-index of the variable from the OD object.
|
||
|
|
* @param [out] val Value will be written here.
|
||
|
|
* @param len Size of value to retrieve from OD.
|
||
|
|
* @param odOrig If true, then potential IO extension on entry will be ignored and data in the original OD location will
|
||
|
|
* be returned.
|
||
|
|
*
|
||
|
|
* @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if variable does not exist in object dictionary or
|
||
|
|
* it does not have the correct length or other reason.
|
||
|
|
*/
|
||
|
|
ODR_t OD_get_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig);
|
||
|
|
|
||
|
|
/** Get int8_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_i8(const OD_entry_t* entry, uint8_t subIndex, int8_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get int16_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_i16(const OD_entry_t* entry, uint8_t subIndex, int16_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get int32_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_i32(const OD_entry_t* entry, uint8_t subIndex, int32_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get int64_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_i64(const OD_entry_t* entry, uint8_t subIndex, int64_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get uint8_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_u8(const OD_entry_t* entry, uint8_t subIndex, uint8_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get uint16_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_u16(const OD_entry_t* entry, uint8_t subIndex, uint16_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get uint32_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_u32(const OD_entry_t* entry, uint8_t subIndex, uint32_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get uint64_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_u64(const OD_entry_t* entry, uint8_t subIndex, uint64_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get float32_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_f32(const OD_entry_t* entry, uint8_t subIndex, float32_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Get float64_t variable from Object Dictionary, see @ref OD_get_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_get_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t* val, bool_t odOrig) {
|
||
|
|
return OD_get_value(entry, subIndex, val, sizeof(*val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set variable in Object Dictionary
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param subIndex Sub-index of the variable from the OD object.
|
||
|
|
* @param val Pointer to value to write.
|
||
|
|
* @param len Size of value to write.
|
||
|
|
* @param odOrig If true, then potential IO extension on entry will be ignored and data in the original OD location will
|
||
|
|
* be written.
|
||
|
|
*
|
||
|
|
* @return Value from @ref ODR_t, "ODR_OK" in case of success. Error, if variable does not exist in object dictionary or
|
||
|
|
* it does not have the correct length or other reason.
|
||
|
|
*/
|
||
|
|
ODR_t OD_set_value(const OD_entry_t* entry, uint8_t subIndex, void* val, OD_size_t len, bool_t odOrig);
|
||
|
|
|
||
|
|
/** Set int8_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_i8(const OD_entry_t* entry, uint8_t subIndex, int8_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set int16_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_i16(const OD_entry_t* entry, uint8_t subIndex, int16_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set int32_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_i32(const OD_entry_t* entry, uint8_t subIndex, int32_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set int32_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_i64(const OD_entry_t* entry, uint8_t subIndex, int64_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set uint8_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_u8(const OD_entry_t* entry, uint8_t subIndex, uint8_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set uint16_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_u16(const OD_entry_t* entry, uint8_t subIndex, uint16_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set uint32_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_u32(const OD_entry_t* entry, uint8_t subIndex, uint32_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set uint64_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_u64(const OD_entry_t* entry, uint8_t subIndex, uint64_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set float32_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_f32(const OD_entry_t* entry, uint8_t subIndex, float32_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Set float64_t variable in Object Dictionary, see @ref OD_set_value */
|
||
|
|
static inline ODR_t
|
||
|
|
OD_set_f64(const OD_entry_t* entry, uint8_t subIndex, float64_t val, bool_t odOrig) {
|
||
|
|
return OD_set_value(entry, subIndex, &val, sizeof(val), odOrig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get pointer to memory which holds data variable from Object Dictionary
|
||
|
|
*
|
||
|
|
* Function always returns "dataOrig" pointer, which points to data in the original OD location. Take care, if IO
|
||
|
|
* extension is enabled on OD entry. Take also care that "dataOrig" could be not aligned to data type.
|
||
|
|
*
|
||
|
|
* @param entry Object Dictionary entry.
|
||
|
|
* @param subIndex Sub-index of the variable from the OD object.
|
||
|
|
* @param len Required length of the variable. If len is different than zero, then actual length of the variable must
|
||
|
|
* match len or error is returned.
|
||
|
|
* @param [out] err Error reason is written here in case of error (allow NULL).
|
||
|
|
*
|
||
|
|
* @return Pointer to variable in Object Dictionary or NULL in case of error.
|
||
|
|
*/
|
||
|
|
void* OD_getPtr(const OD_entry_t* entry, uint8_t subIndex, OD_size_t len, ODR_t* err);
|
||
|
|
/** @} */ /* CO_ODgetSetters */
|
||
|
|
|
||
|
|
#if defined OD_DEFINITION || defined CO_DOXYGEN
|
||
|
|
/**
|
||
|
|
* @defgroup CO_ODdefinition OD definition objects
|
||
|
|
* @{
|
||
|
|
*
|
||
|
|
* Types and functions used only for definition of Object Dictionary
|
||
|
|
*/
|
||
|
|
/**
|
||
|
|
* Types for OD object.
|
||
|
|
*/
|
||
|
|
typedef enum {
|
||
|
|
ODT_VAR = 0x01, /**< This type corresponds to CANopen Object Dictionary object with object code equal to VAR. OD
|
||
|
|
object is type of @ref OD_obj_var_t and represents single variable of any type (any length),
|
||
|
|
located on sub-index 0. Other sub-indexes are not used. */
|
||
|
|
ODT_ARR = 0x02, /**< This type corresponds to CANopen Object Dictionary object with object code equal to ARRAY. OD
|
||
|
|
object is type of @ref OD_obj_array_t and represents array of variables with the same type,
|
||
|
|
located on sub-indexes above 0. Sub-index 0 is of type uint8_t and usually represents length of
|
||
|
|
the array. */
|
||
|
|
ODT_REC = 0x03, /**< This type corresponds to CANopen Object Dictionary object with object code equal to RECORD.
|
||
|
|
This type of OD object represents structure of the variables. Each variable from the structure
|
||
|
|
can have own type and own attribute. OD object is an array of elements of type @ref OD_obj_var_t.
|
||
|
|
Variable at sub-index 0 is of type uint8_t and usually represents number of sub-elements in the
|
||
|
|
structure. */
|
||
|
|
ODT_TYPE_MASK = 0x0F, /**< Mask for basic type */
|
||
|
|
} OD_objectTypes_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Object for single OD variable, used for "VAR" type OD objects
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
void* dataOrig; /**< Pointer to data */
|
||
|
|
OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */
|
||
|
|
OD_size_t dataLength; /**< Data length in bytes */
|
||
|
|
} OD_obj_var_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Object for OD array of variables, used for "ARRAY" type OD objects
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
uint8_t* dataOrig0; /**< Pointer to data for sub-index 0 */
|
||
|
|
void* dataOrig; /**< Pointer to array of data */
|
||
|
|
OD_attr_t attribute0; /**< Attribute bitfield for sub-index 0, see @ref OD_attributes_t */
|
||
|
|
OD_attr_t attribute; /**< Attribute bitfield for array elements */
|
||
|
|
OD_size_t dataElementLength; /**< Data length of array elements in bytes */
|
||
|
|
OD_size_t dataElementSizeof; /**< Sizeof one array element in bytes */
|
||
|
|
} OD_obj_array_t;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Object for OD sub-elements, used in "RECORD" type OD objects
|
||
|
|
*/
|
||
|
|
typedef struct {
|
||
|
|
void* dataOrig; /**< Pointer to data */
|
||
|
|
uint8_t subIndex; /**< Sub index of element. */
|
||
|
|
OD_attr_t attribute; /**< Attribute bitfield, see @ref OD_attributes_t */
|
||
|
|
OD_size_t dataLength; /**< Data length in bytes */
|
||
|
|
} OD_obj_record_t;
|
||
|
|
|
||
|
|
/** @} */ /* CO_ODdefinition */
|
||
|
|
|
||
|
|
#endif /* defined OD_DEFINITION */
|
||
|
|
|
||
|
|
/** @} */ /* CO_ODinterface */
|
||
|
|
|
||
|
|
#ifdef __cplusplus
|
||
|
|
}
|
||
|
|
#endif /* __cplusplus */
|
||
|
|
|
||
|
|
#endif /* CO_OD_INTERFACE_H */
|