962 lines
40 KiB
C
962 lines
40 KiB
C
/**
|
|
* CANopen Service Data Object - server protocol.
|
|
*
|
|
* @file CO_SDO.h
|
|
* @ingroup CO_SDO
|
|
* @author Janez Paternoster
|
|
* @copyright 2004 - 2020 Janez Paternoster
|
|
*
|
|
* This file is part of CANopenNode, an opensource CANopen Stack.
|
|
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
|
|
* For more information on CANopen see <http://www.can-cia.org/>.
|
|
*
|
|
* 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_SDO_H
|
|
#define CO_SDO_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @defgroup CO_SDO SDO server
|
|
* @ingroup CO_CANopen
|
|
* @{
|
|
*
|
|
* CANopen Service Data Object - server protocol.
|
|
*
|
|
* Service data objects (SDOs) allow the access to any entry of the CANopen
|
|
* Object dictionary. An SDO establishes a peer-to-peer communication channel
|
|
* between two devices. In addition, the SDO protocol enables to transfer any
|
|
* amount of data in a segmented way. Therefore the SDO protocol is mainly used
|
|
* in order to communicate configuration data.
|
|
*
|
|
* All CANopen devices must have implemented SDO server and first SDO server
|
|
* channel. Servers serves data from Object dictionary. Object dictionary
|
|
* is a collection of variables, arrays or records (structures), which can be
|
|
* used by the stack or by the application. This file (CO_SDO.h) implements
|
|
* SDO server.
|
|
*
|
|
* SDO client can be (optionally) implemented on one (or multiple, if multiple
|
|
* SDO channels are used) device in CANopen network. Usually this is master
|
|
* device and provides also some kind of user interface, so configuration of
|
|
* the network is possible. Code for the SDO client is in file CO_SDOmaster.h.
|
|
*
|
|
* SDO communication cycle is initiated by the client. Client can upload (read) data
|
|
* from device or can download (write) data to device. If data are less or equal
|
|
* of 4 bytes long, communication is finished by one server response (expedited
|
|
* transfer). If data are longer, they are split into multiple segments of
|
|
* request/response pairs (normal or segmented transfer). For longer data there
|
|
* is also a block transfer protocol, which transfers larger block of data in
|
|
* secure way with little protocol overhead. If error occurs during SDO transfer
|
|
* #CO_SDO_abortCode_t is send by client or server and transfer is terminated.
|
|
*/
|
|
|
|
|
|
/**
|
|
* @defgroup CO_SDO_messageContents SDO message contents
|
|
*
|
|
* Excerpt from CiA DS301, V4.2.
|
|
*
|
|
* For CAN identifier see #CO_Default_CAN_ID_t
|
|
*
|
|
* Expedited transfer is used for transmission of up to 4 data bytes. It consists
|
|
* of one SDO request and one response. For longer variables is used segmented
|
|
* or block transfer.
|
|
*
|
|
* ####Initiate SDO download (client request)
|
|
* - byte 0: SDO command specifier. 8 bits: `0010nnes` (nn: if e=s=1,
|
|
* number of data bytes, that do *not* contain data; e=1 for
|
|
* expedited transfer; s=1 if data size is indicated).
|
|
* - byte 1..2: Object index.
|
|
* - byte 3: Object subIndex.
|
|
* - byte 4..7: Expedited data or data size if segmented transfer.
|
|
*
|
|
* ####Initiate SDO download (server response)
|
|
* - byte 0: SDO command specifier. 8 bits: `01100000`.
|
|
* - byte 1..2: Object index.
|
|
* - byte 3: Object subIndex.
|
|
* - byte 4..7: reserved.
|
|
*
|
|
* ####Download SDO segment (client request)
|
|
* - byte 0: SDO command specifier. 8 bits: `000tnnnc` (t: toggle bit set
|
|
* to 0 in first segment; nnn: number of data bytes, that do
|
|
* *not* contain data; c=1 if this is the last segment).
|
|
* - byte 1..7: Data segment.
|
|
*
|
|
* ####Download SDO segment (server response)
|
|
* - byte 0: SDO command specifier. 8 bits: `001t0000` (t: toggle bit set
|
|
* to 0 in first segment).
|
|
* - byte 1..7: Reserved.
|
|
*
|
|
* ####Initiate SDO upload (client request)
|
|
* - byte 0: SDO command specifier. 8 bits: `01000000`.
|
|
* - byte 1..2: Object index.
|
|
* - byte 3: Object subIndex.
|
|
* - byte 4..7: Reserved.
|
|
*
|
|
* ####Initiate SDO upload (server response)
|
|
* - byte 0: SDO command specifier. 8 bits: `0100nnes` (nn: if e=s=1,
|
|
* number of data bytes, that do *not* contain data; e=1 for
|
|
* expedited transfer; s=1 if data size is indicated).
|
|
* - byte 1..2: Object index.
|
|
* - byte 3: Object subIndex.
|
|
* - byte 4..7: reserved.
|
|
*
|
|
* ####Upload SDO segment (client request)
|
|
* - byte 0: SDO command specifier. 8 bits: `011t0000` (t: toggle bit set
|
|
* to 0 in first segment).
|
|
* - byte 1..7: Reserved.
|
|
*
|
|
* ####Upload SDO segment (server response)
|
|
* - byte 0: SDO command specifier. 8 bits: `000tnnnc` (t: toggle bit set
|
|
* to 0 in first segment; nnn: number of data bytes, that do
|
|
* *not* contain data; c=1 if this is the last segment).
|
|
* - byte 1..7: Data segment.
|
|
*
|
|
* ####Abort SDO transfer (client or server)
|
|
* - byte 0: SDO command specifier. 8 bits: `10000000`.
|
|
* - byte 1..2: Object index.
|
|
* - byte 3: Object subIndex.
|
|
* - byte 4..7: #CO_SDO_abortCode_t.
|
|
*
|
|
* ####Block transfer
|
|
* See DS301 V4.2.
|
|
*/
|
|
|
|
|
|
/**
|
|
* SDO abort codes.
|
|
*
|
|
* Send with Abort SDO transfer message.
|
|
*
|
|
* The abort codes not listed here are reserved.
|
|
*/
|
|
typedef enum{
|
|
CO_SDO_AB_NONE = 0x00000000UL, /**< 0x00000000, No abort */
|
|
CO_SDO_AB_TOGGLE_BIT = 0x05030000UL, /**< 0x05030000, Toggle bit not altered */
|
|
CO_SDO_AB_TIMEOUT = 0x05040000UL, /**< 0x05040000, SDO protocol timed out */
|
|
CO_SDO_AB_CMD = 0x05040001UL, /**< 0x05040001, Command specifier not valid or unknown */
|
|
CO_SDO_AB_BLOCK_SIZE = 0x05040002UL, /**< 0x05040002, Invalid block size in block mode */
|
|
CO_SDO_AB_SEQ_NUM = 0x05040003UL, /**< 0x05040003, Invalid sequence number in block mode */
|
|
CO_SDO_AB_CRC = 0x05040004UL, /**< 0x05040004, CRC error (block mode only) */
|
|
CO_SDO_AB_OUT_OF_MEM = 0x05040005UL, /**< 0x05040005, Out of memory */
|
|
CO_SDO_AB_UNSUPPORTED_ACCESS = 0x06010000UL, /**< 0x06010000, Unsupported access to an object */
|
|
CO_SDO_AB_WRITEONLY = 0x06010001UL, /**< 0x06010001, Attempt to read a write only object */
|
|
CO_SDO_AB_READONLY = 0x06010002UL, /**< 0x06010002, Attempt to write a read only object */
|
|
CO_SDO_AB_NOT_EXIST = 0x06020000UL, /**< 0x06020000, Object does not exist */
|
|
CO_SDO_AB_NO_MAP = 0x06040041UL, /**< 0x06040041, Object cannot be mapped to the PDO */
|
|
CO_SDO_AB_MAP_LEN = 0x06040042UL, /**< 0x06040042, Number and length of object to be mapped exceeds PDO length */
|
|
CO_SDO_AB_PRAM_INCOMPAT = 0x06040043UL, /**< 0x06040043, General parameter incompatibility reasons */
|
|
CO_SDO_AB_DEVICE_INCOMPAT = 0x06040047UL, /**< 0x06040047, General internal incompatibility in device */
|
|
CO_SDO_AB_HW = 0x06060000UL, /**< 0x06060000, Access failed due to hardware error */
|
|
CO_SDO_AB_TYPE_MISMATCH = 0x06070010UL, /**< 0x06070010, Data type does not match, length of service parameter does not match */
|
|
CO_SDO_AB_DATA_LONG = 0x06070012UL, /**< 0x06070012, Data type does not match, length of service parameter too high */
|
|
CO_SDO_AB_DATA_SHORT = 0x06070013UL, /**< 0x06070013, Data type does not match, length of service parameter too short */
|
|
CO_SDO_AB_SUB_UNKNOWN = 0x06090011UL, /**< 0x06090011, Sub index does not exist */
|
|
CO_SDO_AB_INVALID_VALUE = 0x06090030UL, /**< 0x06090030, Invalid value for parameter (download only). */
|
|
CO_SDO_AB_VALUE_HIGH = 0x06090031UL, /**< 0x06090031, Value range of parameter written too high */
|
|
CO_SDO_AB_VALUE_LOW = 0x06090032UL, /**< 0x06090032, Value range of parameter written too low */
|
|
CO_SDO_AB_MAX_LESS_MIN = 0x06090036UL, /**< 0x06090036, Maximum value is less than minimum value. */
|
|
CO_SDO_AB_NO_RESOURCE = 0x060A0023UL, /**< 0x060A0023, Resource not available: SDO connection */
|
|
CO_SDO_AB_GENERAL = 0x08000000UL, /**< 0x08000000, General error */
|
|
CO_SDO_AB_DATA_TRANSF = 0x08000020UL, /**< 0x08000020, Data cannot be transferred or stored to application */
|
|
CO_SDO_AB_DATA_LOC_CTRL = 0x08000021UL, /**< 0x08000021, Data cannot be transferred or stored to application because of local control */
|
|
CO_SDO_AB_DATA_DEV_STATE = 0x08000022UL, /**< 0x08000022, Data cannot be transferred or stored to application because of present device state */
|
|
CO_SDO_AB_DATA_OD = 0x08000023UL, /**< 0x08000023, Object dictionary not present or dynamic generation fails */
|
|
CO_SDO_AB_NO_DATA = 0x08000024UL /**< 0x08000024, No data available */
|
|
}CO_SDO_abortCode_t;
|
|
|
|
|
|
/**
|
|
* @defgroup CO_SDO_objectDictionary Object dictionary
|
|
*
|
|
* CANopen Object dictionary implementation in CANopenNode.
|
|
*
|
|
* CANopen Object dictionary is a collection of different data items, which can
|
|
* be used by the stack or by the application.
|
|
*
|
|
* Each Object dictionary entry is located under 16-bit index, as specified
|
|
* by the CANopen:
|
|
* - 0x0001..0x025F: Data type definitions.
|
|
* - 0x1000..0x1FFF: Communication profile area.
|
|
* - 0x2000..0x5FFF: Manufacturer-specific profile area.
|
|
* - 0x6000..0x9FFF: Standardized device profile area for eight logical devices.
|
|
* - 0xA000..0xAFFF: Standardized network variable area.
|
|
* - 0xB000..0xBFFF: Standardized system variable area.
|
|
* - Other: Reserved.
|
|
*
|
|
* If Object dictionary entry has complex data type (array or structure),
|
|
* then 8-bit subIndex specifies the sub-member of the entry. In that case
|
|
* subIndex 0x00 is encoded as uint8_t and specifies the highest available
|
|
* subIndex with that entry. Subindex 0xFF has special meaning in the standard
|
|
* and is not supported by CANopenNode.
|
|
*
|
|
* ####Object type of one Object dictionary entry
|
|
* - NULL: Not used by CANopenNode.
|
|
* - DOMAIN: Block of data of variable length. Data and length are
|
|
* under control of the application.
|
|
* - DEFTYPE: Definition of CANopen basic data type, for example
|
|
* INTEGER16.
|
|
* - DEFSTRUCT: Definition of complex data type - structure, which is
|
|
* used with RECORD.
|
|
* - VAR: Variable of CANopen basic data type. Subindex is 0.
|
|
* - ARRAY: Array of multiple variables of the same CANopen basic
|
|
* data type. Subindex 1..arrayLength specifies sub-member.
|
|
* - RECORD: Record or structure of multiple variables of different
|
|
* CANopen basic data type. Subindex specifies sub-member.
|
|
*
|
|
*
|
|
* ####Implementation in CANopenNode
|
|
* Object dictionary in CANopenNode is implemented in CO_OD.h and CO_OD.c files.
|
|
* These files are application specific and must be generated by Object
|
|
* dictionary editor (application is included by the stack).
|
|
*
|
|
* CO_OD.h and CO_OD.c files include:
|
|
* - Structure definitions for records.
|
|
* - Global declaration and initialization of all variables, arrays and records
|
|
* mapped to Object dictionary. Variables are distributed in multiple objects,
|
|
* depending on memory location. This eases storage to different memories in
|
|
* microcontroller, like eeprom or flash.
|
|
* - Constant array of multiple Object dictionary entries of type
|
|
* CO_OD_entry_t. If object type is record, then entry includes additional
|
|
* constant array with members of type CO_OD_entryRecord_t. Each OD entry
|
|
* includes information: index, maxSubIndex, #CO_SDO_OD_attributes_t, data size and
|
|
* pointer to variable.
|
|
*
|
|
*
|
|
* Function CO_SDO_init() initializes object CO_SDO_t, which includes SDO
|
|
* server and Object dictionary.
|
|
*
|
|
* Application doesn't need to know anything about the Object dictionary. It can
|
|
* use variables specified in CO_OD.h file directly. If it needs more control
|
|
* over the CANopen communication with the variables, it can configure additional
|
|
* functionality with function CO_OD_configure(). Additional functionality
|
|
* include: @ref CO_SDO_OD_function and #CO_SDO_OD_flags_t.
|
|
*
|
|
* Interface to Object dictionary is provided by following functions: CO_OD_find()
|
|
* finds OD entry by index, CO_OD_getLength() returns length of variable,
|
|
* CO_OD_getAttribute returns attribute and CO_OD_getDataPointer() returns pointer
|
|
* to data. These functions are used by SDO server and by PDO configuration. They
|
|
* can also be used to access the OD by index like this.
|
|
*
|
|
* \code{.c}
|
|
* index = CO_OD_find(CO->SDO[0], OD_H1001_ERR_REG);
|
|
* if (index == 0xffff) {
|
|
* return;
|
|
* }
|
|
* length = CO_OD_getLength(CO->SDO[0], index, 1);
|
|
* if (length != sizeof(new_data)) {
|
|
* return;
|
|
* }
|
|
*
|
|
* p = CO_OD_getDataPointer(CO->SDO[0], index, 1);
|
|
* if (p == NULL) {
|
|
* return;
|
|
* }
|
|
* CO_LOCK_OD();
|
|
* *p = new_data;
|
|
* CO_UNLOCK_OD();
|
|
* \endcode
|
|
*
|
|
* Be aware that accessing the OD directly using CO_OD.h files is more CPU
|
|
* efficient as CO_OD_find() has to do a search everytime it is called.
|
|
*
|
|
*/
|
|
|
|
|
|
/**
|
|
* @defgroup CO_SDO_OD_function Object Dictionary function
|
|
*
|
|
* Optional application specific function, which may manipulate data downloaded
|
|
* or uploaded via SDO.
|
|
*
|
|
* Object dictionary function is external function defined by application or
|
|
* by other stack files. It may be registered for specific Object dictionary
|
|
* entry (with specific index). If it is registered, it is called (through
|
|
* function pointer) from SDO server. It may verify and manipulate data during
|
|
* SDO transfer. Object dictionary function can be registered by function
|
|
* CO_OD_configure().
|
|
*
|
|
* ####SDO download (writing to Object dictionary)
|
|
* After SDO client transfers data to the server, data are stored in internal
|
|
* buffer. If data contains multibyte variable and processor is big endian,
|
|
* then data bytes are swapped. Object dictionary function is called if
|
|
* registered. Data may be verified and manipulated inside that function. After
|
|
* function exits, data are copied to location as specified in CO_OD_entry_t.
|
|
*
|
|
* ####SDO upload (reading from Object dictionary)
|
|
* Before start of SDO upload, data are read from Object dictionary into
|
|
* internal buffer. If necessary, bytes are swapped.
|
|
* Object dictionary function is called if registered. Data may be
|
|
* manipulated inside that function. After function exits, data are
|
|
* transferred via SDO server.
|
|
*
|
|
* ####Domain data type
|
|
* If data type is domain, then length is not specified by Object dictionary.
|
|
* In that case Object dictionary function must be used. In case of
|
|
* download it must store the data in own location. In case of upload it must
|
|
* write the data (maximum size is specified by length) into data buffer and
|
|
* specify actual length. With domain data type it is possible to transfer
|
|
* data, which are longer than #CO_SDO_BUFFER_SIZE. In that case
|
|
* Object dictionary function is called multiple times between SDO transfer.
|
|
*
|
|
* ####Parameter to function:
|
|
* ODF_arg - Pointer to CO_ODF_arg_t object filled before function call.
|
|
*
|
|
* ####Return from function:
|
|
* - 0: Data transfer is successful
|
|
* - Different than 0: Failure. See #CO_SDO_abortCode_t.
|
|
*/
|
|
|
|
|
|
/**
|
|
* SDO buffer size.
|
|
*
|
|
* Size of the internal SDO buffer.
|
|
*
|
|
* Size must be at least equal to size of largest variable in @ref CO_SDO_objectDictionary.
|
|
* If data type is domain, data length is not limited to SDO buffer size. If
|
|
* block transfer is implemented, value should be set to 889.
|
|
*
|
|
* Value can be in range from 7 to 889 bytes.
|
|
*/
|
|
#ifndef CO_SDO_BUFFER_SIZE
|
|
#define CO_SDO_BUFFER_SIZE 32
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Object Dictionary attributes. Bit masks for attribute in CO_OD_entry_t.
|
|
*/
|
|
typedef enum{
|
|
CO_ODA_MEM_ROM = 0x0001U, /**< Variable is located in ROM memory */
|
|
CO_ODA_MEM_RAM = 0x0002U, /**< Variable is located in RAM memory */
|
|
CO_ODA_MEM_EEPROM = 0x0003U, /**< Variable is located in EEPROM memory */
|
|
CO_ODA_READABLE = 0x0004U, /**< SDO server may read from the variable */
|
|
CO_ODA_WRITEABLE = 0x0008U, /**< SDO server may write to the variable */
|
|
CO_ODA_RPDO_MAPABLE = 0x0010U, /**< Variable is mappable for RPDO */
|
|
CO_ODA_TPDO_MAPABLE = 0x0020U, /**< Variable is mappable for TPDO */
|
|
CO_ODA_TPDO_DETECT_COS = 0x0040U, /**< If variable is mapped to any PDO, then
|
|
PDO is automatically send, if variable
|
|
changes its value */
|
|
CO_ODA_MB_VALUE = 0x0080U /**< True when variable is a multibyte value */
|
|
}CO_SDO_OD_attributes_t;
|
|
|
|
|
|
/**
|
|
* 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_PARAM_FUNC = 0x1010U,/**< Store parameter in persistent memory function */
|
|
OD_H1011_REST_PARAM_FUNC = 0x1011U,/**< Restore default parameter function */
|
|
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_MSG = 0x1015U,/**< Inhibit time 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_PARAM = 0x1200U,/**< SDO server parameters */
|
|
OD_H1280_SDO_CLIENT_PARAM = 0x1280U,/**< SDO client parameters */
|
|
OD_H1400_RXPDO_1_PARAM = 0x1400U,/**< RXPDO communication parameter */
|
|
OD_H1401_RXPDO_2_PARAM = 0x1401U,/**< RXPDO communication parameter */
|
|
OD_H1402_RXPDO_3_PARAM = 0x1402U,/**< RXPDO communication parameter */
|
|
OD_H1403_RXPDO_4_PARAM = 0x1403U,/**< RXPDO communication parameter */
|
|
OD_H1600_RXPDO_1_MAPPING = 0x1600U,/**< RXPDO mapping parameters */
|
|
OD_H1601_RXPDO_2_MAPPING = 0x1601U,/**< RXPDO mapping parameters */
|
|
OD_H1602_RXPDO_3_MAPPING = 0x1602U,/**< RXPDO mapping parameters */
|
|
OD_H1603_RXPDO_4_MAPPING = 0x1603U,/**< RXPDO mapping parameters */
|
|
OD_H1800_TXPDO_1_PARAM = 0x1800U,/**< TXPDO communication parameter */
|
|
OD_H1801_TXPDO_2_PARAM = 0x1801U,/**< TXPDO communication parameter */
|
|
OD_H1802_TXPDO_3_PARAM = 0x1802U,/**< TXPDO communication parameter */
|
|
OD_H1803_TXPDO_4_PARAM = 0x1803U,/**< TXPDO communication parameter */
|
|
OD_H1A00_TXPDO_1_MAPPING = 0x1A00U,/**< TXPDO mapping parameters */
|
|
OD_H1A01_TXPDO_2_MAPPING = 0x1A01U,/**< TXPDO mapping parameters */
|
|
OD_H1A02_TXPDO_3_MAPPING = 0x1A02U,/**< TXPDO mapping parameters */
|
|
OD_H1A03_TXPDO_4_MAPPING = 0x1A03U /**< TXPDO mapping parameters */
|
|
}CO_ObjDicId_t;
|
|
|
|
|
|
/**
|
|
* Bit masks for flags associated with variable from @ref CO_SDO_objectDictionary.
|
|
*
|
|
* This additional functionality of any variable in @ref CO_SDO_objectDictionary can be
|
|
* enabled by function CO_OD_configure(). Location of the flag byte can be
|
|
* get from function CO_OD_getFlagsPointer().
|
|
*/
|
|
typedef enum{
|
|
/** Variable was written by RPDO. Flag can be cleared by application */
|
|
CO_ODFL_RPDO_WRITTEN = 0x01U,
|
|
/** Variable is mapped to TPDO */
|
|
CO_ODFL_TPDO_MAPPED = 0x02U,
|
|
/** Change of state bit, initially copy of attribute from CO_OD_entry_t.
|
|
If set and variable is mapped to TPDO, TPDO will be automatically send,
|
|
if variable changed */
|
|
CO_ODFL_TPDO_COS_ENABLE = 0x04U,
|
|
/** PDO send bit, can be set by application. If variable is mapped into
|
|
TPDO, TPDO will be send and bit will be cleared. */
|
|
CO_ODFL_TPDO_SEND = 0x08U,
|
|
/** Variable was accessed by SDO download */
|
|
CO_ODFL_SDO_DOWNLOADED = 0x10U,
|
|
/** Variable was accessed by SDO upload */
|
|
CO_ODFL_SDO_UPLOADED = 0x20U,
|
|
/** Reserved */
|
|
CO_ODFL_BIT_6 = 0x40U,
|
|
/** Reserved */
|
|
CO_ODFL_BIT_7 = 0x80U
|
|
}CO_SDO_OD_flags_t;
|
|
|
|
|
|
/**
|
|
* Internal states of the SDO server state machine
|
|
*/
|
|
typedef enum {
|
|
CO_SDO_ST_IDLE = 0x00U,
|
|
CO_SDO_ST_DOWNLOAD_INITIATE = 0x11U,
|
|
CO_SDO_ST_DOWNLOAD_SEGMENTED = 0x12U,
|
|
CO_SDO_ST_DOWNLOAD_BL_INITIATE = 0x14U,
|
|
CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK = 0x15U,
|
|
CO_SDO_ST_DOWNLOAD_BL_SUB_RESP = 0x16U,
|
|
CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2 = 0x17U,
|
|
CO_SDO_ST_DOWNLOAD_BL_END = 0x18U,
|
|
CO_SDO_ST_UPLOAD_INITIATE = 0x21U,
|
|
CO_SDO_ST_UPLOAD_SEGMENTED = 0x22U,
|
|
CO_SDO_ST_UPLOAD_BL_INITIATE = 0x24U,
|
|
CO_SDO_ST_UPLOAD_BL_INITIATE_2 = 0x25U,
|
|
CO_SDO_ST_UPLOAD_BL_SUBBLOCK = 0x26U,
|
|
CO_SDO_ST_UPLOAD_BL_END = 0x27U
|
|
} CO_SDO_state_t;
|
|
|
|
|
|
/**
|
|
* Object for one entry with specific index in @ref CO_SDO_objectDictionary.
|
|
*/
|
|
typedef struct {
|
|
/** The index of Object from 0x1000 to 0xFFFF */
|
|
uint16_t index;
|
|
/** Number of (sub-objects - 1). If Object Type is variable, then
|
|
maxSubIndex is 0, otherwise maxSubIndex is equal or greater than 1. */
|
|
uint8_t maxSubIndex;
|
|
/** If Object Type is record, attribute is set to zero. Attribute for
|
|
each member is then set in special array with members of type
|
|
CO_OD_entryRecord_t. If Object Type is Array, attribute is common for
|
|
all array members. See #CO_SDO_OD_attributes_t. */
|
|
uint16_t attribute;
|
|
/** If Object Type is Variable, length is the length of variable in bytes.
|
|
If Object Type is Array, length is the length of one array member.
|
|
If Object Type is Record, length is zero. Length for each member is
|
|
set in special array with members of type CO_OD_entryRecord_t.
|
|
If Object Type is Domain, length is zero. Length is specified
|
|
by application in @ref CO_SDO_OD_function. */
|
|
uint16_t length;
|
|
/** If Object Type is Variable, pData is pointer to data.
|
|
If Object Type is Array, pData is pointer to data. Data doesn't
|
|
include Sub-Object 0.
|
|
If object type is Record, pData is pointer to special array
|
|
with members of type CO_OD_entryRecord_t.
|
|
If object type is Domain, pData is null. */
|
|
void *pData;
|
|
}CO_OD_entry_t;
|
|
|
|
|
|
/**
|
|
* Object for record type entry in @ref CO_SDO_objectDictionary.
|
|
*
|
|
* See CO_OD_entry_t.
|
|
*/
|
|
typedef struct{
|
|
/** See #CO_SDO_OD_attributes_t */
|
|
void *pData;
|
|
/** Length of variable in bytes. If object type is Domain, length is zero */
|
|
uint16_t attribute;
|
|
/** Pointer to data. If object type is Domain, pData is null */
|
|
uint16_t length;
|
|
}CO_OD_entryRecord_t;
|
|
|
|
|
|
/**
|
|
* Object contains all information about the object being transferred by SDO server.
|
|
*
|
|
* Object is used as an argument to @ref CO_SDO_OD_function. It is also
|
|
* part of the CO_SDO_t object.
|
|
*/
|
|
typedef struct{
|
|
/** Informative parameter. It may point to object, which is connected
|
|
with this OD entry. It can be used inside @ref CO_SDO_OD_function, ONLY
|
|
if it was registered by CO_OD_configure() function before. */
|
|
void *object;
|
|
/** SDO data buffer contains data, which are exchanged in SDO transfer.
|
|
@ref CO_SDO_OD_function may verify or manipulate that data before (after)
|
|
they are written to (read from) Object dictionary. Data have the same
|
|
endianes as processor. Pointer must NOT be changed. (Data up to length
|
|
can be changed.) */
|
|
uint8_t *data;
|
|
/** Pointer to location in object dictionary, where data are stored.
|
|
(informative reference to old data, read only). Data have the same
|
|
endianes as processor. If data type is Domain, this variable is null. */
|
|
const void *ODdataStorage;
|
|
/** Length of data in the above buffer. Read only, except for domain. If
|
|
data type is domain see @ref CO_SDO_OD_function for special rules by upload. */
|
|
uint16_t dataLength;
|
|
/** Attribute of object in Object dictionary (informative, must NOT be changed). */
|
|
uint16_t attribute;
|
|
/** Pointer to the #CO_SDO_OD_flags_t byte. */
|
|
uint8_t *pFlags;
|
|
/** Index of object in Object dictionary (informative, must NOT be changed). */
|
|
uint16_t index;
|
|
/** Subindex of object in Object dictionary (informative, must NOT be changed). */
|
|
uint8_t subIndex;
|
|
/** True, if SDO upload is in progress, false if SDO download is in progress. */
|
|
bool_t reading;
|
|
/** Used by domain data type. Indicates the first segment. Variable is informative. */
|
|
bool_t firstSegment;
|
|
/** Used by domain data type. If false by download, then application will
|
|
receive more segments during SDO communication cycle. If uploading,
|
|
application may set variable to false, so SDO server will call
|
|
@ref CO_SDO_OD_function again for filling the next data. */
|
|
bool_t lastSegment;
|
|
/** Used by domain data type. By upload @ref CO_SDO_OD_function may write total
|
|
data length, so this information will be send in SDO upload initiate phase. It
|
|
is not necessary to specify this variable. By download this variable contains
|
|
total data size, if size is indicated in SDO download initiate phase */
|
|
uint32_t dataLengthTotal;
|
|
/** Used by domain data type. In case of multiple segments, this indicates the offset
|
|
into the buffer this segment starts at. */
|
|
uint32_t offset;
|
|
}CO_ODF_arg_t;
|
|
|
|
|
|
/**
|
|
* Object is used as array inside CO_SDO_t, parallel to @ref CO_SDO_objectDictionary.
|
|
*
|
|
* Object is generated by function CO_OD_configure(). It is then used as
|
|
* extension to Object dictionary entry at specific index.
|
|
*/
|
|
typedef struct{
|
|
/** Pointer to @ref CO_SDO_OD_function */
|
|
CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg);
|
|
/** Pointer to object, which will be passed to @ref CO_SDO_OD_function */
|
|
void *object;
|
|
/** Pointer to #CO_SDO_OD_flags_t. If object type is array or record, this
|
|
variable points to array with length equal to number of subindexes. */
|
|
uint8_t *flags;
|
|
}CO_OD_extension_t;
|
|
|
|
|
|
/**
|
|
* SDO server object.
|
|
*/
|
|
typedef struct{
|
|
/** 8 data bytes of the received message. */
|
|
uint8_t CANrxData[8];
|
|
/** SDO data buffer of size #CO_SDO_BUFFER_SIZE. */
|
|
uint8_t databuffer[CO_SDO_BUFFER_SIZE];
|
|
/** Internal flag indicates, that this object has own OD */
|
|
bool_t ownOD;
|
|
/** Pointer to the @ref CO_SDO_objectDictionary (array) */
|
|
const CO_OD_entry_t *OD;
|
|
/** Size of the @ref CO_SDO_objectDictionary */
|
|
uint16_t ODSize;
|
|
/** Pointer to array of CO_OD_extension_t objects. Size of the array is
|
|
equal to ODSize. */
|
|
CO_OD_extension_t *ODExtensions;
|
|
/** Offset in buffer of next data segment being read/written */
|
|
uint16_t bufferOffset;
|
|
/** Sequence number of OD entry as returned from CO_OD_find() */
|
|
uint16_t entryNo;
|
|
/** CO_ODF_arg_t object with additional variables. Reference to this object
|
|
is passed to @ref CO_SDO_OD_function */
|
|
CO_ODF_arg_t ODF_arg;
|
|
/** From CO_SDO_init() */
|
|
uint8_t nodeId;
|
|
/** Current internal state of the SDO server state machine #CO_SDO_state_t */
|
|
CO_SDO_state_t state;
|
|
/** Toggle bit in segmented transfer or block sequence in block transfer */
|
|
uint8_t sequence;
|
|
/** Timeout timer for SDO communication */
|
|
uint16_t timeoutTimer;
|
|
/** Number of segments per block with 1 <= blksize <= 127 */
|
|
uint8_t blksize;
|
|
/** True, if CRC calculation by block transfer is enabled */
|
|
bool_t crcEnabled;
|
|
/** Calculated CRC code */
|
|
uint16_t crc;
|
|
/** Length of data in the last segment in block upload */
|
|
uint8_t lastLen;
|
|
/** Indication timeout in sub-block transfer */
|
|
bool_t timeoutSubblockDownolad;
|
|
/** Indication end of block transfer */
|
|
bool_t endOfTransfer;
|
|
/** Variable indicates, if new SDO message received from CAN bus */
|
|
volatile void *CANrxNew;
|
|
/** From CO_SDO_initCallback() or NULL */
|
|
void (*pFunctSignal)(void);
|
|
/** From CO_SDO_init() */
|
|
CO_CANmodule_t *CANdevTx;
|
|
/** CAN transmit buffer inside CANdev for CAN tx message */
|
|
CO_CANtx_t *CANtxBuff;
|
|
}CO_SDO_t;
|
|
|
|
|
|
/**
|
|
* Helper union for manipulating data bytes.
|
|
*/
|
|
typedef union{
|
|
uint8_t u8[8]; /**< 8 bytes */
|
|
uint16_t u16[4]; /**< 4 words */
|
|
uint32_t u32[2]; /**< 2 double words */
|
|
}CO_bytes_t;
|
|
|
|
|
|
/**
|
|
* Helper function like memcpy.
|
|
*
|
|
* Function copies n data bytes from source to destination.
|
|
*
|
|
* @param dest Destination location.
|
|
* @param src Source location.
|
|
* @param size Number of data bytes to be copied (max 0xFFFF).
|
|
*/
|
|
void CO_memcpy(uint8_t dest[], const uint8_t src[], const uint16_t size);
|
|
|
|
/**
|
|
* Helper function like memset.
|
|
*
|
|
* Function fills destination with char "c".
|
|
*
|
|
* @param dest Destination location.
|
|
* @param c set value.
|
|
* @param size Number of data bytes to be copied (max 0xFFFF).
|
|
*/
|
|
void CO_memset(uint8_t dest[], uint8_t c, const uint16_t size);
|
|
|
|
|
|
/**
|
|
* Helper function returns uint16 from byte array.
|
|
*
|
|
* @param data Location of source data.
|
|
* @return Variable of type uint16_t.
|
|
*/
|
|
uint16_t CO_getUint16(const uint8_t data[]);
|
|
|
|
|
|
/**
|
|
* Helper function returns uint32 from byte array.
|
|
*
|
|
* @param data Location of source data.
|
|
* @return Variable of type uint32_t.
|
|
*/
|
|
uint32_t CO_getUint32(const uint8_t data[]);
|
|
|
|
|
|
/**
|
|
* Helper function writes uint16 to byte array.
|
|
*
|
|
* @param data Location of destination data.
|
|
* @param value Variable of type uint16_t to be written into data.
|
|
*/
|
|
void CO_setUint16(uint8_t data[], const uint16_t value);
|
|
|
|
|
|
/**
|
|
* Helper function writes uint32 to byte array.
|
|
*
|
|
* @param data Location of destination data.
|
|
* @param value Variable of type uint32_t to be written into data.
|
|
*/
|
|
void CO_setUint32(uint8_t data[], const uint32_t value);
|
|
|
|
|
|
/**
|
|
* Copy 2 data bytes from source to destination. Swap bytes if
|
|
* microcontroller is big-endian.
|
|
*
|
|
* @param dest Destination location.
|
|
* @param src Source location.
|
|
*/
|
|
void CO_memcpySwap2(void* dest, const void* src);
|
|
|
|
|
|
/**
|
|
* Copy 4 data bytes from source to destination. Swap bytes if
|
|
* microcontroller is big-endian.
|
|
*
|
|
* @param dest Destination location.
|
|
* @param src Source location.
|
|
*/
|
|
void CO_memcpySwap4(void* dest, const void* src);
|
|
|
|
|
|
/**
|
|
* Copy 8 data bytes from source to destination. Swap bytes if
|
|
* microcontroller is big-endian.
|
|
*
|
|
* @param dest Destination location.
|
|
* @param src Source location.
|
|
*/
|
|
void CO_memcpySwap8(void* dest, const void* src);
|
|
|
|
|
|
/**
|
|
* Initialize SDO object.
|
|
*
|
|
* Function must be called in the communication reset section.
|
|
*
|
|
* @param SDO This object will be initialized.
|
|
* @param COB_IDClientToServer COB ID for client to server for this SDO object.
|
|
* @param COB_IDServerToClient COB ID for server to client for this SDO object.
|
|
* @param ObjDictIndex_SDOServerParameter Index in Object dictionary.
|
|
* @param parentSDO Pointer to SDO object, which contains object dictionary and
|
|
* its extension. For first (default) SDO object this argument must be NULL.
|
|
* If this argument is specified, then OD, ODSize and ODExtensions arguments
|
|
* are ignored.
|
|
* @param OD Pointer to @ref CO_SDO_objectDictionary array defined externally.
|
|
* @param ODSize Size of the above array.
|
|
* @param ODExtensions Pointer to the externally defined array of the same size
|
|
* as ODSize.
|
|
* @param nodeId CANopen Node ID of this device.
|
|
* @param CANdevRx CAN device for SDO server reception.
|
|
* @param CANdevRxIdx Index of receive buffer in the above CAN device.
|
|
* @param CANdevTx CAN device for SDO server 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_SDO_init(
|
|
CO_SDO_t *SDO,
|
|
uint32_t COB_IDClientToServer,
|
|
uint32_t COB_IDServerToClient,
|
|
uint16_t ObjDictIndex_SDOServerParameter,
|
|
CO_SDO_t *parentSDO,
|
|
const CO_OD_entry_t OD[],
|
|
uint16_t ODSize,
|
|
CO_OD_extension_t ODExtensions[],
|
|
uint8_t nodeId,
|
|
CO_CANmodule_t *CANdevRx,
|
|
uint16_t CANdevRxIdx,
|
|
CO_CANmodule_t *CANdevTx,
|
|
uint16_t CANdevTxIdx);
|
|
|
|
|
|
/**
|
|
* Initialize SDOrx callback function.
|
|
*
|
|
* Function initializes optional callback function, which is called after new
|
|
* message is received from the CAN bus. Function may wake up external task,
|
|
* which processes mainline CANopen functions.
|
|
*
|
|
* @param SDO This object.
|
|
* @param pFunctSignal Pointer to the callback function. Not called if NULL.
|
|
*/
|
|
void CO_SDO_initCallback(
|
|
CO_SDO_t *SDO,
|
|
void (*pFunctSignal)(void));
|
|
|
|
|
|
/**
|
|
* Process SDO communication.
|
|
*
|
|
* Function must be called cyclically.
|
|
*
|
|
* @param SDO This object.
|
|
* @param NMTisPreOrOperational Different than zero, if #CO_NMT_internalState_t is
|
|
* NMT_PRE_OPERATIONAL or NMT_OPERATIONAL.
|
|
* @param timeDifference_ms Time difference from previous function call in [milliseconds].
|
|
* @param SDOtimeoutTime Timeout time for SDO communication in milliseconds.
|
|
* @param timerNext_ms Return value - info to OS - see CO_process().
|
|
*
|
|
* @return 0: SDO server is idle.
|
|
* @return 1: SDO server is in transfer state.
|
|
* @return -1: SDO abort just occurred.
|
|
*/
|
|
int8_t CO_SDO_process(
|
|
CO_SDO_t *SDO,
|
|
bool_t NMTisPreOrOperational,
|
|
uint16_t timeDifference_ms,
|
|
uint16_t SDOtimeoutTime,
|
|
uint16_t *timerNext_ms);
|
|
|
|
|
|
/**
|
|
* Configure additional functionality to one @ref CO_SDO_objectDictionary entry.
|
|
*
|
|
* Additional functionality include: @ref CO_SDO_OD_function and
|
|
* #CO_SDO_OD_flags_t. It is optional feature and can be used on any object in
|
|
* Object dictionary. If OD entry does not exist, function returns silently.
|
|
*
|
|
* @param SDO This object.
|
|
* @param index Index of object in the Object dictionary.
|
|
* @param pODFunc Pointer to @ref CO_SDO_OD_function, specified by application.
|
|
* If NULL, @ref CO_SDO_OD_function will not be used on this object.
|
|
* @param object Pointer to object, which will be passed to @ref CO_SDO_OD_function.
|
|
* @param flags Pointer to array of #CO_SDO_OD_flags_t defined externally. If
|
|
* zero, #CO_SDO_OD_flags_t will not be used on this OD entry.
|
|
* @param flagsSize Size of the above array. It must be equal to number
|
|
* of sub-objects in object dictionary entry. Otherwise #CO_SDO_OD_flags_t will
|
|
* not be used on this OD entry.
|
|
*/
|
|
void CO_OD_configure(
|
|
CO_SDO_t *SDO,
|
|
uint16_t index,
|
|
CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg),
|
|
void *object,
|
|
uint8_t *flags,
|
|
uint8_t flagsSize);
|
|
|
|
|
|
/**
|
|
* Find object with specific index in Object dictionary.
|
|
*
|
|
* @param SDO This object.
|
|
* @param index Index of the object in Object dictionary.
|
|
*
|
|
* @return Sequence number of the @ref CO_SDO_objectDictionary entry, 0xFFFF if not found.
|
|
*/
|
|
uint16_t CO_OD_find(CO_SDO_t *SDO, uint16_t index);
|
|
|
|
|
|
/**
|
|
* Get length of the given object with specific subIndex.
|
|
*
|
|
* @param SDO This object.
|
|
* @param entryNo Sequence number of OD entry as returned from CO_OD_find().
|
|
* @param subIndex Sub-index of the object in Object dictionary.
|
|
*
|
|
* @return Data length of the variable.
|
|
*/
|
|
uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex);
|
|
|
|
|
|
/**
|
|
* Get attribute of the given object with specific subIndex. See #CO_SDO_OD_attributes_t.
|
|
*
|
|
* If Object Type is array and subIndex is zero, function always returns
|
|
* 'read-only' attribute. An exception to this rule is ID1003 (Error field).
|
|
* However, this is supposed to be only written by network.
|
|
*
|
|
* @param SDO This object.
|
|
* @param entryNo Sequence number of OD entry as returned from CO_OD_find().
|
|
* @param subIndex Sub-index of the object in Object dictionary.
|
|
*
|
|
* @return Attribute of the variable.
|
|
*/
|
|
uint16_t CO_OD_getAttribute(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex);
|
|
|
|
|
|
/**
|
|
* Get pointer to data of the given object with specific subIndex.
|
|
*
|
|
* If Object Type is array and subIndex is zero, function returns pointer to
|
|
* object->maxSubIndex variable.
|
|
*
|
|
* @param SDO This object.
|
|
* @param entryNo Sequence number of OD entry as returned from CO_OD_find().
|
|
* @param subIndex Sub-index of the object in Object dictionary.
|
|
*
|
|
* @return Pointer to the variable in @ref CO_SDO_objectDictionary.
|
|
*/
|
|
void* CO_OD_getDataPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex);
|
|
|
|
|
|
/**
|
|
* Get pointer to the #CO_SDO_OD_flags_t byte of the given object with
|
|
* specific subIndex.
|
|
*
|
|
* @param SDO This object.
|
|
* @param entryNo Sequence number of OD entry as returned from CO_OD_find().
|
|
* @param subIndex Sub-index of the object in Object dictionary.
|
|
*
|
|
* @return Pointer to the #CO_SDO_OD_flags_t of the variable.
|
|
*/
|
|
uint8_t* CO_OD_getFlagsPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex);
|
|
|
|
|
|
/**
|
|
* Initialize SDO transfer.
|
|
*
|
|
* Find object in OD, verify, fill ODF_arg s.
|
|
*
|
|
* @param SDO This object.
|
|
* @param index Index of the object in Object dictionary.
|
|
* @param subIndex subIndex of the object in Object dictionary.
|
|
*
|
|
* @return 0 on success, otherwise #CO_SDO_abortCode_t.
|
|
*/
|
|
uint32_t CO_SDO_initTransfer(CO_SDO_t *SDO, uint16_t index, uint8_t subIndex);
|
|
|
|
|
|
/**
|
|
* Read data from @ref CO_SDO_objectDictionary to internal buffer.
|
|
*
|
|
* ODF_arg s must be initialized before with CO_SDO_initTransfer().
|
|
* @ref CO_SDO_OD_function is called if configured.
|
|
*
|
|
* @param SDO This object.
|
|
* @param SDOBufferSize Total size of the SDO buffer.
|
|
*
|
|
* @return 0 on success, otherwise #CO_SDO_abortCode_t.
|
|
*/
|
|
uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize);
|
|
|
|
|
|
/**
|
|
* Write data from internal buffer to @ref CO_SDO_objectDictionary.
|
|
*
|
|
* ODF_arg s must be initialized before with CO_SDO_initTransfer().
|
|
* @ref CO_SDO_OD_function is called if configured.
|
|
*
|
|
* @param SDO This object.
|
|
* @param length Length of data (received from network) to write.
|
|
*
|
|
* @return 0 on success, otherwise #CO_SDO_abortCode_t.
|
|
*/
|
|
uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /*__cplusplus*/
|
|
|
|
/** @} */
|
|
#endif
|