ECS Custom Object Enum
1 Example project
Use the ECS CustomOD Example from our Knowledge Base
KB → Software → LFW Host Examples → EtherCAT Slave
For netX90:
2 ECS Sources
The ECS Sources in the ECS CustomOD Example are in the folder:
netXStudio_ECSV5_CustomOD_V3.0.0.1\netX 90 - EtherCAT Slave - CustomOD V3.0.0.1\Components\cifXApplicationDemoECS\Sources
3 ECS Sourcecode changes
go to AppECS_DemoObjectDictionary.h and add the array g_tDatatypeObjects for the new objects 0x800.
#define INDEX_OF_MY_ENUM 0x0800 typedef struct{ /* As described in ETG1000.6 V1.0.3 Table 65 */ uint32_t ulIntegerValue; unsigned char szVisibleString[20]; /* assumption: string has 19 letters + zero*/ }ENUM_ELEMENT_T; #define FIRST_ENUM_VALUE (0) #define SECOND_ENUM_VALUE (1) static const ENUM_ELEMENT_T s_EnumElements[] = { { FIRST_ENUM_VALUE, "EnumElement0" }, { SECOND_ENUM_VALUE, "EnumElement1" }, }; SUBOBJECT_DESCRIPTION_T g_tSiObj_0800[] = { { .bSubIndex = 1, .bIndicationFlags = 0, .usAccessRights = ECAT_OD_READ_ALL, .usDatatype = ECAT_OD_DTYPE_OCTET_STRING, .ulMaxFieldUnits = sizeof(s_EnumElements[0]), .pszName = "Enum1", .ulInitialValueLength = sizeof(s_EnumElements[0]), .pvInitialValue = &s_EnumElements[0] }, { .bSubIndex = 2, .bIndicationFlags = 0, .usAccessRights = ECAT_OD_READ_ALL, .usDatatype = ECAT_OD_DTYPE_OCTET_STRING, .ulMaxFieldUnits = sizeof(s_EnumElements[1]), .pszName = "Enum2", .ulInitialValueLength = sizeof(s_EnumElements[1]), .pvInitialValue = &s_EnumElements[1] }, }; static const uint8_t s_b0800_NumElements = 2; #define ODV3_ACCESS_FLAGS_IS_DATATYPE_AREA 0x0100 OBJECT_DESCRIPTION_T g_tDatatypeObjects[] = { { .usIndex = INDEX_OF_MY_ENUM, .bMaxNumOfSubObjs = ARRCNT(g_tSiObj_0800), .ulMaxFieldUnits = 1, .bObjectCode = ODV3_OBJCODE_RECORD, .usAccessFlags = ODV3_ACCESS_FLAGS_IS_DATATYPE_AREA | ODV3_ACCESS_FLAGS_CREATE_SUBINDEX_0, .bIndicationFlags = 0, .usDatatype = ECAT_OD_DTYPE_ENUM, .usAccessRights = ECAT_OD_READ_ALL, .pszName = "MyEnum", .ptSi00 = &g_tSiObj_0800[0], .ptSiBreak = &g_tSiObj_0800[ ARRCNT(g_tSiObj_0800)], .pvInitialValue = &s_b0800_NumElements, .ulInitialValueLength = sizeof(s_b0800_NumElements), }, }; SUBOBJECT_DESCRIPTION_T g_tSiObj_4000[] = { { ... } { .bSubIndex = 4, .bIndicationFlags = 0, .usAccessRights = ECAT_OD_ACCESS_ALL, .usDatatype = INDEX_OF_MY_ENUM, .ulMaxFieldUnits = 1,//sizeof(s_EnumElements[0].ulIntegerValue), .pszName = "Enum Value1", .ulInitialValueLength = sizeof(s_EnumElements[0].ulIntegerValue), .pvInitialValue = &s_EnumElements[0].ulIntegerValue, }, { .bSubIndex = 5, .bIndicationFlags = 0, .usAccessRights = ECAT_OD_ACCESS_ALL, .usDatatype = INDEX_OF_MY_ENUM, .ulMaxFieldUnits = 1,//sizeof(s_EnumElements[1].ulIntegerValue), .pszName = "Enum Value2", .ulInitialValueLength = sizeof(s_EnumElements[1].ulIntegerValue), .pvInitialValue = &s_EnumElements[1].ulIntegerValue, }, };
and it is necessary to change and add functions in the file AppECS_DemoApplicationFunctions.c
CUSTOM_OD_T g_datatype = { .ptCurrObj = &g_tDatatypeObjects[0], .ptBreakObj = &g_tDatatypeObjects[ ARRCNT(g_tDatatypeObjects) ], /* pointer to one after last object which is taken as break condition in a loop */ .ptCurrSubObj = 0, }; static uint32_t AppECS_CreateDatatypeReq(CIFX_PACKET* ptPkt ) { uint32_t ulRet = CIFX_NO_ERROR; ODV3_CREATE_DATATYPE_REQ_T* ptReq = (ODV3_CREATE_DATATYPE_REQ_T*)ptPkt; memset(ptReq, 0x00, sizeof(*ptReq)); ptReq->tHead.ulCmd = ODV3_CREATE_DATATYPE_REQ; ptReq->tHead.ulDest = HIL_PACKET_DEST_DEFAULT_CHANNEL; ptReq->tHead.ulLen = 6; ptReq->tData.ulDatatypeBitLength=sizeof(uint32_t) * 8; ptReq->tData.usDatatype= INDEX_OF_MY_ENUM; return ulRet; } static uint32_t AppECS_OD_HandleCreateObjectCnf(APP_DATA_T *ptAppData, CUSTOM_OD_T* ptCustOd) { ... //CUSTOM_OD_T* ptCustOd = &g_customOd; ... } static uint32_t AppECS_OD_SendCreateObjectReq(APP_DATA_T *ptAppData, CUSTOM_OD_T* ptCustOd) { ... AppECS_OD_HandleCreateObjectCnf(ptAppData, ptCustOd); ... } static uint32_t AppECS_OD_HandleCreateSubObjectCnf(APP_DATA_T *ptAppData, CUSTOM_OD_T* ptCustOd) { ... //CUSTOM_OD_T* ptCustOd = &g_customOd; ... } static uint32_t AppECS_OD_SendCreateSubObjectReq(APP_DATA_T *ptAppData, CUSTOM_OD_T* ptCustOd) { ... AppECS_OD_HandleCreateSubObjectCnf(ptAppData, ptCustOd); ... } uint32_t AppECS_ConfigureStack(APP_DATA_T *ptAppData) { ... /* initialize channel to use the configured data */ App_SysPkt_AssembleChannelInitReq(ptPacket); ulRet = Pkt_SendReceivePacket(ptAppData, ECS_DEMO_CHANNEL_INDEX, ptPacket, TXRX_TIMEOUT); if( ulRet != CIFX_NO_ERROR ) return ulRet; /* Create datatypeObjects */ AppECS_OD_SendCreateObjectReq(ptAppData, &g_datatype); if( ulRet != CIFX_NO_ERROR ) return ulRet; /* Create datatypeObjects */ AppECS_CreateDatatypeReq(ptPacket); ulRet = Pkt_SendReceivePacket(ptAppData, ECS_DEMO_CHANNEL_INDEX, ptPacket, TXRX_TIMEOUT); if( ulRet != CIFX_NO_ERROR ) return ulRet; /* Create Objects */ AppECS_OD_SendCreateObjectReq(ptAppData, &g_customOd); if( ulRet != CIFX_NO_ERROR ) return ulRet; ... }