UINT8 SDOS_SdoInd(TINITSDOMBX MBXMEM *pSdoInd)
{
UINT8 abort = 0;
UINT8 sdoHeader = pSdoInd->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] & SDOHEADER_COMMANDMASK;
/* the SDO-command is in bit 5-7 of the first SDO-Byte */
UINT8 command = (sdoHeader & SDOHEADER_COMMAND);
/* mbxSize contains the size of the mailbox (CoE-Header (2 Bytes) + SDO-Header (8 Bytes) + SDO-Data (if the data length is greater than 4)) */
UINT16 mbxSize = pSdoInd->MbxHeader.Length;
UINT16 index;
UINT8 subindex;
OBJCONST TOBJECT OBJMEM * pObjEntry;
/* this variable contains the information, if all entries of an object will be read (bCompleteAccess > 0) or a single entry */
UINT8 bCompleteAccess = 0;
UINT32 objLength = 0;
UINT32 dataSize = 0;
#if SDO_RES_INTERFACE
if ( bSdoInWork )
{
/* the last SDO is still in work */
return MBXERR_SERVICEINWORK;
}
#endif
/*根据SDO的不同的服务类型,选择想对应的SDO服务*/
switch (command)
{
case SDOSERVICE_INITIATEDOWNLOADREQ:
case SDOSERVICE_INITIATEUPLOADREQ:
/* the variable index contains the requested index of the SDO service */
/*这个变量索引包含需要的SDO服务的索引*/
index = pSdoInd->SdoHeader.Sdo[SDOHEADER_INDEXHIOFFSET] & SDOHEADER_INDEXHIMASK;
index <<= 8;
index += pSdoInd->SdoHeader.Sdo[SDOHEADER_INDEXLOOFFSET] >> SDOHEADER_INDEXLOSHIFT;
/* the variable subindex contains the requested subindex of the SDO service */
/*子索引的变量包含需要的SDO服务需要的子索引*/
subindex = pSdoInd->SdoHeader.Sdo[SDOHEADER_SUBINDEXOFFSET] >> SDOHEADER_SUBINDEXSHIFT;
/* OBJ_GetObjectHandle checks if the requested index is defined in the object dictionary */
/*OBJ_GetObjectHandle检查是否需要的index是否在对象字典里面定义,并获得它的句柄*/
pObjEntry = OBJ_GetObjectHandle( index );
if ( pObjEntry )
{
/*如果在搜寻所有的对象字典之后,得到所需要索引的句柄*/
/* transferType contains the information if the SDO Download Request or the SDO Upload Response
can be an expedited service (SDO data length <= 4, that means the data is stored in the
SDO-Header completely */
/*transferType包含那些信息,是否SDO 下载请求和SDO 上传响应可以是快速服务类型(SDO数据长度小于等于4个字节,数据可以完全放在SDO-Header里面)*/
UINT8 bTransferType = 0;
/* pData is the pointer to the received (SDO-Download) or sent (SDO-Upload) SDO data in the mailbox */
/*pData是一个指针指向在邮箱里面,SDO下载和SDO上传的对象字典的数据*/
UINT16 MBXMEM * pData = NULL;
#if SEGMENTED_SDO_SUPPORTED
UINT8 segTransfer = 0;
#endif
{
dataSize = objLength = OBJ_GetObjectLength( index, subindex, pObjEntry, (UINT8) (sdoHeader & SDOHEADER_COMPLETEACCESS) );
if ( command == SDOSERVICE_INITIATEUPLOADREQ )//如果SDO里面的命令是SDO上传请求的话
{
/*如果SDO里面的对象字典的长度小于等于MAX_EXPEDITED_DATA和不等于零的时候,则是快速类型的上传模式*/
/* SDO Upload */
if ( mbxSize != EXPEDITED_FRAME_SIZE )
/* a SDO Upload request has always a fixed size (2 Byte CoE-Header plus 8 Byte SDO-Header) */
return MBXERR_INVALIDSIZE;
/* distinguish between expedited and normal upload response within the length of the response data */
if ( (objLength <= MAX_EXPEDITED_DATA) && objLength != 0 )
{
/* Expedited Upload */
bTransferType = 1;
/* pData is the pointer where the object data has to be copied for the response */
/*pData是一个指针,它指向的对象字典数据被复制对应的数据作为响应*/
pData = ((TINITSDOUPLOADEXPRESMBX MBXMEM *) pSdoInd)->Data;
/* initialize the 4 data bytes of the SDO upload response because the requested object data
could be less than 4 */
/*因为请求的对象数据是小于4个字节,初始化4个字节数据给SDO上传响应*/
pData[0] = 0;
pData[1] = 0;
}
else //这个else是对应上面的((objLength<=MAX_EXPEDITED_DATA)&& objLength !=0) 如果对象字典的长度大于MAX_EXPEDITED_DATA也就是4个字节的时候。则说明上传是分段上传模式或者是正常上传模式。
{
dataSize = u16SendMbxSize - MBX_HEADER_SIZE - UPLOAD_NORM_RES_SIZE;
/*如果对象字典的长度比邮箱对象数据区的长度还要打的时候,说明是要采用分段类型的形式上传数据*/
if ( dataSize < objLength )
/* Segmented Upload */
segTransfer = 1;
else
/*否则采用正常上传模式*/
/* Normal Upload */
pData = ((TINITSDOUPLOADNORMRESMBX MBXMEM *) pSdoInd)->Data;
/*pData指向对象字典的数据区地址*/
#else/*如果从站本身不支持分段上传模式的话,则不需要上面的判断*/
/* Normal Upload */
/* pData is the pointer where the object data has to be copied for the response */
/*pData是一个指针,作为响应,指向的地方对象字典的数据应该被拷贝*/
pData = ((TINITSDOUPLOADNORMRESMBX MBXMEM *) pSdoInd)->Data;
#endif
}
}
else//如果对象字典的命令,不是SDO上传命令的话
{
/* SDO-Download: store if the request is a expedited or normal request 判断是否为快速还是普通请求 */
bTransferType = sdoHeader & SDOHEADER_TRANSFERTYPE;
}
}
if ( command == SDOSERVICE_INITIATEDOWNLOADREQ )//如果SDO的命令是下载请求
{
/* SDO Download */
if ( bTransferType )//根据前面判断是否为快速下载请求
{
/* Expedited Download */
if ( mbxSize != EXPEDITED_FRAME_SIZE )
/* an Expedited SDO Download request has always a fixed size (2 Byte CoE-Header plus 8 Byte SDO-Header) */
return MBXERR_INVALIDSIZE;
/* dataSize gets the real size of the downloaded object data (1,2,3 or 4) */
dataSize = MAX_EXPEDITED_DATA - ((sdoHeader & SDOHEADER_DATASETSIZE) >> SDOHEADERSHIFT_DATASETSIZE);
/* pData is the pointer to the downloaded object data */
//pData是一个指针指向SDO的数据区
pData = (UINT16 MBXMEM *) &pSdoInd[1];
}
else//如果不是快速下载请求
{
/* Normal Download */
/* downloadSize gets the real size of the downloaded data */
/* '&' operator was too much */
UINT32 downloadSize = ((UINT32)(SWAPWORD(((TINITSDODOWNLOADNORMREQMBX MBXMEM *) pSdoInd)->CompleteSize[1]))<<16) + (SWAPWORD(((TINITSDODOWNLOADNORMREQMBX MBXMEM *) pSdoInd)->CompleteSize[0]));
/* HBu 29.03.06: if it is a segmented download the mbxSize has to be the complete mailbox size */
if ( (MBX_HEADER_SIZE+EXPEDITED_FRAME_SIZE+downloadSize) > u16ReceiveMbxSize )//如果它是一个分段下载类型,mbxSize毕业是一个完整的邮箱长度
{
if ( mbxSize != (u16ReceiveMbxSize-MBX_HEADER_SIZE) )
return MBXERR_INVALIDSIZE;
}
else
{
if ( mbxSize != (EXPEDITED_FRAME_SIZE+downloadSize) )
/* the mbxSize and the downloadSize are not consistent (mbxSize = downloadSize + 2 byte CoE-Header + 8 byte SDO Header */
return MBXERR_INVALIDSIZE;
}
/* pData is the pointer to the downloaded object data */
pData = (UINT16 MBXMEM *) ((TINITSDODOWNLOADNORMREQMBX MBXMEM *) pSdoInd)->Data;//pData是一个指针指向下载对象的数据区
/* the received dataSize will be checked in the object specific functions called from
OBJ_Write (in objdef.c) */
dataSize = downloadSize;接受的dataSize多大将会被检查在对象特殊的函数,在OBJ_Write(在object.c文件里调用)
if ( dataSize > (UINT32)(mbxSize - DOWNLOAD_NORM_REQ_SIZE) )//对象字典的长度大于mbxSize-DOWNLOAD_NORM_REQ_SIZE的时候
#if SEGMENTED_SDO_SUPPORTED
/* Segmented Download */
segTransfer = 1;//采用分段下载的形式
#else /* SEGMENTED_SDO_SUPPORTED */
abort = ABORTIDX_PARAM_LENGTH_ERROR;
#endif /* SEGMENTED_SDO_SUPPORTED */
}
}
if ( sdoHeader & SDOHEADER_COMPLETEACCESS )//接下来对sdoHeader的是否完全操作进行判断
#if COMPLETE_ACCESS_SUPPORTED
{
bCompleteAccess = 1;//可以完全操作
// HBu 02.05.06: Complete Access is only supported with subindex 0 and 1
if (subindex > 1)
abort = ABORTIDX_UNSUPPORTED_ACCESS;
}
#else
abort = ABORTIDX_UNSUPPORTED_ACCESS;
#endif
if ( abort == 0 )//abort ==0,说明是可以完全操作子索引是0或者1
{
#if SEGMENTED_SDO_SUPPORTED
if ( segTransfer )//如果可以分段传输
{
bSdoSegFollows = TRUE;
bSdoSegLastToggle = 1;
#if COMPLETE_ACCESS_SUPPORTED
bSdoSegAccess = bCompleteAccess;
#endif
nSdoSegIndex = index;
nSdoSegSubindex = subindex;
pSdoSegObjEntry = pObjEntry;
if ( command == SDOSERVICE_INITIATEUPLOADREQ )
nSdoSegCompleteSize = objLength;
else
nSdoSegCompleteSize = dataSize;
if (pSdoSegData != NULL)
{
FREEMEM( (UINT16 VARMEM *) pSdoSegData);
pSdoSegData = NULL;
}
/*ECATCHANGE_START(V5.01) MBX1*/
pSdoSegData = (UINT16 VARMEM *) ALLOCMEM( ROUNDUPBYTE2WORD(nSdoSegCompleteSize) );
/*ECATCHANGE_END(V5.01) MBX1*/
if ( pSdoSegData == NULL )
abort = ABORTIDX_OUT_OF_MEMORY;
else
{
if ( command == SDOSERVICE_INITIATEUPLOADREQ )
{
/* Segmented Upload */
abort = OBJ_Read( index, subindex, objLength, pObjEntry, (UINT16 MBXMEM *) pSdoSegData, bCompleteAccess );
//如果读操作成功的话,则返回0;如果读操作失败的话,则返回0xFF
if ( abort == 0 )
{
MBXMEMCPY( ((TINITSDOUPLOADNORMRESMBX MBXMEM *) pSdoInd)->Data, pSdoSegData, dataSize );//将读到的pSdoSegData数据拷贝到pSdoInd的数据区。
nSdoSegService = SDOSERVICE_UPLOADSEGMENTREQ;
}
#if SDO_RES_INTERFACE
else if ( abort == ABORTIDX_WORKING )
{
/* ECATCHANGE_START(V5.01) SDO6*/
/* the application generates the SDO-Response later on by calling SDOS_SdoRes (only possible if object access function pointer is defined) */
//在这种情况应用程序产生一个SDO-Response通过调用函数SDOS_SdoRes()就是SDO响应程序,当数据对象接入函数已经被定义
u8PendingSdo = SDO_PENDING_SEG_READ;
bStoreCompleteAccess = bCompleteAccess;
u8StoreSubindex = subindex;
u16StoreIndex = index;
u32StoreDataSize = objLength;
pStoreData = pSdoSegData;
pSdoPendFunc = pObjEntry->Read;//采用虚函数的形式定义数据对象的函数
bSdoInWork = TRUE;
/* we have to store the buffer and the response header */
pSdoResStored = pSdoInd;
/*update command field*/
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] &= ~SDOHEADER_COMMANDMASK;
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] |= (sdoHeader & (SDOHEADER_COMPLETEACCESS | SDOHEADER_COMMAND));
nSdoSegService = SDOSERVICE_UPLOADSEGMENTREQ;
return 0;//返回去函数,并且,通过SDOS_SdoRes()来操作数据对象
/* ECATCHANGE_END(V5.01) SDO6*/
}
#endif
}
else//如果命令是SDO下载命令,则将pSdoInd->Data里面的数据拷贝到pSdoSegData里面,并且,付对应的SdoSegService和对应的数据长度
{
/* Segmented Download */
MBXMEMCPY( pSdoSegData, ((TINITSDODOWNLOADNORMREQMBX MBXMEM *) pSdoInd)->Data, mbxSize-DOWNLOAD_NORM_REQ_SIZE );
nSdoSegService = SDOSERVICE_DOWNLOADSEGMENTREQ;
dataSize = (mbxSize-DOWNLOAD_NORM_REQ_SIZE);
}
nSdoSegBytesToHandle = dataSize;
}
}
else//接下来的这种情况,考虑不是分段传输的情况
#endif // SEGMENTED_SDO_SUPPORTED
{
#if SEGMENTED_SDO_SUPPORTED
#if SDO_RES_INTERFACE
if ( objLength == 0 )
{
/* the objLength is not known, therefore the variables for a possible segmented transfer
should be initialized */
nSdoSegIndex = index;
nSdoSegSubindex = subindex;
pSdoSegObjEntry = pObjEntry;
}
#endif // SDO_RES_INTERFACE
#endif // SEGMENTED_SDO_SUPPORTED
if ( command == SDOSERVICE_INITIATEUPLOADREQ )//如果SDO服务是上传服务
{
/* Expedited or Normal Upload *///已经排除了分段上传,就剩下快速上传和普通上传模式
abort = OBJ_Read( index, subindex, objLength, pObjEntry, pData, bCompleteAccess );
#if SDO_RES_INTERFACE
if ( abort == ABORTIDX_WORKING )
{
/* ECATCHANGE_START(V5.01) SDO6*/
/* the application generates the SDO-Response later on by calling SDOS_SdoRes (only possible if object access function pointer is defined) *///同上的分段上传的情况
u8PendingSdo = SDO_PENDING_READ;
bStoreCompleteAccess = bCompleteAccess;
u8StoreSubindex = subindex;
u16StoreIndex = index;
u32StoreDataSize = objLength;
pStoreData = pData;
pSdoPendFunc = pObjEntry->Read;
bSdoInWork = TRUE;
/* we have to store the buffer and the response header */
pSdoResStored = pSdoInd;
/*update command field*/
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] &= ~SDOHEADER_COMMANDMASK;
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] |= (sdoHeader & (SDOHEADER_COMPLETEACCESS | SDOHEADER_COMMAND));
return 0;
/* ECATCHANGE_END(V5.01) SDO6*/
}
#endif // SDO_RES_INTERFACE
}
else
{
/* Expedited or Normal Download *///快速和普通下载模式
abort = OBJ_Write( index, subindex, dataSize, pObjEntry, pData, bCompleteAccess );
#if SDO_RES_INTERFACE
if ( abort == ABORTIDX_WORKING )
{
/* ECATCHANGE_START(V5.01) SDO6*/
/* the application generates the SDO-Response later on by calling SDOS_SdoRes (only possible if object access function pointer is defined) */
u8PendingSdo = SDO_PENDING_WRITE;
bStoreCompleteAccess = bCompleteAccess;
u8StoreSubindex = subindex;
u16StoreIndex = index;
u32StoreDataSize = dataSize;
pStoreData = pData;
pSdoPendFunc = pObjEntry->Write;
bSdoInWork = TRUE;
/* we have to store the buffer and the response header */
pSdoResStored = pSdoInd;
/*update command field*/
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] &= ~SDOHEADER_COMMANDMASK;
pSdoResStored->SdoHeader.Sdo[SDOHEADER_COMMANDOFFSET] |= (sdoHeader & (SDOHEADER_COMPLETEACCESS | SDOHEADER_COMMAND));
return 0;
/* ECATCHANGE_END(V5.01) SDO6*/
}
#endif // SDO_RES_INTERFACE
}
} /* else if ( objLength == 0 ) */
} /* if ( abort == 0 ) */
}//endif 获得不到对应的对象字典的句柄
else
{
abort = ABORTIDX_OBJECT_NOT_EXISTING;
}
break;
#if SEGMENTED_SDO_SUPPORTED
case SDOSERVICE_DOWNLOADSEGMENTREQ://当SDOSERVICE_DOWNLOADSEGMENTREQ和SDOSERVICE_UPLOADSEGMENTREQ产生时候一并在下面处理
case SDOSERVICE_UPLOADSEGMENTREQ:
if ( command == nSdoSegService )
{
if ( command == SDOSERVICE_DOWNLOADSEGMENTREQ )
abort = SdoDownloadSegmentInd( (TDOWNLOADSDOSEGREQMBX MBXMEM *) pSdoInd );
//这个函数将会被调用当下载SDO主站的分段请求服务,如果它是最后一个分段数据的话,将会被写入到对象字典,这个函数自身会做出对象响应
else
abort = SdoUploadSegmentInd( (TUPLOADSDOSEGREQMBX MBXMEM *) pSdoInd );
}
else
abort = ABORTIDX_COMMAND_SPECIFIER_UNKNOWN;
break;
#endif
default:
abort = ABORTIDX_COMMAND_SPECIFIER_UNKNOWN;
break;
}
#if SDO_RES_INTERFACE
/* ECATCHANGE_START(V5.01) SDO6*/
if(abort != ABORTIDX_WORKING)
/* ECATCHANGE_END(V5.01) SDO6*/
#endif
{
/*当SDO响应应该被发送的时候,这个函数将会被调用*/
SdoRes(abort, command, (UINT8) (sdoHeader & SDOHEADER_COMPLETEACCESS), (UINT16) dataSize, objLength, pSdoInd);
}
return 0;
}