/*
This file is part of CanFestival, a library implementing CanOpen Stack.
Copyright (C): Edouard TISSERANT and Francis DUPIN
See COPYING file for copyrights details.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @defgroup comobj Communication Objects
* @ingroup userapi
*/
/** @defgroup sdo Service Data Object (SDO)
* SDOs provide the access to entries in the CANopen Object Dictionary.
* An SDO is made up of at least two CAN messages with different identifiers.
* SDO s are always confirmed point-to-point communications services.
* @ingroup comobj
*/
#ifndef __sdo_h__
#define __sdo_h__
struct struct_s_transfer;
#include "timer.h"
/* Block mode : Data consumer receive step
* - set to RXSTEP_STARTED when client receive initiate upload response
* - set to RXSTEP_END when last segment of a block received
*/
typedef enum {RXSTEP_INIT, RXSTEP_STARTED, RXSTEP_END } rxStep_t;
typedef void (*SDOCallback_t)(CO_Data* d, UNS8 nodeId);
/* The Transfer structure
Used to store the different segments of
- a SDO received before writing in the dictionary
- the reading of the dictionary to put on a SDO to transmit
WARNING : after a change in this structure check the macro s_transfer_Initializer in data.h
*/
struct struct_s_transfer {
UNS8 CliServNbr; /**< The index of the SDO client / server in our OD minus 0x1280 / 0x1200 */
UNS8 whoami; /**< Takes the values SDO_CLIENT or SDO_SERVER */
UNS8 state; /**< state of the transmission : Takes the values SDO_... */
UNS8 toggle;
UNS32 abortCode; /**< Sent or received */
/**< index and subindex of the dictionary where to store */
/**< (for a received SDO) or to read (for a transmit SDO) */
UNS16 index;
UNS8 subIndex;
UNS32 count; /**< Number of data received or to be sent. */
UNS32 offset; /**< stack pointer of data[]
* Used only to tranfer part of a line to or from a SDO.
* offset is always pointing on the next free cell of data[].
* WARNING s_transfer.data is subject to ENDIANISATION
* (with respect to CANOPEN_BIG_ENDIAN)
*/
UNS8 data [SDO_MAX_LENGTH_TRANSFER];
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
UNS8 *dynamicData;
UNS32 dynamicDataSize;
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION
UNS8 peerCRCsupport; /**< True if peer supports CRC */
UNS8 blksize; /**< Number of segments per block with 0 < blksize < 128 */
UNS8 ackseq; /**< sequence number of last segment that was received successfully */
UNS32 objsize; /**< Size in bytes of the object provided by data producer */
UNS8 lastblockoffset; /**< Value of offset before last block */
UNS8 seqno; /**< Last sequence number received OK or transmitted */
UNS8 endfield; /**< nbr of bytes in last segment of last block that do not contain data */
rxStep_t rxstep; /**< data consumer receive step - set to true when last segment of a block received */
UNS8 tmpData[8]; /**< temporary segment storage */
UNS8 dataType; /**< Defined in objdictdef.h Value is visible_string
* if it is a string, any other value if it is not a string,
* like 0. In fact, it is used only if client.
*/
TIMER_HANDLE timer; /**< Time counter to implement a timeout in milliseconds.
* It is automatically incremented whenever
* the line state is in SDO_DOWNLOAD_IN_PROGRESS or
* SDO_UPLOAD_IN_PROGRESS, and reseted to 0
* when the response SDO have been received.
*/
SDOCallback_t Callback; /**< The user callback func to be called at SDO transaction end */
};
typedef struct struct_s_transfer s_transfer;
#include "data.h"
/**
* @brief Reset of a SDO exchange on timeout.
* Send a SDO abort.
* @param *d Pointer on a CAN object data structure
* @param id
*/
void SDOTimeoutAlarm(CO_Data* d, UNS32 id);
/**
* @brief Reset all SDO buffers.
* @param *d Pointer on a CAN object data structure
*/
void resetSDO (CO_Data* d);
/**
* @brief Copy the data received from the SDO line transfer to the object dictionary.
* @param *d Pointer on a CAN object data structure
* @param line SDO line
* @return SDO error code if error. Else, returns 0.
*/
UNS32 SDOlineToObjdict (CO_Data* d, UNS8 line);
/**
* @brief Copy the data from the object dictionary to the SDO line for a network transfer.
* @param *d Pointer on a CAN object data structure
* @param line SDO line
* @return SDO error code if error. Else, returns 0.
*/
UNS32 objdictToSDOline (CO_Data* d, UNS8 line);
/**
* @brief Copy data from an existant line in the argument "* data"
* @param d Pointer on a CAN object data structure
* @param line SDO line
* @param nbBytes
* @param *data Pointer on the data
* @return 0xFF if error. Else, returns 0.
*/
UNS8 lineToSDO (CO_Data* d, UNS8 line, UNS32 nbBytes, UNS8 * data);
/**
* @brief Add data to an existant line
* @param d Pointer on a CAN object data structure
* @param line SDO line
* @param nbBytes
* @param *data Pointer on the data
* @return 0xFF if error. Else, returns 0.
*/
UNS8 SDOtoLine (CO_Data* d, UNS8 line, UNS32 nbBytes, UNS8 * data);
/**
* @brief Called when an internal SDO abort occurs.
* Release the line * Only if server *
* If client, the line must be released manually in the core application.
* The reason of that is to permit the program to read the transfers structure before its reset,
* because many informations are stored on it : index, subindex, data received or trasmited, ...
* In all cases, sends a SDO abort.
* @param *d Pointer on a CAN object data structure
* @param CliServNbr
* @param whoami
* @param index
* @param subIndex
* @param abortCode
* @return 0
*/
UNS8 failedSDO (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS16 index, UNS8 subIndex, UNS32 abortCode);
/**
* @brief Reset an unused line.
* @param *d Pointer on a CAN object data structure
* @param line SDO line
*/
void resetSDOline (CO_Data* d, UNS8 line);
/**
* @brief Initialize some fields of the structure.
* @param *d Pointer on a CAN object data structure
* @param line
* @param CliServNbr
* @param index
* @param subIndex
* @param state
* @return 0
*/
UNS8 initSDOline (CO_Data* d, UNS8 line, UNS8 CliServNbr, UNS16 index, UNS8 subIndex, UNS8 state);
/**
* @brief Search for an unused line in the transfers array
* to store a new SDO.
* ie a line which value of the field "state" is "SDO_RESET"
* An unused line have the field "state" at the value SDO_RESET
* @param *d Pointer on a CAN object data structure
* @param whoami Create the line for a SDO_SERVER or SDO_CLIENT.
* @param *line Pointer on a SDO line
* @return 0xFF if all the lines are on use. Else, return 0.
*/
UNS8 getSDOfreeLine (CO_Data* d, UNS8 whoami, UNS8 *line);
/**
* @brief Search for the line, in the transfers array, which contains the
* beginning of the reception of a fragmented SDO
* @param *d Pointer on a CAN object data structure
* @param CliServNbr Client or Server object involved
* @param whoami takes 2 values : look for a line opened as SDO_CLIENT or SDO_SERVER
* @param *line Pointer on a SDO line
* @return 0xFF if error. Else, return 0
*/
UNS8 getSDOlineOnUse (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS8 *line);
/**
* @brief Search for the line, in the transfers array, which contains the
* beginning of the reception of a fragmented SDO
*
* Because getSDOlineOnUse() does not return any line in state \c SDO_ABORTED_INTERNAL,
* this funtion is used to return them, too.
*
* @param *d Pointer on a CAN object data structure
* @param CliServNbr Client or Server object involved
* @param whoami takes 2 values : look for a line opened as SDO_CLIENT or SDO_SERVER
* @param *line Pointer on a SDO line
* @return 0xFF if error. Else, return 0
*/
UNS8 getSDOlineToClose (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS8 *line);
/**
* @brief Close a transmission.
* @param *d Pointer on a CAN object data structure
* @param CliServNbr Client or Server object involved
* @param whoami Line opened as SDO_CLIENT or SDO_SERVER
*/
UNS8 closeSDOtransfer (CO_Data* d, UNS8 CliServNbr, UNS8 whoami);
/**
* @brief Bytes in the line structure which must be transmited (or received)
* @param *d Pointer on a CAN object data structure
* @param line SDO line
* @param *nbBytes Pointer on nbBytes
* @return 0.
*/
UNS8 getSDOlineRestBytes (CO_Data* d, UNS8 line, UNS32 * nbBytes);
/**
* @brief Store in the line structure the nb of bytes which must be transmited (or received)
* @param *d Pointer on a CAN object data structure
* @param line SDO line
* @param nbBytes
* @return 0 if success, 0xFF if error.
*/
UNS8 setSDOlineRestBytes (CO_Data* d, UNS8 line, UNS32 nbBytes);
/**
* @brief Transmit a SDO frame on the bus bus_id
* @param *d Pointer on a CAN object data structure
* @param whoami Takes 2 values : SDO_CLIENT or SDO_SERVER
* @param CliServNbr Client or Server object involved
* @param data Array of the 8 bytes to transmit
* @return canSend(bus_id,&m) or 0xFF if error.
*/
UNS8 sendSDO (CO_Data* d, UNS8 whoami, UNS8 CliServNbr, UNS8 *pData);
/**
* @brief Transmit a SDO error to the client. The reasons may be :
* Read/Write to a undefined object
* Read/Write to a undefined subindex
* Read/write a not valid length object
* Write a read only object
* @param *d Pointer on a CAN object data structure
* @param whoami takes 2 values : SDO_CLIENT or SDO_SERVER
* @param CliServNbr
* @param index
* @param subIndex
* @param abortCode
* @return 0
*/
UNS8 sendSDOabort (CO_Data* d, UNS8 whoami, UNS8 CliServNbr, UNS16 index, UNS8 subIndex, UNS32 abortCode);
/**
* @brief Treat a SDO frame reception
* call the function sendSDO
* @param *d Pointer on a CAN object data structure
* @param *m Pointer on a CAN message structure
* @return code :
* - 0xFF if error
* - 0x80 if transfer aborted by the server
* - 0x0 ok
*/
UNS8 proceedSDO (CO_Data* d, Message *m);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to write the data at the index and subIndex indicated
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param count number of bytes to write in the dictionnary.
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @param *data Pointer to data
* @return
* - 0 is returned upon success.
* - 0xFE is returned when no sdo client to communicate with node.
* - 0xFF is returned when error occurs.
*/
UNS8 writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to write in a distant node dictionnary.
* @details The function Callback which must be defined in the user code is called at the
* end of the exchange. (on succes or abort).
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param count number of bytes to write in the dictionnary.
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @param *data Pointer to data
* @param Callback Callback function
* @return
* - 0 is returned upon success.
* - 0xFE is returned when no sdo client to communicate with node.
* - 0xFF is returned when error occurs.
*/
UNS8 writeNetworkDictCallBack (CO_Data* d, UNS8 nodeId, UNS16 index,
UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to write in a distant node dictionnary.
* @details The function Callback which must be defined in the user code is called at the
* end of the exchange. (on succes or abort). First free SDO client parameter is
* automatically initialized for specific node if not already defined.
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param count number of bytes to write in the dictionnary.
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @param *data Pointer to data
* @param Callback Callback function
* @param endianize When not 0, data is endianized into network byte order
* when 0, data is not endianized and copied in machine native
* endianness
* @return
* - 0 is returned upon success.
* - 0xFF is returned when error occurs.
*/
UNS8 writeNetworkDictCallBackAI (CO_Data* d, UNS8 nodeId, UNS16 index,
UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 endianize, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to read.
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @return
* - 0 is returned upon success.
* - 0xFE is returned when no sdo client to communicate with node.
* - 0xFF is returned when error occurs.
*/
UNS8 readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to read in a distant node dictionnary.
* @details The function Callback which must be defined in the user code is called at the
* end of the exchange. (on succes or abort).
* @param *d Pointer on a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @param Callback Callback function
* @return
* - 0 is returned upon success.
* - 0xFE is returned when no sdo client to communicate with node.
* - 0xFF is returned when error occurs.
*/
UNS8 readNetworkDictCallback (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Used to send a SDO request frame to read in a distant node dictionnary.
* @details The function Callback which must be defined in the user code is called at the
* end of the exchange. (on succes or abort). First free SDO client parameter is
* automatically initialized for specific node if not already defined.
* @param *d Pointer on a CAN object data structure
* @param nodeId Node Id of the slave
* @param index At index indicated
* @param subIndex At subIndex indicated
* @param dataType (defined in objdictdef.h) : put "visible_string" for strings, 0 for integers or reals or other value.
* @param Callback Callback function
* @return
* - 0 is returned upon success.
* - 0xFF is returned when error occurs.
*/
UNS8 readNetworkDictCallbackAI (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode);
/**
* @ingroup sdo
* @brief Use this function after calling readNetworkDict to get the result.
*
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param *data Pointer to the buffer to get the data
* @param *size Pointer to the size : MUST contain the size of the buffer before calling
* The function set it to the actual number of written bytes
* @param *abortCode Pointer to the abortcode. (0 = not available. Else : SDO abort code. (received if return SDO_ABORTED_RCV)
*
*
* @return
* - SDO_FINISHED // datas are available
* - SDO_ABORTED_RCV // Transfer failed (abort SDO received)
* - SDO_ABORTED_INTERNAL // Transfer failed (internal abort)
* - SDO_UPLOAD_IN_PROGRESS // Datas are not yet available
* - SDO_DOWNLOAD_IN_PROGRESS // Download is in progress
* - SDO_PROVIDED_BUFFER_TOO_SMALL //The value *size is not enough to store the received data
* \n\n
* example :
* @code
* UNS32 data;
* UNS8 size;
* readNetworkDict(0, 0x05, 0x1016, 1, 0) // get the data index 1016 subindex 1 of node 5
* while (getReadResultNetworkDict (0, 0x05, &data, &size) == SDO_UPLOAD_IN_PROGRESS);
* @endcode
*/
UNS8 getReadResultNetworkDict (CO_Data* d, UNS8 nodeId, void* data, UNS32 *size, UNS32 * abortCode);
/**
* @ingroup sdo
* @brief Use this function after calling writeNetworkDict function to get the result of the write.
* @details It is mandatory to call this function because it is releasing the line used for the transfer.
* @param *d Pointer to a CAN object data structure
* @param nodeId Node Id of the slave
* @param *abortCode Pointer to the abortcode
* - 0 = not available.
* - SDO abort code (received if return SDO_ABORTED_RCV)
*
* @return :
* - SDO_FINISHED // datas are available
* - SDO_ABORTED_RCV // Transfer failed (abort SDO received)
* - SDO_ABORTED_INTERNAL // Transfer failed (Internal abort)
* - SDO_DOWNLOAD_IN_PROGRESS // Datas are not yet available
* - SDO_UPLOAD_IN_PROGRESS // Upload in progress
* \n\n
* example :
* @code
* UNS32 data = 0x50;
* UNS8 size;
* UNS32 abortCode;
* writeNetworkDict(0, 0x05, 0x1016, 1, size, &data) // write the data index 1016 subindex 1 of node 5
* while (getWriteResultNetworkDict (0, 0x05, &abortCode) == SDO_DOWNLOAD_IN_PROGRESS);
* @endcode
*/
UNS8 getWriteResultNetworkDict (CO_Data* d, UNS8 nodeId, UNS32 * abortCode);
#endif