往死里写——SDO处理过程2-1

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

你可能感兴趣的:(往死里写——SDO处理过程2-1)