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