include/sdo.h
author Robert Lehmann <robert.lehmann@sitec-systems.de>
Tue, 28 Jul 2015 16:36:55 +0200
changeset 793 72e9e1064432
parent 694 8dd1e58b3815
child 801 32d146b64a35
permissions -rw-r--r--
timers_unix: Fix termination problem of WaitReceiveTaskEnd

The function pthread_kill sends the Signal thread and to the own process.
If you use this construct than the application which calls uses the
canfestival api will terminate at the call of canClose. To avoid that
use pthread_cancel instead of pthread_kill. To use the pthread_cancel call
you need to set the cancel ability in the thread function. That means
you need to call pthread_setcancelstate and pthread_setcanceltype.
For the termination of the thread at any time it is important to set the
cancel type to PTHREAD_CANCEL_ASYNCHRONOUS.
/*
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