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;
...
}


4 CoE objectlist