设备收到can帧之后就调用解包函数canDispatch,在这个函数里,根据帧ID的不同进行分类处理。
void canDispatch(CO_Data* d, Message *m)
{
UNS16 cob_id = UNS16_LE(m->cob_id);
switch(cob_id >> 7)
{
case SYNC: /* can be a SYNC or a EMCY message */
if(cob_id == 0x080) /* SYNC */
{
if(d->CurrentCommunicationState.csSYNC)
proceedSYNC(d);
} else /* EMCY */
if(d->CurrentCommunicationState.csEmergency)
proceedEMCY(d,m);
break;
case TIME_STAMP:
case PDO1tx:
case PDO1rx:
case PDO2tx:
case PDO2rx:
case PDO3tx:
case PDO3rx:
case PDO4tx:
case PDO4rx:
if (d->CurrentCommunicationState.csPDO)
proceedPDO(d,m);
break;
case SDOtx:
case SDOrx:
if (d->CurrentCommunicationState.csSDO)
proceedSDO(d,m);
break;
case NODE_GUARD:
if (d->CurrentCommunicationState.csLifeGuard)
proceedNODE_GUARD(d,m);
break;
case NMT:
if (*(d->iam_a_slave))
{
proceedNMTstateChange(d,m);
}
break;
#ifdef CO_ENABLE_LSS
case LSS:
if (!d->CurrentCommunicationState.csLSS)break;
if ((*(d->iam_a_slave)) && cob_id==MLSS_ADRESS)
{
proceedLSS_Slave(d,m);
}
else if(!(*(d->iam_a_slave)) && cob_id==SLSS_ADRESS)
{
proceedLSS_Master(d,m);
}
break;
#endif
}
}
- 对于PDO,调用proceedPDO。
/*!
**
**
** @param d
** @param m
**
** @return
**/
UNS8
proceedPDO (CO_Data * d, Message * m)
{
UNS8 numPdo;
UNS8 numMap; /* Number of the mapped varable */
UNS8 *pMappingCount = NULL; /* count of mapped objects... */
/* pointer to the var which is mapped to a pdo... */
/* void * pMappedAppObject = NULL; */
/* pointer fo the var which holds the mapping parameter of an
mapping entry */
UNS32 *pMappingParameter = NULL;
UNS8 *pTransmissionType = NULL; /* pointer to the transmission
type */
UNS32 *pwCobId = NULL;
UNS8 Size;
UNS8 offset;
UNS8 status;
UNS32 objDict;
UNS16 offsetObjdict;
UNS16 lastIndex;
status = state2;
MSG_WAR (0x3935, "proceedPDO, cobID : ", (UNS16_LE(m->cob_id) & 0x7ff));
offset = 0x00;
numPdo = 0;
numMap = 0;
if ((*m).rtr == NOT_A_REQUEST)
{
offsetObjdict = d->firstIndex->PDO_RCV;
lastIndex = d->lastIndex->PDO_RCV;
if (offsetObjdict)
while (offsetObjdict <= lastIndex)
{
switch (status)
{
case state2:
pwCobId = d->objdict[offsetObjdict].pSubindex[1].pObject;
if (*pwCobId == UNS16_LE(m->cob_id))
{
/* The cobId is recognized */
status = state4;
MSG_WAR (0x3936, "cobId found at index ",
0x1400 + numPdo);
break;
}
else
{
/* received cobId does not match */
numPdo++;
offsetObjdict++;
status = state2;
break;
}
case state4: /* Get Mapped Objects Number */
/* The cobId of the message received has been found in the
dictionnary. */
offsetObjdict = d->firstIndex->PDO_RCV_MAP;
lastIndex = d->lastIndex->PDO_RCV_MAP;
pMappingCount =
(UNS8 *) (d->objdict + offsetObjdict +
numPdo)->pSubindex[0].pObject;
numMap = 0;
while (numMap < *pMappingCount)
{
UNS8 tmp[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
UNS32 ByteSize;
pMappingParameter =
(UNS32 *) (d->objdict + offsetObjdict +
numPdo)->pSubindex[numMap + 1].pObject;
if (pMappingParameter == NULL)
{
MSG_ERR (0x1937, "Couldn't get mapping parameter : ",
numMap + 1);
return 0xFF;
}
/* Get the addresse of the mapped variable. */
/* detail of *pMappingParameter : */
/* The 16 hight bits contains the index, the medium 8 bits
contains the subindex, */
/* and the lower 8 bits contains the size of the mapped
variable. */
Size = (UNS8) (*pMappingParameter & (UNS32) 0x000000FF);
/* set variable only if Size != 0 and
* Size is lower than remaining bits in the PDO */
if (Size && ((offset + Size) <= (m->len << 3)))
{
/* copy bit per bit in little endian */
CopyBits (Size, (UNS8 *) & m->data[offset >> 3],
offset % 8, 0, ((UNS8 *) tmp), 0, 0);
/*1->8 => 1 ; 9->16 =>2, ... */
ByteSize = (UNS32)(1 + ((Size - 1) >> 3));
objDict =
setODentry (d, (UNS16) ((*pMappingParameter) >> 16),
(UNS8) (((*pMappingParameter) >> 8) &
0xFF), tmp, &ByteSize, 0);
if (objDict != OD_SUCCESSFUL)
{
MSG_ERR (0x1938,
"error accessing to the mapped var : ",
numMap + 1);
MSG_WAR (0x2939, " Mapped at index : ",
(*pMappingParameter) >> 16);
MSG_WAR (0x2940, " subindex : ",
((*pMappingParameter) >> 8) & 0xFF);
return 0xFF;
}
MSG_WAR (0x3942,
"Variable updated by PDO cobid : ",
UNS16_LE(m->cob_id));
MSG_WAR (0x3943, " Mapped at index : ",
(*pMappingParameter) >> 16);
MSG_WAR (0x3944, " subindex : ",
((*pMappingParameter) >> 8) & 0xFF);
offset += Size;
}
numMap++;
} /* end loop while on mapped variables */
if (d->RxPDO_EventTimers)
{
TIMEVAL EventTimerDuration = *(UNS16 *)d->objdict[offsetObjdict].pSubindex[5].pObject;
if(EventTimerDuration){
DelAlarm (d->RxPDO_EventTimers[numPdo]);
d->RxPDO_EventTimers[numPdo] = SetAlarm (d, numPdo, d->RxPDO_EventTimers_Handler,
MS_TO_TIMEVAL (EventTimerDuration), 0);
}
}
return 0;
} /* end switch status */
} /* end while */
} /* end if Donnees */
else if ((*m).rtr == REQUEST)
{
MSG_WAR (0x3946, "Receive a PDO request cobId : ", UNS16_LE(m->cob_id));
status = state1;
offsetObjdict = d->firstIndex->PDO_TRS;
lastIndex = d->lastIndex->PDO_TRS;
if (offsetObjdict)
while (offsetObjdict <= lastIndex)
{
/* study of all PDO stored in the objects dictionary */
switch (status)
{
case state1: /* check the CobId */
/* get CobId of the dictionary which match to the received PDO
*/
pwCobId =
(d->objdict +
offsetObjdict)->pSubindex[1].pObject;
if (*pwCobId == UNS16_LE(m->cob_id))
{
status = state4;
break;
}
else
{
numPdo++;
offsetObjdict++;
}
status = state1;
break;
case state4: /* check transmission type */
pTransmissionType =
(UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject;
/* If PDO is to be sampled and send on RTR, do it */
if ((*pTransmissionType == TRANS_RTR))
{
status = state5;
break;
}
/* RTR_SYNC means data prepared at SYNC, transmitted on RTR */
else if ((*pTransmissionType == TRANS_RTR_SYNC))
{
if (d->PDO_status[numPdo].
transmit_type_parameter & PDO_RTR_SYNC_READY)
{
/*Data ready, just send */
canSend (d->canHandle,
&d->PDO_status[numPdo].last_message);
return 0;
}
else
{
/* if SYNC did never occur, transmit current data */
/* DS301 do not tell what to do in such a case... */
MSG_ERR (0x1947,
"Not ready RTR_SYNC TPDO send current data : ",
UNS16_LE(m->cob_id));
status = state5;
}
break;
}
else if ((*pTransmissionType == TRANS_EVENT_PROFILE) ||
(*pTransmissionType == TRANS_EVENT_SPECIFIC))
{
/* Zap all timers and inhibit flag */
d->PDO_status[numPdo].event_timer =
DelAlarm (d->PDO_status[numPdo].event_timer);
d->PDO_status[numPdo].inhibit_timer =
DelAlarm (d->PDO_status[numPdo].inhibit_timer);
d->PDO_status[numPdo].transmit_type_parameter &=
~PDO_INHIBITED;
/* Call PDOEventTimerAlarm for this TPDO,
* this will trigger emission et reset timers */
PDOEventTimerAlarm (d, numPdo);
return 0;
}
else
{
/* The requested PDO is not to send on request. So, does
nothing. */
MSG_WAR (0x2947, "PDO is not to send on request : ",
UNS16_LE(m->cob_id));
return 0xFF;
}
case state5: /* build and send requested PDO */
{
Message pdo;
if (buildPDO (d, numPdo, &pdo))
{
MSG_ERR (0x1948, " Couldn't build TPDO number : ", numPdo);
return 0xFF;
}
canSend (d->canHandle, &pdo);
return 0;
}
} /* end switch status */
} /* end while */
} /* end if Requete */
return 0;
}
这个函数执行流程如下:
非远程帧(NOT_A_REQUEST),那么这是一个RPDO。遍历索引表中的RPDO,如果找到了对应的cob_id,就记录它相对于RPDO开始位置的偏移量(numPdo变量),进而找到映射参数map对象。解析map对象里子索引0参数,得到这个map里子索引的数量。遍历子索引,依次对子索引的map参数进行解析,找到数据存放区。调用setODentry对数据区进行写操作,写完之后调用用户自定义的回调函数。再之后,检查是否有事件定时器,如果有就根据子索引5中的设定一个定时事件,定时时间到会调用_RxPDO_EventTimers_Handler这个回调函数,在这个函数里可以实现一些需要延迟处理的动作。
远程帧(REQUEST),那么这是一个TPDO。根据TPDO传输类型的不同进行不同的处理:如果是远程异步(TRANS_RTR),就直接把这个TPDO的内容发送出去;如果是远程同步(TRANS_RTR_SYNC),还要检查transmit_type_parameter这个参数并做不同处理;如果是制造商特定事件(TRANS_EVENT_SPECIFIC)或者设备子协议特定事件(TRANS_EVENT_PROFILE),就调用PDOEventTimerAlarm函数,生成TPDO对象并和上一次的对象比较,如果不同就发送出去。
而根据DS301协议规定的另外两种传输类型非循环同步和循环同步,则是在处理同步帧的函数proceedSYNC处理的。