当从站收到主站发来的RPDO数据之后,怎么去执行特定的操作呢?
只需要编写回调函数并注册到相应的索引对象就可以。
索引回调函数的原型在objdictdef.h定义,如下所示
typedef UNS32 (*ODCallback_t)(CO_Data* d, const indextable *, UNS8 bSubindex);
typedef struct td_subindex
{
UNS8 bAccessType;
UNS8 bDataType; /* Defines of what datatype the entry is */
UNS32 size; /* The size (in Byte) of the variable */
void* pObject; /* This is the pointer of the Variable */
ODCallback_t callback; /* Callback function on write event */
} subindex;
定义RPDO1的回调函数如下
UNS32 _cb_RPDO1(CO_Data* d, const indextable *table, UNS8 bSubindex)
{
//关联变量:Write_Outputs_8_Bit
uint32_t ret = 0;
uint8_t doOut = *(uint8_t*)table->pSubindex[bSubindex].pObject;
for(int channel=0;channel<8;channel++)
{
JC_do_output(channel+1,(doOut>>channel)&0x01);
}
return ret;
}
函数里可以直接操作关联的变量Write_Outputs_8_Bit的,直接操作还简单一点。
注册回调函数的函数在objacces.c中定义
UNS32 RegisterSetODentryCallBack(CO_Data* d, UNS16 wIndex, UNS8 bSubindex, ODCallback_t Callback)
{
UNS32 errorCode;
const indextable *odentry;
odentry = d->scanIndexOD (d, wIndex, &errorCode);
if(errorCode == OD_SUCCESSFUL && bSubindex < odentry->bSubCount)
odentry->pSubindex[bSubindex].callback = Callback;
return errorCode;
}
这个函数很简单也很好理解,只需要调用它把自定义的回调函数注册到对应索引的对象就可以了
RegisterSetODentryCallBack( &A46Slave_Data,0x6200,0x01,_cb_RPDO1);
这样当收到RPDO1的数据之后,协议栈在处理完数据之后会自动调用自定义的回调函数_cb_RPDO1,自定义的操作得以执行。
有些RPDO可能会有多个子索引,我们可以在每个子索引都注册回调函数,也可以只在最后的那个子索引注册回调函数,对之前的子索引统一操作。
除了能自定义回调函数,协议栈还预定义了其他一些回调函数,但是都是空实现,我们可以根据自己的实际需求去实现
/***********************************************************************
**callbacks frome canfestival start
**这些回调看需求实现
***********************************************************************/
//states.c
void _initialisation(CO_Data* d)
{
_ledState = d->nodeState;
}
void _preOperational(CO_Data* d)
{
_ledState = d->nodeState;
if (!(*(d->iam_a_slave)))
{
masterSendNMTstateChange (d, 0, NMT_Reset_Node);
}
}
void _operational(CO_Data* d)
{
_ledState = d->nodeState;
}
void _stopped(CO_Data* d)
{
_ledState = d->nodeState;
}
//emcy.c
void _post_emcy(CO_Data* d, UNS8 nodeID, UNS16 errCode, UNS8 errReg, const UNS8 errSpec[5])
{
(void)d;
(void)nodeID;
(void)errCode;
(void)errReg;
(void)errSpec;
}
//lifegrd.c
void _heartbeatError(CO_Data* d, UNS8 heartbeatID)
{
(void)d;
(void)heartbeatID;
}
void _post_SlaveBootup(CO_Data* d, UNS8 SlaveID)
{
(void)d;
(void)SlaveID;
}
void _post_SlaveStateChange(CO_Data* d, UNS8 nodeId, e_nodeState newNodeState)
{
(void)d;
(void)nodeId;
(void)newNodeState;
}
void _nodeguardError(CO_Data* d, UNS8 id)
{
(void)d;
(void)id;
}
//objacces.c
UNS32 _storeODSubIndex (CO_Data* d, UNS16 wIndex, UNS8 bSubindex)
{
(void)d;
(void)wIndex;
(void)bSubindex;
return OD_SUCCESSFUL;
}
//sync.c
void _post_sync(CO_Data* d)
{
(void)d;
}
void _post_TPDO(CO_Data* d)
{
(void)d;
}
void canChangeBaudRate(CAN_PORT canhandle, char* baudrate)
{
return;
}
/***********************************************************************
**callbacks from canfestival end
***********************************************************************/
这些函数有的在初始化字典编辑器自动生成的A46Slave_Data变量(CO_Data类型)的时候,成为了A46Slave_Data的一个元素。
CO_Data A46Slave_Data = CANOPEN_NODE_DATA_INITIALIZER(A46Slave);
/* A macro to initialize the data in client app.*/
/* CO_Data structure */
#define CANOPEN_NODE_DATA_INITIALIZER(NODE_PREFIX) {\
/* Object dictionary*/\
& NODE_PREFIX ## _bDeviceNodeId, /* bDeviceNodeId */\
NODE_PREFIX ## _objdict, /* objdict */\
NODE_PREFIX ## _PDO_status, /* PDO_status */\
NULL, /* RxPDO_EventTimers */\
_RxPDO_EventTimers_Handler, /* RxPDO_EventTimers_Handler */\
& NODE_PREFIX ## _firstIndex, /* firstIndex */\
& NODE_PREFIX ## _lastIndex, /* lastIndex */\
& NODE_PREFIX ## _ObjdictSize, /* ObjdictSize */\
& NODE_PREFIX ## _iam_a_slave, /* iam_a_slave */\
NODE_PREFIX ## _valueRangeTest, /* valueRangeTest */\
\
/* SDO, structure s_transfer */\
{\
REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERS_TIMES(s_transfer_Initializer)\
},\
\
/* State machine*/\
Unknown_state, /* nodeState */\
/* structure s_state_communication */\
{\
0, /* csBoot_Up */\
0, /* csSDO */\
0, /* csEmergency */\
0, /* csSYNC */\
0, /* csHeartbeat */\
0, /* csPDO */\
0 /* csLSS */\
},\
_initialisation, /* initialisation */\
_preOperational, /* preOperational */\
_operational, /* operational */\
_stopped, /* stopped */\
NULL, /* NMT node reset callback */\
NULL, /* NMT communications reset callback */\
\
/* NMT-heartbeat */\
& NODE_PREFIX ## _highestSubIndex_obj1016, /* ConsumerHeartbeatCount */\
NODE_PREFIX ## _obj1016, /* ConsumerHeartbeatEntries */\
NODE_PREFIX ## _heartBeatTimers, /* ConsumerHeartBeatTimers */\
& NODE_PREFIX ## _obj1017, /* ProducerHeartBeatTime */\
TIMER_NONE, /* ProducerHeartBeatTimer */\
_heartbeatError, /* heartbeatError */\
\
{REPEAT_NMT_MAX_NODE_ID_TIMES(NMTable_Initializer)},\
/* is well initialized at "Unknown_state". Is it ok ? (FD)*/\
\
/* NMT-nodeguarding */\
TIMER_NONE, /* GuardTimeTimer */\
TIMER_NONE, /* LifeTimeTimer */\
_nodeguardError, /* nodeguardError */\
& NODE_PREFIX ## _obj100C, /* GuardTime */\
& NODE_PREFIX ## _obj100D, /* LifeTimeFactor */\
{REPEAT_NMT_MAX_NODE_ID_TIMES(nodeGuardStatus_Initializer)},\
\
/* SYNC */\
TIMER_NONE, /* syncTimer */\
& NODE_PREFIX ## _obj1005, /* COB_ID_Sync */\
& NODE_PREFIX ## _obj1006, /* Sync_Cycle_Period */\
/*& NODE_PREFIX ## _obj1007, */ /* Sync_window_length */\
_post_sync, /* post_sync */\
_post_TPDO, /* post_TPDO */\
_post_SlaveBootup, /* post_SlaveBootup */\
_post_SlaveStateChange, /* post_SlaveStateChange */\
\
/* General */\
0, /* toggle */\
NULL, /* canSend */\
NODE_PREFIX ## _scanIndexOD, /* scanIndexOD */\
_storeODSubIndex, /* storeODSubIndex */\
/* DCF concise */\
NULL, /*dcf_odentry*/\
NULL, /*dcf_cursor*/\
1, /*dcf_entries_count*/\
0, /* dcf_status*/\
0, /* dcf_size */\
NULL, /* dcf_data */\
\
/* EMCY */\
Error_free, /* error_state */\
sizeof(NODE_PREFIX ## _obj1003) / sizeof(NODE_PREFIX ## _obj1003[0]), /* error_history_size */\
& NODE_PREFIX ## _highestSubIndex_obj1003, /* error_number */\
& NODE_PREFIX ## _obj1003[0], /* error_first_element */\
& NODE_PREFIX ## _obj1001, /* error_register */\
& NODE_PREFIX ## _obj1014, /* error_cobid */\
/* error_data: structure s_errors */\
{\
REPEAT_EMCY_MAX_ERRORS_TIMES(ERROR_DATA_INITIALIZER)\
},\
_post_emcy, /* post_emcy */\
/* LSS */\
lss_Initializer\
}