1.首先进行设置节点的状态,节点自动从初始化切入到预操作状态,如果接收到其他节点的boot up,则主节点则通过SDO来对相应的从节点进行配置,配置完成后,需要主站调用函数,将所有的节点设置到操作状态。
主站根据自身的状态开启不同通信的功能,比如:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83/*! ** ** ** @param d ** @param newCommunicationState **/ void switchCommunicationState(CO_Data* d, s_state_communication *newCommunicationState) { #ifdef CO_ENABLE_LSS StartOrStop(csLSS, startLSS(d), stopLSS(d)) #endif StartOrStop(csSDO, None, resetSDO(d)) StartOrStop(csSYNC, startSYNC(d), stopSYNC(d)) StartOrStop(csHeartbeat, heartbeatInit(d), heartbeatStop(d)) StartOrStop(csEmergency, emergencyInit(d), emergencyStop(d)) StartOrStop(csPDO, PDOInit(d), PDOStop(d)) StartOrStop(csBoot_Up, None, slaveSendBootUp(d)) } UNS8 setState(CO_Data* d, e_nodeState newState) { if(newState != d->nodeState){ switch( newState ){ case Initialisation: { s_state_communication newCommunicationState = {1, 0, 0, 0, 0, 0, 0}; d->nodeState = Initialisation; switchCommunicationState(d, &newCommunicationState); /* call user app init callback now. */ /* d->initialisation MUST NOT CALL SetState */ (*d->initialisation)(d); } /* Automatic transition - No break statement ! */ /* Transition from Initialisation to Pre_operational */ /* is automatic as defined in DS301. */ /* App don't have to call SetState(d, Pre_operational) */ case Pre_operational: { s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 0, 1}; d->nodeState = Pre_operational; switchCommunicationState(d, &newCommunicationState); if (!(*(d->iam_a_slave))) { masterSendNMTstateChange (d, 0, NMT_Reset_Node); } (*d->preOperational)(d); } break; case Operational: if(d->nodeState == Initialisation) return 0xFF; { s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 1, 0}; d->nodeState = Operational; newState = Operational; switchCommunicationState(d, &newCommunicationState); (*d->operational)(d); } break; case Stopped: if(d->nodeState == Initialisation) return 0xFF; { s_state_communication newCommunicationState = {0, 0, 0, 0, 1, 0, 1}; d->nodeState = Stopped; newState = Stopped; switchCommunicationState(d, &newCommunicationState); (*d->stopped)(d); } break; default: return 0xFF; }/* end switch case */ } /* d->nodeState contains the final state */ /* may not be the requested state */ return d->nodeState; }
其中可以看到主节点设备在预操作状态下,boot up上线,SDO和emergency紧急报文和SYNC功能了,协议栈后续一系列的功能都是基于主站的这个同步发生器的功能实现。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/*! ** ** ** @param d **/ void startSYNC(CO_Data* d) { if(d->syncTimer != TIMER_NONE){ stopSYNC(d); } RegisterSetODentryCallBack(d, 0x1005, 0, &OnCOB_ID_SyncUpdate); RegisterSetODentryCallBack(d, 0x1006, 0, &OnCOB_ID_SyncUpdate); if(*d->COB_ID_Sync & 0x40000000ul && *d->Sync_Cycle_Period) { d->syncTimer = SetAlarm( d, 0 /*No id needed*/, &SyncAlarm, US_TO_TIMEVAL(*d->Sync_Cycle_Period), US_TO_TIMEVAL(*d->Sync_Cycle_Period)); } }
先判断同步发生器是否使能并且同步周期的值不为零,然后根据相应的参数设置一个同步定时器。
同步定时器的定时时间到回调相应的函数:
复制代码
1
2
3
4
5
6
7
8
9
10/*! ** ** ** @param d ** @param id **/ void SyncAlarm(CO_Data* d, UNS32 id) { sendSYNC(d) ; }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/*! ** ** ** @param d ** @param cob_id ** ** @return **/ UNS8 sendSYNC(CO_Data* d) { UNS8 res; res = sendSYNCMessage(d); proceedSYNC(d) ; return res ; }
主站向总线上发送一个同步报文,然后处理同步报文。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/*! ** ** ** @param d ** @param m ** ** @return **/ UNS8 proceedSYNC(CO_Data* d) { UNS8 res; MSG_WAR(0x3002, "SYNC received. Proceed. ", 0); (*d->post_sync)(d); /* only operational state allows PDO transmission */ if(! d->CurrentCommunicationState.csPDO) return 0; res = _sendPDOevent(d, 1 /*isSyncEvent*/ ); /*Call user app callback*/ (*d->post_TPDO)(d); return res; }
执行同步报文的回调函数,判断主站节点是否是操作状态,如果不是就返回,然后发送主站节点的PDO,最后执行发送PDO的回调函数。
下面是发送PDO需要先后执行的函数:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135/*! ** ** ** @param d ** @param isSyncEvent ** ** @return **/ UNS8 _sendPDOevent (CO_Data * d, UNS8 isSyncEvent) { UNS8 pdoNum = 0x00; /* number of the actual processed pdo-nr. */ UNS8 *pTransmissionType = NULL; UNS8 status = state3; UNS16 offsetObjdict = d->firstIndex->PDO_TRS; UNS16 offsetObjdictMap = d->firstIndex->PDO_TRS_MAP; UNS16 lastIndex = d->lastIndex->PDO_TRS; if (!d->CurrentCommunicationState.csPDO) { return 0; } /* study all PDO stored in the objects dictionary */ if (offsetObjdict) { Message pdo;/* = Message_Initializer;*/ memset(&pdo, 0, sizeof(pdo)); while (offsetObjdict <= lastIndex) { switch (status) { case state3: if ( /* bSubCount always 5 with objdictedit -> check disabled */ /*d->objdict[offsetObjdict].bSubCount < 5 ||*/ /* check if TPDO is not valid */ *(UNS32 *) d->objdict[offsetObjdict].pSubindex[1]. pObject & 0x80000000) { MSG_WAR (0x3960, "Not a valid PDO ", 0x1800 + pdoNum); /*Go next TPDO */ status = state11; break; } /* get the PDO transmission type */ pTransmissionType = (UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject; MSG_WAR (0x3962, "Reading PDO at index : ", 0x1800 + pdoNum); /* check if transmission type is SYNCRONOUS */ /* message transmited every n SYNC with n=TransmissionType */ if (isSyncEvent && (*pTransmissionType >= TRANS_SYNC_MIN) && (*pTransmissionType <= TRANS_SYNC_MAX) && (++d->PDO_status[pdoNum].transmit_type_parameter == *pTransmissionType)) { /*Reset count of SYNC */ d->PDO_status[pdoNum].transmit_type_parameter = 0; MSG_WAR (0x3964, " PDO is on SYNCHRO. Trans type : ", *pTransmissionType); memset(&pdo, 0, sizeof(pdo)); /*{ Message msg_init = Message_Initializer; pdo = msg_init; }*/ if (buildPDO (d, pdoNum, &pdo)) { MSG_ERR (0x1906, " Couldn't build TPDO number : ", pdoNum); status = state11; break; } status = state5; /* If transmission RTR, with data sampled on SYNC */ } else if (isSyncEvent && (*pTransmissionType == TRANS_RTR_SYNC)) { if (buildPDO (d, pdoNum, &d->PDO_status[pdoNum].last_message)) { MSG_ERR (0x1966, " Couldn't build TPDO number : ", pdoNum); d->PDO_status[pdoNum].transmit_type_parameter &= ~PDO_RTR_SYNC_READY; } else { d->PDO_status[pdoNum].transmit_type_parameter |= PDO_RTR_SYNC_READY; } status = state11; break; /* If transmission on Event and not inhibited, check for changes */ } else if ( (isSyncEvent && (*pTransmissionType == TRANS_SYNC_ACYCLIC)) || (!isSyncEvent && (*pTransmissionType == TRANS_EVENT_PROFILE || *pTransmissionType == TRANS_EVENT_SPECIFIC) && !(d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED))) { sendOnePDOevent(d, pdoNum); status = state11; } else { MSG_WAR (0x306C, " PDO is not on EVENT or synchro or not at this SYNC. Trans type : ", *pTransmissionType); status = state11; } break; case state5: /*Send the pdo */ sendPdo(d, pdoNum, &pdo); status = state11; break; case state11: /*Go to next TPDO */ pdoNum++; offsetObjdict++; offsetObjdictMap++; MSG_WAR (0x3970, "next pdo index : ", pdoNum); status = state3; break; default: MSG_ERR (0x1972, "Unknown state has been reached : %d", status); return 0xFF; } /* end switch case */ } /* end while */ } return 0; }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74UNS8 sendOnePDOevent (CO_Data * d, UNS8 pdoNum) { UNS16 offsetObjdict; Message pdo; if (!d->CurrentCommunicationState.csPDO || (d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED)) { return 0; } offsetObjdict = (UNS16) (d->firstIndex->PDO_TRS + pdoNum); MSG_WAR (0x3968, " PDO is on EVENT. Trans type : ", *((UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject)); memset(&pdo, 0, sizeof(pdo)); if (buildPDO (d, pdoNum, &pdo)) { MSG_ERR (0x3907, " Couldn't build TPDO number : ", pdoNum); return 0; } /*Compare new and old PDO */ if (d->PDO_status[pdoNum].last_message.cob_id == pdo.cob_id && d->PDO_status[pdoNum].last_message.len == pdo.len && memcmp(d->PDO_status[pdoNum].last_message.data, pdo.data, 8) == 0 ) { /* No changes -> go to next pdo */ return 0; } else { TIMEVAL EventTimerDuration; TIMEVAL InhibitTimerDuration; MSG_WAR (0x306A, "Changes TPDO number : ", pdoNum); /* Changes detected -> transmit message */ EventTimerDuration = *(UNS16 *) d->objdict[offsetObjdict].pSubindex[5]. pObject; InhibitTimerDuration = *(UNS16 *) d->objdict[offsetObjdict].pSubindex[3]. pObject; /* Start both event_timer and inhibit_timer */ if (EventTimerDuration) { DelAlarm (d->PDO_status[pdoNum].event_timer); d->PDO_status[pdoNum].event_timer = SetAlarm (d, pdoNum, &PDOEventTimerAlarm, MS_TO_TIMEVAL (EventTimerDuration), 0); } if (InhibitTimerDuration) { DelAlarm (d->PDO_status[pdoNum].inhibit_timer); d->PDO_status[pdoNum].inhibit_timer = SetAlarm (d, pdoNum, &PDOInhibitTimerAlarm, US_TO_TIMEVAL (InhibitTimerDuration * 100), 0); /* and inhibit TPDO */ d->PDO_status[pdoNum].transmit_type_parameter |= PDO_INHIBITED; } sendPdo(d, pdoNum, &pdo); } return 1; }
复制代码
1
2
3
4
5
6
7
8
9
10static void sendPdo(CO_Data * d, UNS32 pdoNum, Message * pdo) { /*store_as_last_message */ d->PDO_status[pdoNum].last_message = *pdo; MSG_WAR (0x396D, "sendPDO cobId :", UNS16_LE(pdo->cob_id)); MSG_WAR (0x396E, " Nb octets : ", pdo->len); canSend (d->canHandle, pdo); }
最后调用底层的函数将PDO的数据发送出去。
最后
以上就是幸福小鸭子最近收集整理的关于02_同步对象SYNC的全部内容,更多相关02_同步对象SYNC内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复