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