f2838x_cm_cia402_solution/objdef.c
Alex 9661838676 rev.(UML-1899): рабочий пример EtherCAT Slave на CM
Работает. Есть CiA402, OD из SSC Tool. Автономный со своим main(). Проверялся тестами на SOEM.
2024-02-02 12:33:48 +03:00

1744 lines
76 KiB
C

/*
* This source file is part of the EtherCAT Slave Stack Code licensed by Beckhoff Automation GmbH & Co KG, 33415 Verl, Germany.
* The corresponding license agreement applies. This hint shall not be removed.
* https://www.beckhoff.com/media/downloads/slave-stack-code/ethercat_ssc_license.pdf
*/
/**
\addtogroup CoE CAN Application Profile over EtherCAT
@{
*/
/**
\file objdef.c
\author EthercatSSC@beckhoff.com
\brief Implementation
This file contains the object dictionary access functions
\version 5.13
<br>Changes to version V5.12:<br>
V5.13 COE1: handling objects with 255 entries<br>
V5.13 COE4: update default entry name handling in case of 16Bit characters, add CoE Read/write indication functions<br>
V5.13 COE9: prevent compiler warning in get entry description if char is 8bit<br>
V5.13 TEST7: add entries with bit9-16 types<br>
<br>Changes to version V5.11:<br>
V5.12 COE10: update object entry string handling<br>
V5.12 COE3: update entry access right handling<br>
V5.12 COE6: handle get object length in case of an out of range subindex<br>
V5.12 COE7: in case of a padding entry SDO upload/download return Unsupported access<br>
V5.12 COE9: SDO download 0xF030.0 shall be 0 before writing entries 1..n<br>
V5.12 ECAT1: update SM Parameter measurement (based on the system time), enhancement for input only devices and no mailbox support, use only 16Bit pointer in process data length caluclation<br>
V5.12 ECAT5: update Sync error counter/flag handling,check enum memory alignment depending on the processor,in case of a polled timer disable ESC interrupts during DC_CheckWatchdog<br>
<br>Changes to version V5.10.1:<br>
V5.11 DIAG4: change parameter handling in DIAG_CreateNewMessage()<br>
V5.11 ECAT: <br>
V5.11 ECAT10: change PROTO handling to prevent compiler errors<br>
V5.11 ESM7: "add Sync define for 0x22 (""SYNCTYPE_SM2_SYNCHRON""), support value 0x22 for 0x1C33.1 (SM2 sync)"<br>
V5.11 OBJ1: OBJ_GetEntryOffset: return offset 0 for si0 (always offset 16 was returned before)<br>
V5.11 SDO1: "Obj_Read/Obj_Write: Check if entries > 8bit has even word offset (otherwise ""unsupported access"" is returned). To support these object a read/write callback function need to be used (see Application Note ET9300)"<br>
V5.11 SDO2: Obj_Read/Obj_Write: Handle arrays (string, array of byte, ...) with an odd word length (buffer shift was wrong). Only an entry <=8Bit is allowed after such an entry.<br>
V5.11 SDO3: handle not word aligned enums<br>
V5.11 SDO5: add missing swapping on SI0 write access<br>
V5.11 SDO6: OBJ_GetDesc ensure that the default string is used if no string was found<br>
V5.11 SDO7: add missing value swapping if memory values are bitwise modified on object read/write access<br>
V5.11 SDO9: "handle SDO access for entries which are not accessible (in case of SDO complete access), SDO access handle ""DEFTYPE_ARRAY_OF_INT"" , ""DEFTYPE_ARRAY_OF_SINT"" , ""DEFTYPE_ARRAY_OF_DINT"" , ""DEFTYPE_ARRAY_OF_UDINT"", SDO access handle : ""BYTE"" , ""WORD"" and ""DWORD"""<br>
V5.11 TEST2: add test 0x300C object (entry bitlength > 65535)<br>
V5.11 TEST8: create diag message on SDO write access to 0x3002<br>
<br>Changes to version V5.01:<br>
V5.10 COE2: Change return value of Get ObjectSize to UINT32<br>
Change object size to UINT32<br>
V5.10 ECAT11: Add define "USE_SINGLE_PDO_MAPPING_ENTRY_DESCR" (Only one entry description is required for all PDO mapping entries)<br>
V5.10 ECAT13: Update Synchronisation handling (FreeRun,SM Sync, Sync0, Sync1)<br>
Compare DC UINT configuration (by ESC Config data) vs. DC activation register settings<br>
Update 0x1C3x entries<br>
V5.10 ECAT3: Add new datatype handling (BITARRxx)<br>
Use read/write macro to access STRING entries<br>
V5.10 SDO1: Handle access to enums on odd memory addresses (only for MBX_16BIT_ACCESS)<br>
V5.10 SDO2: Check for termination char in every substring<br>
V5.10 SDO5: Check also for PDO mapping object if the subindex 0 was set to 0 before the entries will be changed.<br>
V5.10 SDO9: SDO complete write access update buffer offset calculation in case of SI0 is readonly<br>
V5.10 TEST2: Add 0x3004.14 (Access to this entry will always rejected with the code "cannot be acceesd because of local control")<br>
V5.10 TEST4: Add CoE test (0x2020.5) to return always max object data on complete access (not limited to value of SI0)<br>
<br>Changes to version V5.0:<br>
V5.01 COE2: Calculate the bit offset also for SI0 in case if an SDO download access.<br>
V5.01 SDO1: Update alignment entry handling.<br>
V5.01 SDO5: Update offset calculation in case of an not accessible entry<br>
V5.01 SDO7: Update object length calculation in case of an BitArray<br>
V5.01 TEST5: Add slave configuration object handling (0x8000, if test application is active)<br>
V5.01 TEST6: Add test to create dummy object dictionary.<br>
<br>Changes to version V4.40:<br>
V5.0 TEST1: Add test application.<br>
V5.0 COE3: Update OCTED_STRING and VISIBLE_STRING read/write.<br>
V5.0 COE5: Add BigEndian support for enum SDO read, handle complete access also for objects with align or not existing entries.<br>
V5.0 COE7: Support SDO Info entry name handling for 16Bit access<br>
V5.0 DIAG2: SDO Info request for diagnosis messages 0x10F3 SI5 or greater return always description of SI6.<br>
V5.0 COE2: Add plausibility check for PDO assign objects.<br>
V5.0 OBJ2: Support DWORD/WORD aligned object structures.<br>
V5.0 SDO7: Update SDO read/write for object(entries) less or equal 8Bit.<br>
<br>Changes to version V4.30:<br>
V4.40 DIAG1: Add diagnosis access functions<br>
V4.40 OBJ2: change counter variable to prevent deadlock caused by overrun (required if subindex0 is 255)<br>
V4.40 COE2: Prevent accessing empty object dictionary entry<br>
V4.40 COE3: Read whole object dictionary<br>
V4.40 COE1: Prototype of OBJ_GetObjectList() changed, set abort code if object dictionary is empty<br>
V4.30 OBJ 3: Object dictionary list handling<br>
V4.30 OBJ 2: fix SDO complete access bug<br>
V4.11 OBJ 1-3: OBJ_GetDesc() Now, subindex 0 instead of 0xFF is used to return the description of the whole object<br>
Subindex 0xFF could be used like a normal subindex.<br>
<br>Changes to version V4.08:<br>
V4.10 OBJ 1: calculate size of PdoObjectEntry Index 1 and not Index 0<br>
V4.10 OBJ 2: the pointer of the object dictionary will be get by a function (COE_GetObjectDictionary)<br>
<br>Changes to version V4.07:<br>
V4.08 OBJ 1: if subindex 0 is writable, the maximum subindex should be checked in an object specific function,<br>
because for the PDO mapping and PDO assign the object shall only be written if subindex 0 is 0.<br>
<br>Changes to version V4.04:<br>
V4.04 OBJ 1: The loop in OBJ_GetObjectList was one subindex too low<br>
<br>Changes to version V4.03:<br>
V4.04 SDO 1: The SDO interface was changed in that way that a SDO response<br>
could be sent by the application to a later time. In that case<br>
the functions OBJ_Read and OBJ_Write shall return the value<br>
ABORTIDX_WORKING. To send the SDO response the new function SDOS_SdoRes<br>
has to be called by the application. While waiting for the call<br>
of SDOS_SdoRes the SDO interface will answer to another SDO request<br>
with the error MBXERR_SERVICEINWORK in the mailbox protocol<br>
V4.04 OBJ 1: The loop in OBJ_GetNoOfObjects was one subindex too low<br>
<br>Changes to version V4.02:<br>
V4.03 OBJ 1: The object list was not returned correctly for the list types 2-5<br>
<br>Changes to version V3.20:<br>
V4.00 OBJ 1: The OBJ functions are modified for a more flexible definition of<br>
the object dictionary and to support bit types too<br>
V4.00 SDO 2: The object lists will be generated in the functions OBJ_GetNoOfObjects<br>
and OBJ_GetObjectList in objdef.c to decouple the SDO services from<br>
the implementation of the object dictionary<br>
V4.00 COEAPPL 2: The handling of backup parameters was included according to<br>
the EtherCAT Guidelines and Protocol Enhancements Specification
*/
#define OBJDEF 0x4000
#define OBJDEFMAX 0x0A
/*---------------------------------------------------------------------------------------
------
------ Includes
------
---------------------------------------------------------------------------------------*/
#include "ecat_def.h"
#include "ecatslv.h"
#include "coeappl.h"
#define _OBJDEF_ 1
#include "objdef.h"
#undef _OBJDEF_
/*remove definition of _OBJDEF_ (#ifdef is used in objdef.h)*/
#include "applInterface.h"
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 143 to 145 deleted*/
/*ET9300 Project Handler :(#if DIAGNOSIS_SUPPORTED) lines 147 to 149 deleted*/
extern OBJCONST TOBJECT OBJMEM *pSdoInfoObjEntry;
extern OBJCONST TSDOINFOENTRYDESC OBJMEM * OBJ_GetEntryDesc(OBJCONST TOBJECT OBJMEM * pObjEntry, UINT8 Subindex);
//---------------------------------------------------------------------------------------
/*---------------------------------------------------------------------------------------
------
------ Internal types and defines
------
---------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------
------
------ module internal function declarations
------
---------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------
------
------ Module internal variable definitions
------
---------------------------------------------------------------------------------------*/
const UINT16 cBitMask[16] = {0x0000,0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF};
/*---------------------------------------------------------------------------------------
------
------ Functions
------
---------------------------------------------------------------------------------------*/
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index Indicates the index of the dictionary object.
\return A handle to an object of the requested index or NULL if not found.
\brief The function looks in all objects of the dictionary after the indicated index
and returns a handle if found.
*////////////////////////////////////////////////////////////////////////////////////////
OBJCONST TOBJECT OBJMEM * OBJ_GetObjectHandle( UINT16 index )
{
OBJCONST TOBJECT OBJMEM * pObjEntry = (OBJCONST TOBJECT OBJMEM *) COE_GetObjectDictionary();
while (pObjEntry!= NULL)
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 201 to 203 deleted*/
{
if (pObjEntry->Index == index)
{
return pObjEntry;
}
pObjEntry = (TOBJECT OBJMEM *) pObjEntry->pNext;
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 212 to 214 deleted*/
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index Index of the requested object.
\param subindex Subindex of the requested object.
\param pObjEntry Handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\param bCompleteAccess Indicates if a complete read of all subindices of the
object shall be done or not
\return The size of the object entry in bytes (!).
\brief This function returns the size of the requested entry. If bCompleteaccess is set the size of the complete object is returned (the returned size is byte packed, gaps based on the used platform/compiler are not taken into account)
*////////////////////////////////////////////////////////////////////////////////////////
UINT32 OBJ_GetObjectLength( UINT16 index, UINT8 subindex, OBJCONST TOBJECT OBJMEM * pObjEntry, UINT8 bCompleteAccess)
{
/* get the information of ObjCode and MaxSubindex in local variables to support different types of microcontroller */
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
UINT8 maxSubindex = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_MAXSUBINDEXMASK) >> OBJFLAGS_MAXSUBINDEXSHIFT;
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 239 to 314 deleted*/
{
if ( objCode == OBJCODE_VAR )
{
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 318 to 326 deleted*/
return (BIT2BYTE(pObjEntry->pEntryDesc->BitLength));
}
else if ( subindex == 0 )
{
/* for single access subindex 0 is transmitted as UINT8 */
return 1;
}
else if((objCode == OBJCODE_ARR)
|| (IS_RX_PDO(pObjEntry->Index) || IS_TX_PDO(pObjEntry->Index))
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 340 to 343 deleted*/
)
{
return (BIT2BYTE(pObjEntry->pEntryDesc[1].BitLength));
}
else
{
/*ET9300 Project Handler :(#if DIAGNOSIS_SUPPORTED) lines 350 to 356 deleted*/
{
if (maxSubindex < subindex)
{
return 0;
}
else
{
return (BIT2BYTE(pObjEntry->pEntryDesc[subindex].BitLength));
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pStr Pointer to a string
\param Number Number to be included in the string
\brief The function copies the Number in the string pStr,
which shall be initialized with 000
*////////////////////////////////////////////////////////////////////////////////////////
void OBJ_CopyNumberToString(UCHAR MBXMEM *pStr, UINT8 Number)
{
UINT8 Modulo;
pStr[2] = '0';
pStr[0] += (Number / 100);
Modulo = Number % 100;
pStr[1] += (Modulo / 10);
pStr[2] += (Modulo % 10);
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param listType requested listType (0=all objects, 1=RxPDO mappable objects,
2=TxPDO mappable objects, 3=backup objects, 4=setting objects)
\return Number of objects of the requested list type
\brief The function counts the number of objects of the requested list type
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 OBJ_GetNoOfObjects(UINT8 listType)
{
/* the variable listFlags contains the mask used for the ObjAccess in the Entry-Desc
see the structure TSDOINFOENTRYDESC in sdoserv.h, listType = 0 indicates that
all objects has to be counted */
UINT16 listFlags = 0x0020 << listType;
/* set pObjEntry to the beginning of the object dictionary */
OBJCONST TOBJECT OBJMEM * pObjEntry = (OBJCONST TOBJECT OBJMEM *) COE_GetObjectDictionary();
UINT16 n = 0;
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 416 to 422 deleted*/
while (pObjEntry != NULL)
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 426 to 428 deleted*/
{
/* count the objects of the requested list type */
if ( pObjEntry->Index >= 0x1000 )
{
UINT8 t = listType;
if ( t )
{
UINT8 maxSubindex = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_MAXSUBINDEXMASK) >> OBJFLAGS_MAXSUBINDEXSHIFT;
UINT16 i = 0;
while ( t && i <= maxSubindex )
{
if ( OBJ_GetEntryDesc(pObjEntry,(UINT8) i)->ObjAccess & listFlags )
{
t = 0;
}
i++;
}
}
if ( !t )
{
/* object from listType found */
n++;
}
}
/* next object in object dictionary */
pObjEntry = (TOBJECT OBJMEM *) pObjEntry->pNext;
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 457 to 459 deleted*/
}
return n;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param listType Requested listType (0=all objects, 1=RxPDO mappable objects,
2=TxPDO mappable objects, 3=backup objects, 4=setting objects)
\param pIndex Pointer to the next Index of the object list to copied in the mailbox buffer,
has to adapted at the end of the function
\param size Size of the available mailbox buffer
\param pData Pointer to the mailbox buffer where (the part of) the object list requested listType (0=all objects, 1=RxPDO mappable objects,
\param pAbort Pointer to abortCode
\return Size of the available mailbox buffer which was not copied to
\brief The function copies (the part of) the object list in the mailbox buffer
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 OBJ_GetObjectList(UINT16 listType, UINT16 *pIndex, UINT16 size, UINT16 MBXMEM *pData,UINT8 *pAbort)
{
/* the variable listFlags contains the mask used for the ObjAccess in the Entry-Desc
see the structure TSDOINFOENTRYDESC in sdoserv.h, listType = 0 indicates that
all objects has to be counted */
UINT16 listFlags = 0x0020 << listType;
OBJCONST TOBJECT OBJMEM * pObjEntry;
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 488 to 500 deleted*/
if ( pIndex[0] == 0x1000 )
{
/* beginning of object list, set pObjEntry to the beginning of the object dictionary */
pObjEntry = (OBJCONST TOBJECT OBJMEM *) COE_GetObjectDictionary();
// set abort code if no object dictionary is available
if((pObjEntry == NULL) && (pAbort != NULL))
{
*pAbort = ABORTIDX_NO_OBJECT_DICTIONARY_IS_PRESENT;
}
}
else
{
/* next fragment, the next object to be handled was stored in pSdoInfoObjEntry */
pObjEntry = pSdoInfoObjEntry;
}
if ( pObjEntry != NULL )
{
while (pObjEntry != NULL && size > 1 )
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 522 to 524 deleted*/
{
/* get the next index of the requested object list if there is enough space in the mailbox buffer */
if ( pObjEntry->Index >= 0x1000 )
{
/* UINT8 was changed to UINT16 */
UINT16 t = listType;
if ( t )
{
UINT8 maxSubindex = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_MAXSUBINDEXMASK) >> OBJFLAGS_MAXSUBINDEXSHIFT;
/*ECATCHANGE_START(V5.13) COE1*/
UINT16 i = 0;
/*ECATCHANGE_END(V5.13) COE1*/
while ( t && i <= maxSubindex )
{
if ( OBJ_GetEntryDesc(pObjEntry, (UINT8)i)->ObjAccess & listFlags )
{
t = 0;
}
i++;
}
}
if ( !t )
{
/* store the index in the mailbox buffer */
*pData = SWAPWORD(pObjEntry->Index);
pData++;
size -= 2;
}
}
pObjEntry = (TOBJECT OBJMEM *) pObjEntry->pNext;
/*ET9300 Project Handler :(#if !STATIC_OBJECT_DIC #else) lines 557 to 559 deleted*/
}
}
/* return the next Index to be handled */
if(pObjEntry != NULL)
{
pIndex[0] = pObjEntry->Index;
}
else
{
/*last entry reached*/
pIndex[0] = 0xFFFF;
}
/* store object description pointer and index for next fragment */
pSdoInfoObjEntry = pObjEntry;
/* return the size of the available mailbox buffer which was not copied to */
return size;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index Indicates the index of the dictionary object.
\param subindex Indicates the subindex of the dictionary object.
Subindex 0xff returns the description of the whole object ( the name of
the object ).
Subindex 0x00 returns the description of the subindex 0 and so on.
\param pObjEntry Is a handle to the dictionary object ( for faster access ) or NULL.
\param pData Is the memory field for the description string or NULL ( if the size of
string is unknown ):
\return The size in bytes of the description string (without null termination byte ).
0 will be returned if a description for the indicated entry was not found.
\brief The function returns size and description string of the requested entry.
Its possible to define all description strings of one entry ( including the name
of the object ) in one structure: <br>
{ <br>
name_of_object with index, <br>
description_of_subindex0, <br>
. <br>
description_of_subindexN, <br>
0xFF <br>
}
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 OBJ_GetDesc( UINT16 index, UINT8 subindex, OBJCONST TOBJECT OBJMEM * pObjEntry, UINT16 MBXMEM * pData )
{
UINT16 strSize = 0;
OBJCONST UCHAR OBJMEM * pDesc = (OBJCONST UCHAR OBJMEM *) pObjEntry->pName;
/* get the information of ObjCode and MaxSubindex in local variables to support different types of microcontroller */
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
if ( (subindex == 0) || (objCode == OBJCODE_VAR) )
{
// Get object description length
strSize = (UINT16) OBJSTRLEN((OBJCONST CHAR OBJMEM *) pDesc);
// If there is a pointer given, copy data:
if ( pData )
{
OBJTOMBXSTRCPY( pData, pDesc, strSize );
}
}
else
{
if ( objCode == OBJCODE_REC )
{
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 632 to 653 deleted*/
{
// get pointer to description of subindex 1 :
// 16bit variable to avoid overflow if subindex 0xFF is read
UINT16 i = 1;
UINT16 tmpSubindex = subindex;
/*ET9300 Project Handler :(#if DIAGNOSIS_SUPPORTED) lines 660 to 666 deleted*/
{
OBJCONST UCHAR OBJMEM * pSubDesc = (OBJCONST UCHAR OBJMEM *) OBJGETNEXTSTR( pDesc );
while (( i <= tmpSubindex )
&&( pSubDesc[0] != 0xFF && pSubDesc[0] != 0xFE
/* ECATCHANGE_START(V5.13) COE9*/
/*ET9300 Project Handler :(#if MEMORY_UNIT_16BIT) lines 673 to 676 deleted*/
/* ECATCHANGE_END(V5.13) COE9*/
))
{
if ( i == tmpSubindex )
{
strSize = (UINT16) OBJSTRLEN((OBJCONST CHAR OBJMEM *) pSubDesc);
if ( pData && strSize )
{
OBJTOMBXSTRCPY( pData, pSubDesc, strSize );
}
break;
}
else
{
i++;
pSubDesc = (OBJCONST UCHAR OBJMEM *) OBJGETNEXTSTR( pSubDesc );
}
}
}
}
}
if ( strSize == 0 )
{
// no string found for subindex x -> name is Subindex x
strSize = 12;
if ( pData )
{
UCHAR OBJMEM TmpDescr[13];
/* ECATCHANGE_START(V5.13) COE4*/
MEMCPY(TmpDescr, aSubindexDesc, SIZEOF(TmpDescr));
/* ECATCHANGE_END(V5.13) COE4*/
OBJ_CopyNumberToString( &TmpDescr[9], subindex );
MBXSTRCPY( pData, TmpDescr, SIZEOF(TmpDescr) );
}
}
}
return strSize;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pObjEntry handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\param Subindex subindex of the requested object.
\return Pointer to the EntryDesc of the Subindex
\brief The function returns the Entry-Desc of a subindex to allow the application
to define the object dictionary independent of the sdoserv-files
*////////////////////////////////////////////////////////////////////////////////////////
OBJCONST TSDOINFOENTRYDESC OBJMEM * OBJ_GetEntryDesc(OBJCONST TOBJECT OBJMEM * pObjEntry, UINT8 Subindex)
{
OBJCONST TSDOINFOENTRYDESC OBJMEM *pEntry;
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
if ((objCode == OBJCODE_ARR)
|| (IS_RX_PDO(pObjEntry->Index) || IS_TX_PDO(pObjEntry->Index))
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 742 to 746 deleted*/
)
{
/* object is an array */
if ( Subindex == 0 )
{
/* subindex 0 has a description */
pEntry = &pObjEntry->pEntryDesc[0];
}
else
{
/* and all other elements have the same description */
pEntry = &pObjEntry->pEntryDesc[1];
}
}
else
{
/*ET9300 Project Handler :(#if DIAGNOSIS_SUPPORTED) lines 763 to 771 deleted*/
{
/* object is a variable or a record return the corresponding entry */
pEntry = &pObjEntry->pEntryDesc[Subindex];
}
}
return pEntry;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param pObjEntry handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\return Pointer to the ObjDesc of the Object
\brief The function returns the Obj-Desc of an object to allow the application
to define the object dictionary independent of the sdoserv-files
*////////////////////////////////////////////////////////////////////////////////////////
OBJCONST TSDOINFOOBJDESC OBJMEM * OBJ_GetObjDesc(OBJCONST TOBJECT OBJMEM * pObjEntry)
{
return &pObjEntry->ObjDesc;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param subindex subindex of the entry
\param pObjEntry handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\return bit offset of the entry in the variable
\brief This function calculates the bit offset of the entry in the object's variable
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 OBJ_GetEntryOffset(UINT8 subindex, OBJCONST TOBJECT OBJMEM * pObjEntry)
{
UINT16 i;
/* bitOffset will be initialized with the bit offset of subindex 1 */
UINT16 bitOffset = 0;
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
OBJCONST TSDOINFOENTRYDESC OBJMEM *pEntry;
if(subindex > 0)
{
/*subindex 1 has an offset of 16Bit (even if Si0 is only an UINT8) */
bitOffset +=16;
}
if (objCode == OBJCODE_VAR)
{
return 0;
}
for (i = 1; i <= subindex; i++)
{
/* get the entry description */
if ((objCode == OBJCODE_ARR)
|| (IS_RX_PDO(pObjEntry->Index) || IS_TX_PDO(pObjEntry->Index))
)
{
pEntry = &pObjEntry->pEntryDesc[1];
}
else
{
pEntry = &pObjEntry->pEntryDesc[i];
}
switch (pEntry->DataType)
{
case DEFTYPE_INTEGER16:
case DEFTYPE_UNSIGNED16:
case DEFTYPE_BITARR16:
case DEFTYPE_WORD:
case DEFTYPE_UNICODE_STRING:
case DEFTYPE_ARRAY_OF_INT :
#if OBJ_WORD_ALIGN || OBJ_DWORD_ALIGN
/* the 16-bit variables in the structure are word-aligned,
align the actual bitOffset to a word */
bitOffset = (bitOffset+15) & 0xFFF0;
#endif
if (i < subindex)
{
if((pEntry->DataType == DEFTYPE_UNICODE_STRING)
||(pEntry->DataType == DEFTYPE_ARRAY_OF_INT))
{
bitOffset += pEntry->BitLength;
}
else
{
bitOffset += 16;
}
}
break;
case DEFTYPE_UNSIGNED32:
case DEFTYPE_INTEGER32:
case DEFTYPE_REAL32:
case DEFTYPE_BITARR32:
case DEFTYPE_DWORD:
case DEFTYPE_ARRAY_OF_DINT :
case DEFTYPE_ARRAY_OF_UDINT:
#if OBJ_DWORD_ALIGN
/* the 32-bit variables in the structure are dword-aligned,
align the actual bitOffset to a dword */
bitOffset = (bitOffset+31) & 0xFFE0;
#elif OBJ_WORD_ALIGN
/* the 32-bit variables in the structure are word-aligned,
align the actual bitOffset to a word */
bitOffset = (bitOffset+15) & 0xFFF0;
#endif
if (i < subindex)
{
if((pEntry->DataType == DEFTYPE_ARRAY_OF_DINT)
||(pEntry->DataType == DEFTYPE_ARRAY_OF_UDINT))
{
bitOffset += pEntry->BitLength;
}
else
{
bitOffset += 32;
}
}
break;
case DEFTYPE_REAL64:
case DEFTYPE_INTEGER64:
case DEFTYPE_UNSIGNED64:
#if OBJ_DWORD_ALIGN
/* the 64-bit variables in the structure are dword-aligned,
align the actual bitOffset to a dword */
bitOffset = (bitOffset + 31) & 0xFFE0;
#elif OBJ_WORD_ALIGN
/* the 64-bit variables in the structure are word-aligned,
align the actual bitOffset to a word */
bitOffset = (bitOffset + 15) & 0xFFF0;
#endif
if (i < subindex)
{
bitOffset += 64;
}
break;
default:
/* align the actual bitOffset to a byte */
if (i < subindex)
{
bitOffset += pEntry->BitLength;
}
break;
}
}
return bitOffset;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index index of the SyncManager Parameter object
\param NewSyncType New value for the Sync Type (SubIndex 1)
\return result Result of the value validation
\brief Checks if the new Sync type value is valid
*////////////////////////////////////////////////////////////////////////////////////////
UINT8 CheckSyncTypeValue(UINT16 index, UINT16 NewSyncType)
{
switch (NewSyncType)
{
case SYNCTYPE_FREERUN:
return 0; //free run sync mode is always accepted
case SYNCTYPE_SM_SYNCHRON:
if ((index == 0x1C32)
&& (nPdOutputSize > 0)
&& ((sSyncManOutPar.u16SyncTypesSupported & SYNCTYPE_SYNCHRONSUPP) > 0))
{
/*SyncManager sync mode is supported and output process data is configured*/
return 0;
}
else
if ((index == 0x1C33)
&& ((sSyncManInPar.u16SyncTypesSupported & SYNCTYPE_SYNCHRONSUPP) > 0)
&& (nPdOutputSize == 0)
&& (nPdInputSize > 0))
{
/*SyncManager sync mode is supported and input only shall be configured*/
return 0;
}
break;
case SYNCTYPE_SM2_SYNCHRON:
if ((index == 0x1C33)
&& ((sSyncManInPar.u16SyncTypesSupported & SYNCTYPE_SYNCHRONSUPP) > 0)
&& (nPdOutputSize > 0))
{
/*SyncManager sync mode is supported and outputs are defined*/
return 0;
}
break;
case SYNCTYPE_DCSYNC0:
if ((index == 0x1C32) && ((sSyncManOutPar.u16SyncTypesSupported & SYNCTYPE_DCSYNC0SUPP) > 0))
{
return 0;
}
else
if ((index == 0x1C33) && ((sSyncManInPar.u16SyncTypesSupported & SYNCTYPE_DCSYNC0SUPP) > 0))
{
return 0;
}
break;
case SYNCTYPE_DCSYNC1:
if ((index == 0x1C32) && ((sSyncManOutPar.u16SyncTypesSupported & SYNCTYPE_DCSYNC1SUPP) > 0))
{
return 0;
}
else
if ((index == 0x1C33) && ((sSyncManInPar.u16SyncTypesSupported & SYNCTYPE_DCSYNC1SUPP) > 0))
{
return 0;
}
break;
} //switch
return ABORTIDX_VALUE_EXCEEDED;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index index of the requested object.
\param subindex subindex of the requested object.
\param objSize Size of the object, returned by the function OBJ_GetObjectLength
which was called before
\param pObjEntry handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\param pData Pointer to the buffer where the read data shall be copied to
\param bCompleteAccess Indicates if a complete read of all subindices of the
object shall be done or not
\return result of the read operation (0 (success) or an abort code (ABORTIDX_.... defined in
sdosrv.h))
\brief This function reads the requested object
*////////////////////////////////////////////////////////////////////////////////////////
UINT8 OBJ_Read( UINT16 index, UINT8 subindex, UINT32 objSize, OBJCONST TOBJECT OBJMEM * pObjEntry, UINT16 MBXMEM * pData, UINT8 bCompleteAccess )
{
UINT16 i = subindex;
/* get the information of ObjCode and MaxSubindex in local variables to support different types of microcontroller */
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
UINT16 maxSubindex = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_MAXSUBINDEXMASK) >> OBJFLAGS_MAXSUBINDEXSHIFT;
OBJCONST TSDOINFOENTRYDESC OBJMEM *pEntry;
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1053 to 1058 deleted*/
if ( objCode != OBJCODE_VAR && index >= 0x1000 )
{
/* if the object is an array or record we have to get the maxSubindex from the
actual value of subindex 0, which is stored as UINT16 at the beginning of the
object's variable */
maxSubindex = (*((UINT16 *) (pObjEntry->pVarPtr))) & 0x00FF;
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1067 to 1080 deleted*/
}
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1083 to 1097 deleted*/
if ( subindex > maxSubindex )
{
/* the maximum subindex is reached */
return ABORTIDX_SUBINDEX_NOT_EXISTING;
}
else
{
/* get the corresponding entry description */
pEntry = OBJ_GetEntryDesc(pObjEntry, (UINT8)i);
/*Check access only for non-align entries*/
if(pEntry->ObjAccess != 0x0)
{
/* check if we have read access (bits 0-2 (PREOP, SAFEOP, OP) of ObjAccess)
by comparing with the actual state (bits 1-3 (PREOP, SAFEOP, OP) of AL Status) */
if (0 == (((UINT8) ((pEntry->ObjAccess & ACCESS_READ)<<1)) & (nAlStatus & STATE_MASK)))
{
/* we don't have read access */
if ( (pEntry->ObjAccess & ACCESS_READ) == 0 )
{
/* it is a write only entry */
return ABORTIDX_WRITE_ONLY_ENTRY;
}
else
{
/* we don't have read access in this state */
return ABORTIDX_IN_THIS_STATE_DATA_CANNOT_BE_READ_OR_STORED;
}
}
}
else
{
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1133 to 1140 deleted*/
}
/* ECATCHANGE_START(V5.13) COE4*/
if (pAPPL_CoeReadInd != NULL)
{
pAPPL_CoeReadInd(index, subindex, bCompleteAccess);
}
/* ECATCHANGE_END(V5.13) COE4*/
if ( pObjEntry->Read != NULL )
{
/* Read function is defined, we call the object specific read function */
return pObjEntry->Read(index, subindex, objSize, pData, bCompleteAccess);
}
else if ( index < 0x1000 && subindex != 0 )
{
/* an ENUM description is read */
UINT16 size;
UINT16 MBXMEM *pVarPtr = (UINT16 MBXMEM *) pObjEntry->pVarPtr;
CHAR **p;
/* we get the corresponding entry description */
pEntry = OBJ_GetEntryDesc(pObjEntry, subindex);
size = BIT2BYTE(pEntry->BitLength);
p = (CHAR **) pVarPtr;
pVarPtr = (UINT16 MBXMEM *)p[subindex-1];
/*ECATCHANGE_START(V5.13) */
/*ET9300 Project Handler :(#if MBX_16BIT_ACCESS && !MEMORY_UNIT_16BIT) lines 1170 to 1200 deleted*/
{
// Get enum value (first 32Bit)
/*ECATCHANGE_START(V5.13) */
/*ET9300 Project Handler :(#if MEMORY_UNIT_16BIT) lines 1204 to 1210 deleted*/
/*ET9300 Project Handler :(#if (BIG_ENDIAN_16BIT || BIG_ENDIAN_FORMAT)) lines 1212 to 1215 deleted*/
pData[0] = pVarPtr[0];
pData[1] = pVarPtr[1];
pData += 2;
pVarPtr += 2;
/*ECATCHANGE_END(V5.13) */
// Get enum description
OBJTOMBXSTRCPY(pData,pVarPtr,size-4);
}
}
else
{
UINT8 bRead = 0x0;
UINT8 result = 0;
/* a variable object is read */
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1235 to 1237 deleted*/
{
/* if only a single entry is requested, this loop will only be done once */
UINT16 MBXMEM *pVarPtr = (UINT16 MBXMEM *) pObjEntry->pVarPtr;
UINT16 bitOffset = 0;
if (i == 0)
{
/* subindex 0 is requested, the entry's data is at the beginning of the object's variable */
}
else if ( index >= 0x1000 )
{
/* subindex 1-n of an variable object is requested, we get the offset of the variable here */
bitOffset = OBJ_GetEntryOffset((UINT8)i, pObjEntry);
}
/* we increment the variable pointer to the corresponding word address */
pVarPtr += (bitOffset >> 4);
/* get the corresponding entry description */
pEntry = OBJ_GetEntryDesc(pObjEntry, (UINT8)i);
if (0 != (((UINT8) ((pEntry->ObjAccess & ACCESS_READ)<<1)) & (nAlStatus & STATE_MASK)) )
{
if ( i == subindex /* requested entry */
|| (bCompleteAccess && i >= subindex) ) /* complete access and entry should be read */
{
UINT16 bitMask;
/* we have to copy the entry */
if ( i == 0 && objCode != OBJCODE_VAR )
{
/* we read subindex 0 of an array or record */
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1270 to 1276 deleted*/
{
pData[0] = SWAPWORD((UINT16)maxSubindex);
}
/* we increment the destination pointer by 2 because the subindex 0 will be
transmitted as UINT16 for a complete access */
pData++;
}
else
{
UINT16 dataType = pEntry->DataType;
if (pEntry->DataType >= 0x700)
{
/* the ENUM data types are defined from index 0x700 in this example
convert in standard data type for the read access */
if ( pEntry->BitLength <= 8 )
{
dataType = DEFTYPE_BIT1-1+pEntry->BitLength;
}
else if ( pEntry->BitLength == 16 )
{
dataType = DEFTYPE_UNSIGNED16;
}
else if ( pEntry->BitLength == 32 )
{
dataType = DEFTYPE_UNSIGNED32;
}
}
switch (dataType)
{
case DEFTYPE_NULL:
if(bCompleteAccess)
{
/*Handle alignment entry*/
if (((pEntry->BitLength & 0xF) > 0)
&& (((bitOffset + pEntry->BitLength) & 0x0F) == 0 ))
{
/* we have reached the UINT16 border */
pData++;
}
/*increment WORD offset*/
pData += ((pEntry->BitLength & 0xF0) >> 4);
}
else
{
return ABORTIDX_DATA_CANNOT_BE_READ_OR_STORED;
}
break;
case DEFTYPE_BOOLEAN:
case DEFTYPE_BIT1:
case DEFTYPE_BIT2:
case DEFTYPE_BIT3:
case DEFTYPE_BIT4:
case DEFTYPE_BIT5:
case DEFTYPE_BIT6:
case DEFTYPE_BIT7:
case DEFTYPE_BIT8:
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1337 to 1348 deleted*/
case DEFTYPE_BITARR8:
/* in this example the objects are defined in that way,
that the bit types are always inside a 16-bit field,
and they shall not overlap a byte border*/
case DEFTYPE_INTEGER8:
case DEFTYPE_UNSIGNED8:
case DEFTYPE_BYTE :
{
/* depending on the bitOffset we have to copy the Hi or the Lo-Byte */
UINT16 TmpValue = 0x0000;
bitMask = cBitMask[pEntry->BitLength] << (bitOffset & 0x0F);
/*Swap object data (if required); all masks and offsets are defined for little endian format*/
TmpValue = SWAPWORD(pVarPtr[0]);
/*Clear pData if the first bits within the WORD memory will be copied*/
if ((bitOffset & 0x0F) == 0)
{
pData[0] = 0;
}
pData[0] = SWAPWORD(pData[0]);
if (bCompleteAccess)
{
/*shifting is not required for Complete access because the bits are set to the correct offset by the master*/
pData[0] |= TmpValue & bitMask;
}
else
{
/*Shift Bits to the beginning of the mailbox memory*/
pData[0] |= ((TmpValue & bitMask) >> (bitOffset & 0x0F));
}
pData[0] = SWAPWORD(pData[0]);
if ( ((bitOffset + pEntry->BitLength) & 0x0F) == 0 )
{
/* we have reached the UINT16 border */
pData++;
}
}
break;
case DEFTYPE_INTEGER16:
case DEFTYPE_UNSIGNED16:
case DEFTYPE_BITARR16:
case DEFTYPE_WORD:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that the 16 bit type are always starting at an exact WORD offset */
pData[0] = SWAPWORD(pVarPtr[0]);
pData++;
break;
case DEFTYPE_UNSIGNED32:
case DEFTYPE_INTEGER32:
case DEFTYPE_REAL32:
case DEFTYPE_BITARR32:
case DEFTYPE_DWORD:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that the 32 bit type are always starting at an exact WORD offset */
/*ET9300 Project Handler :(#if BIG_ENDIAN_16BIT || BIG_ENDIAN_FORMAT) lines 1422 to 1425 deleted*/
pData[0] = pVarPtr[0];
pData[1] = pVarPtr[1];
pData += 2;
break;
case DEFTYPE_REAL64:
case DEFTYPE_INTEGER64:
case DEFTYPE_UNSIGNED64:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that the 64 bit type are always starting at an exact WORD offset */
/*ET9300 Project Handler :(#if BIG_ENDIAN_16BIT || BIG_ENDIAN_FORMAT) lines 1442 to 1447 deleted*/
pData[0] = pVarPtr[0];
pData[1] = pVarPtr[1];
pData[2] = pVarPtr[2];
pData[3] = pVarPtr[3];
pData += 4;
break;
case DEFTYPE_OCTETSTRING:
case DEFTYPE_UNICODE_STRING:
case DEFTYPE_ARRAY_OF_INT :
case DEFTYPE_ARRAY_OF_SINT :
case DEFTYPE_ARRAY_OF_DINT :
case DEFTYPE_ARRAY_OF_UDINT:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
OBJTOMBXMEMCPY(pData, pVarPtr, BIT2BYTE(pEntry->BitLength));
pData += BIT2WORD((pEntry->BitLength & ~0xF));
if((pEntry->BitLength & 0xF) != 0)
{
/*current entry has an odd word length => clear last byte of next word*/
*pData &= 0xFF;
}
break;
case DEFTYPE_VISIBLESTRING:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that these types are always starting at an even WORD offset */
OBJTOMBXSTRCPY(pData, pVarPtr, BIT2BYTE(pEntry->BitLength));
pData += BIT2WORD((pEntry->BitLength & ~0xF));
if((pEntry->BitLength & 0xF) != 0)
{
/*current entry has an odd word length => clear last byte of next word*/
*pData &= 0xFF;
}
break;
default:
/* other data types are not supported from this example */
return ABORTIDX_DATA_CANNOT_BE_READ_OR_STORED;
} //switch (deftype)
bRead = 1;
}
}
}
else
{
/*No access to current object entry => shift pData if required*/
UINT8 cnt = 0;
/*If this entry is the first in the 16Bit block clear the memory*/
if ((bitOffset & 0x0F) == 0)
{
*pData = 0;
}
/*Handle Bit/Byte Offset*/
if (((pEntry->BitLength & 0xF) > 0)
&& (((bitOffset + pEntry->BitLength) & 0x0F) == 0 ))
{
/* we have reached the UINT16 border */
pData++;
/*Clear new buffer*/
*pData = 0;
}
/*increment WORD offset*/
for(cnt = 0; cnt <((pEntry->BitLength & 0xF0) >> 4); cnt++)
{
/*current 16Bit are skipped => clear current buffer */
pData++;
/*Clear new buffer*/
*pData = 0;
}
/* we don't have read access */
if ( (pEntry->ObjAccess & ACCESS_READ) == 0 )
{
/* it is a write only entry */
result = ABORTIDX_WRITE_ONLY_ENTRY;
}
else
{
/* we don't have read access in this state */
result = ABORTIDX_IN_THIS_STATE_DATA_CANNOT_BE_READ_OR_STORED;
}
}
}
if(bRead == 0)
{
return result;
}
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\param index index of the requested object.
\param subindex subindex of the requested object.
\param dataSize received data size of the SDO Download
\param pObjEntry handle to the dictionary object returned by
OBJ_GetObjectHandle which was called before
\param pData Pointer to the buffer where the written data can be copied from
\param bCompleteAccess Indicates if a complete write of all subindices of the
object shall be done or not
\return result of the write operation (0 (success) or an abort code (ABORTIDX_.... defined in
sdoserv.h))
\brief This function writes the requested object
*////////////////////////////////////////////////////////////////////////////////////////
UINT8 OBJ_Write( UINT16 index, UINT8 subindex, UINT32 dataSize, OBJCONST TOBJECT OBJMEM * pObjEntry, UINT16 MBXMEM * pData, UINT8 bCompleteAccess )
{
UINT16 i = subindex;
/* get the information of ObjCode and MaxSubindex in local variables to support different types of microcontroller */
UINT8 objCode = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_OBJCODEMASK) >> OBJFLAGS_OBJCODESHIFT;
UINT16 maxSubindex = 0;
UINT16 maxConfiguredSubindex = (pObjEntry->ObjDesc.ObjFlags & OBJFLAGS_MAXSUBINDEXMASK) >> OBJFLAGS_MAXSUBINDEXSHIFT; //required to check if value for Subindex0 is valid
OBJCONST TSDOINFOENTRYDESC OBJMEM *pEntry;
BOOL bClearSubindex0Required = FALSE;
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1592 to 1597 deleted*/
/* if subindex 0 is writable, the maximum subindex should be checked in an object specific function,
because for the PDO mapping and PDO assign the object shall only be written if subindex 0 is 0. */
if ( objCode != OBJCODE_VAR )
{
/* if the object is an array or record we have to get the maxSubindex from the
actual value of subindex 0, which is stored as UINT16 at the beginning of the
object's variable */
maxSubindex = (UINT8) ((UINT16 MBXMEM *) (pObjEntry->pVarPtr))[0];
/*If the subindex0 of a PDO assign or PDO mapping object is 0 the maximum subindex is specified by the object description*/
if(maxSubindex == 0 && (IS_PDO_ASSIGN(index) || IS_RX_PDO(index) || IS_TX_PDO(index) || (index == 0xF030)))
{
maxSubindex = maxConfiguredSubindex;
}
}
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1616 to 1636 deleted*/
if (subindex > maxSubindex)
{
/* the maximum subindex is reached */
return ABORTIDX_SUBINDEX_NOT_EXISTING;
}
else
{
/* we check the write access for single accesses here, a complete write access
is allowed if at least one entry is writable (in this case the values for the
read only entries shall be ignored) */
/* we get the corresponding entry description */
pEntry = OBJ_GetEntryDesc(pObjEntry, subindex);
/* check if we have write access (bits 3-5 (PREOP, SAFEOP, OP) of ObjAccess)
by comparing with the actual state (bits 1-3 (PREOP, SAFEOP, OP) of AL Status) */
if (0 == (((UINT8)((pEntry->ObjAccess & ACCESS_WRITE) >> 2)) & (nAlStatus & STATE_MASK) ))
{
/* we don't have write access */
if ( (pEntry->ObjAccess & ACCESS_WRITE) == 0 )
{
if (pEntry->ObjAccess == 0)
{
return ABORTIDX_UNSUPPORTED_ACCESS;
}
else
{
/* it is a read only entry */
return ABORTIDX_READ_ONLY_ENTRY;
}
}
else
{
/* we don't have write access in this state */
return ABORTIDX_IN_THIS_STATE_DATA_CANNOT_BE_READ_OR_STORED;
}
}
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1674 to 1681 deleted*/
}
/* Subindex 0 shall be set to zero if a single PDO / PDO assign entry is written
or a complete access without subindex0 is requested */
if((subindex > 0) &&
(IS_PDO_ASSIGN(index) || IS_RX_PDO(index)|| IS_TX_PDO(index) || (index == 0xF030))
)
{
/*Check if Subindex0 was cleared before*/
UINT16 Subindex0 = (*(UINT16 *)pObjEntry->pVarPtr) & 0x00FF;
if(Subindex0 != 0x00)
{
bClearSubindex0Required = TRUE;
}
}
if ( pObjEntry->Write != NULL )
{
/* Write function is defined, we call the object specific write function */
/* ECATCHANGE_START(V5.13) COE4*/
UINT8 result = 0;
result = pObjEntry->Write(index, subindex, dataSize, pData, bCompleteAccess);
if ((result == 0) && (pAPPL_CoeWriteInd != NULL))
{
pAPPL_CoeWriteInd(index, subindex, bCompleteAccess);
}
return result;
/* ECATCHANGE_END(V5.13) COE4*/
}
else
{
UINT8 bWritten = 0;
UINT8 result = ABORTIDX_READ_ONLY_ENTRY;
if (dataSize == 0)
{
return 0; //no error
}
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1725 to 1731 deleted*/
/* we use the standard write function */
/*ET9300 Project Handler :(#if COMPLETE_ACCESS_SUPPORTED) lines 1733 to 1735 deleted*/
{
/* if only a single entry is requested, this loop will only be done once */
UINT16 MBXMEM *pVarPtr = (UINT16 MBXMEM *) pObjEntry->pVarPtr;
UINT16 bitOffset = 0;
/* we get the corresponding entry description */
pEntry = OBJ_GetEntryDesc(pObjEntry,(UINT8) i);
/*Get the bitOffset before check the access rights to calculate pData offset*/
bitOffset = OBJ_GetEntryOffset((UINT8)i, pObjEntry);
/* we check if we have write access (bits 3-5 (PREOP, SAFEOP, OP) of ObjAccess)
by comparing with the actual state (bits 1-3 (PREOP, SAFEOP, OP) of AL Status) */
if (0 != (((UINT8)((pEntry->ObjAccess & ACCESS_WRITE) >> 2)) & (nAlStatus & STATE_MASK) ))
{
/* we have write access for this entry */
if (i != 0)
{
/* we increment the variable pointer to the corresponding word address */
pVarPtr += (bitOffset >> 4);
}
if ( i == subindex /* requested entry */
|| (bCompleteAccess && i >= subindex) ) /* complete access and entry should be read */
{
UINT16 bitMask;
/* we have to copy the entry */
if (i == 0 && objCode != OBJCODE_VAR)
{
/*check if the value for subindex0 is valid */
UINT8 NewSubindex0 = (UINT8) SWAPWORD(pData[0]);
if(maxConfiguredSubindex < NewSubindex0)
{
return ABORTIDX_VALUE_TOO_GREAT;
}
/* subindex 0 of an array or record shall be written */
pVarPtr[0] = SWAPWORD(pData[0]);
/* we increment the destination pointer by 2 because the subindex 0 will be
transmitted as UINT16 for a complete access */
pData++;
}
else
{
UINT16 dataType = pEntry->DataType;
if (pEntry->DataType >= 0x700)
{
/* the ENUM data types are defined from index 0x700 in this example
convert in standard data type for the write access */
if ( pEntry->BitLength <= 8 )
{
dataType = DEFTYPE_BIT1-1+pEntry->BitLength;
}
else if ( pEntry->BitLength == 16 )
{
dataType = DEFTYPE_UNSIGNED16;
}
else if ( pEntry->BitLength == 32 )
{
dataType = DEFTYPE_UNSIGNED32;
}
}
switch (dataType)
{
case DEFTYPE_NULL:
if(bCompleteAccess)
{
/*Handle alignment entry*/
if (((pEntry->BitLength & 0xF) > 0)
&& (((bitOffset + pEntry->BitLength) & 0x0F) == 0 ))
{
/* we have reached the UINT16 border */
pData++;
}
/*increment WORD offset*/
pData += ((pEntry->BitLength & 0xF0) >> 4);
}
else
{
return ABORTIDX_DATA_CANNOT_BE_READ_OR_STORED;
}
break;
case DEFTYPE_BOOLEAN:
case DEFTYPE_BIT1:
case DEFTYPE_BIT2:
case DEFTYPE_BIT3:
case DEFTYPE_BIT4:
case DEFTYPE_BIT5:
case DEFTYPE_BIT6:
case DEFTYPE_BIT7:
case DEFTYPE_BIT8:
/*ET9300 Project Handler :(#if TEST_APPLICATION) lines 1832 to 1843 deleted*/
case DEFTYPE_BITARR8:
/* in this example the objects are defined in that way,
that the bit types are always inside a 16-bit field,
and shall not overlap a byte border*/
case DEFTYPE_INTEGER8:
case DEFTYPE_UNSIGNED8:
case DEFTYPE_BYTE :
{
/* depending on the bitOffset we have to copy the Hi or the Lo-Byte */
UINT16 TmpValue = 0x0000;
bitMask = cBitMask[pEntry->BitLength] << (bitOffset & 0x0F);
/*Swap object data (if required); all masks and offsets are defined for little endian format*/
TmpValue = SWAPWORD(pVarPtr[0]);
/*Clear corresponding bits*/
TmpValue &= ~bitMask;
if (bCompleteAccess)
{
/*shifting is not required for Complete access because the bits are set to the correct offset by the master*/
TmpValue |= (SWAPWORD(pData[0]) & bitMask);
}
else
{
if((SWAPWORD(pData[0]) & ~cBitMask[pEntry->BitLength]))
{
/*written value exceed entry range*/
return ABORTIDX_VALUE_EXCEEDED;
}
else
{
/*Shift Bits to corresponding offset within the object memory*/
TmpValue |= ((SWAPWORD(pData[0]) & cBitMask[pEntry->BitLength]) << (bitOffset & 0x0F));
}
}
/*Swap written data to big endian format (if required)*/
pVarPtr[0] = SWAPWORD(TmpValue);
if ( ((bitOffset+pEntry->BitLength) & 0x0F) == 0 )
{
/* we have reached the UINT16 border */
pData++;
}
}
break;
case DEFTYPE_INTEGER16:
case DEFTYPE_UNSIGNED16:
case DEFTYPE_BITARR16:
case DEFTYPE_WORD:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
{
/* in this example the objects are defined in that way,
that the 16 bit type are always starting at an exact WORD offset */
UINT16 u16NewData = SWAPWORD(pData[0]);
if(bClearSubindex0Required && (pVarPtr[0] != u16NewData))
{
/* try to write new data when subindex0 shall be reset*/
return ABORTIDX_ENTRY_CANT_BE_WRITTEN_SI0_NOT_0;
}
/*check value if a new PDO assign entry should be written*/
if(IS_PDO_ASSIGN(index)) //PDO assign
{
if (!IS_RX_PDO(u16NewData) && !IS_TX_PDO(u16NewData) && (u16NewData != 0)) //check if the new assign entry value is valid
{
return ABORTIDX_VALUE_EXCEEDED;
}
}
if(index == 0x1C32 || index == 0x1C33)
{
if (i == 1) /* "Synchronisation type" written */
{
/* The Synchronisation type (0x1C3x.1) was written by the user => the Sync type will not be calculated based on the register settings (if they don't match an error will be returned P_2_S)*/
if (pVarPtr[0] != u16NewData)
{
result = CheckSyncTypeValue(index, u16NewData);
if (result != 0)
{
return result;
}
}
/* The user may force to current Sync Mode for that reason the flag has also to be set if the same value was written */
bSyncSetByUser = TRUE;
}
if (i == 8) /* "Get Cycle Time" written*/
{
sSyncManOutPar.u32CalcAndCopyTime = (PD_OUTPUT_CALC_AND_COPY_TIME);
sSyncManOutPar.u32MinCycleTime = (MIN_PD_CYCLE_TIME);
sSyncManOutPar.u32CycleTime = 0;
sSyncManInPar.u32CalcAndCopyTime = (PD_INPUT_CALC_AND_COPY_TIME);
sSyncManInPar.u32MinCycleTime = (MIN_PD_CYCLE_TIME);
sSyncManInPar.u32CycleTime = 0;
if ((u16NewData & 0x2) == 0x2)
{
/* reset the error counters*/
sSyncManOutPar.u16CycleExceededCounter = 0;
sSyncManOutPar.u16SmEventMissedCounter = 0;
sSyncManOutPar.u8SyncError = 0;
sSyncManInPar.u16CycleExceededCounter = 0;
sSyncManInPar.u16SmEventMissedCounter = 0;
sSyncManInPar.u8SyncError = 0;
}
} /* Subindex 8 written*/
}
pVarPtr[0] = u16NewData;
pData++;
}
break;
case DEFTYPE_UNSIGNED32:
case DEFTYPE_INTEGER32:
case DEFTYPE_REAL32:
case DEFTYPE_BITARR32:
case DEFTYPE_DWORD:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
{
/* in this example the objects are defined in that way,
that the 32 bit type are always starting at an exact WORD offset */
/*ET9300 Project Handler :(#if BIG_ENDIAN_16BIT || BIG_ENDIAN_FORMAT) lines 1992 to 2003 deleted*/
if(bClearSubindex0Required &&
((pVarPtr[0] != pData[0])
|| (pVarPtr[1] != pData[1])))
{
/* try to write new data when subindex0 shall be reset*/
return ABORTIDX_ENTRY_CANT_BE_WRITTEN_SI0_NOT_0;
}
pVarPtr[0] = pData[0];
pVarPtr[1] = pData[1];
pData += 2;
}
/*ET9300 Project Handler :(#if TEST_APPLICATION && DIAGNOSIS_SUPPORTED) lines 2017 to 2028 deleted*/
break;
case DEFTYPE_REAL64:
case DEFTYPE_INTEGER64:
case DEFTYPE_UNSIGNED64:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that the 64 bit type are always starting at an exact WORD offset */
/*ET9300 Project Handler :(#if BIG_ENDIAN_16BIT || BIG_ENDIAN_FORMAT) lines 2040 to 2045 deleted*/
pVarPtr[0] = pData[0];
pVarPtr[1] = pData[1];
pVarPtr[2] = pData[2];
pVarPtr[3] = pData[3];
pData += 4;
break;
case DEFTYPE_VISIBLESTRING:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
OBJTOMBXSTRCPY(pVarPtr, pData, BIT2BYTE(pEntry->BitLength));
pData += BIT2WORD((pEntry->BitLength)& ~0xF);
break;
case DEFTYPE_OCTETSTRING:
case DEFTYPE_UNICODE_STRING:
case DEFTYPE_ARRAY_OF_INT :
case DEFTYPE_ARRAY_OF_SINT :
case DEFTYPE_ARRAY_OF_DINT :
case DEFTYPE_ARRAY_OF_UDINT:
if(bitOffset & 0xF)
{
/* return an error in case of an odd word offset (to support 16bit data type on odd word addresses an object specific access function need to be implemented and register in the object dictionary, see SSC Application Note)*/
return ABORTIDX_UNSUPPORTED_ACCESS;
}
/* in this example the objects are defined in that way,
that the other types are always starting at an even byte offset */
OBJTOMBXMEMCPY(pVarPtr, pData, BIT2BYTE(pEntry->BitLength));
pData += BIT2WORD((pEntry->BitLength) & ~0xF);
break;
default:
/* other data types are not supported from this example */
return ABORTIDX_DATA_CANNOT_BE_READ_OR_STORED;
}
}
/* set flag */
bWritten = 1;
/*ET9300 Project Handler :(#if STORE_BACKUP_PARAMETER_IMMEDIATELY && BACKUP_PARAMETER_SUPPORTED) lines 2091 to 2098 deleted*/
}
}
else
{
if(i == 0)
{
/* For SubIndex0 16Bit are reserved even if the BitLength is 8 */
pData++;
}
else
{
/*Handle Bit/Byte Offset*/
if (((pEntry->BitLength & 0xF) > 0)
&& (((bitOffset + pEntry->BitLength) & 0x0F) == 0 ))
{
/* we have reached the UINT16 border */
pData++;
}
/*increment WORD offset*/
pData += ((pEntry->BitLength & 0xFFF0) >> 4);
}
/*If no other entry was written this result will be returned*/
result = ABORTIDX_DATA_CANNOT_BE_READ_OR_STORED;
}
}
if (bWritten == 0)
{
/* we didn't write anything, so we have to return the stored error code */
return result;
}
}
/* ECATCHANGE_START(V5.13) COE4*/
if (pAPPL_CoeWriteInd != NULL)
{
pAPPL_CoeWriteInd(index, subindex, bCompleteAccess);
}
/* ECATCHANGE_END(V5.13) COE4*/
return 0;
}
/** @} */