flexPTP 1.0
An IEEE 1588 PTP implementation designed for microcontrollers
Loading...
Searching...
No Matches
bmca.c
Go to the documentation of this file.
1#include "bmca.h"
2
3#include "clock_utils.h"
4#include "event.h"
5#include "format_utils.h"
6#include "ptp_core.h"
7#include "ptp_defs.h"
8#include "ptp_types.h"
9#include "task_ptp.h"
10
11#include <flexptp_options.h>
12#include <stdint.h>
13#include <string.h>
14
16// global state
17#define S (gPtpCoreState)
19
20// ------------
21
22#define COMPARE_AND_RETURN(pmp1, pmp2, field) \
23 { \
24 if (pmp1->field < pmp2->field) { \
25 return 0; \
26 } else if (pmp1->field > pmp2->field) { \
27 return 1; \
28 } \
29 }
30
32 COMPARE_AND_RETURN(pMP1, pMP2, priority1);
33 COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockClass);
34 COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockAccuracy);
35 COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockVariance);
36 COMPARE_AND_RETURN(pMP1, pMP2, priority2);
37 COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockIdentity);
38 return 1;
39}
40
41static char *BMCA_HINTS[] = {
42 "INITIALIZING",
43 "LISTENING",
44 "PRE_MASTER",
45 "MASTER",
46 "SLAVE",
47 "PASSIVE",
48 "UNCALIBRATED",
49 "FAULTY",
50 "DISABLED"};
51
52#define SBMC_PRINT_LOG(p, c) \
53 if (S.logging.bmca) \
54 MSG("%s -> %s\n", BMCA_HINTS[(p)], BMCA_HINTS[(c)]);
55
56// handle possible state change
58 if (S.bmca.state != state) {
59 // print log
60 SBMC_PRINT_LOG(S.bmca.state, state);
61
62 // store state
63 S.bmca.stateDuration = 0;
64 S.bmca.state = state;
65
66 // dispatch event
67 PtpCoreEvent event = {.code = PTP_CEV_BMCA_STATE_CHANGED, .w = state, .dw = 0};
68 ptp_event_enqueue(&event);
69 }
70}
71
73 PtpBmcaFsmState state = S.bmca.state;
74 uint32_t sd = S.bmca.stateDuration;
75 bool master_mode_enabled = PTP_ENABLE_MASTER_OPERATION && (!(S.profile.flags & PTP_PF_SLAVE_ONLY));
76
77 uint64_t bmCI, ourCI;
78 bmCI = S.bmca.masterProps.grandmasterClockIdentity;
79 ourCI = S.capabilities.grandmasterClockIdentity;
80
81 switch (state) {
83 state = PTP_BMCA_LISTENING; // next state should be LISTENING
84
85 if (master_mode_enabled) { // if master operation is enabled
86 S.bmca.masterProps = S.capabilities; // in the beginning, let's assume we're the best master
87 }
88 } break;
89 case PTP_BMCA_LISTENING: {
90 if (sd > (PTP_BMCA_LISTENING_TIMEOUT_MS / PTP_HEARTBEAT_TICKRATE_MS)) { // if the LISTENING state residence time has expired...
91 if (master_mode_enabled && (bmCI == ourCI)) { // if it's us who takes the MASTER role...
92 state = PTP_BMCA_PRE_MASTER;
93 } else { // if we should follow a remote master
94 if ((bmCI != ourCI) && (bmCI != ~((uint64_t)0)) && (bmCI != 0)) { // us as a master and extrema cases exluded
95 state = PTP_BMCA_UNCALIBRATED; // leave only listening state if some remote master has ennounced itself
96 }
97 }
98 }
99 } break;
100 case PTP_BMCA_PRE_MASTER: {
101 if (sd > (PTP_MASTER_QUALIFICATION_TIMEOUT * ptp_logi2ms(S.profile.logAnnouncePeriod) / PTP_HEARTBEAT_TICKRATE_MS)) {
102 state = PTP_BMCA_MASTER;
103 }
104 } break;
106 state = PTP_BMCA_SLAVE;
107 } break;
108 case PTP_BMCA_SLAVE: {
109 if (S.bmca.masterTOCntr++ > (PTP_ANNOUNCE_RECEIPT_TIMEOUT * S.bmca.masterAnnPer_ms / PTP_HEARTBEAT_TICKRATE_MS)) { // if a master dropout is detected
110 if (master_mode_enabled) {
111 S.bmca.masterProps = S.capabilities; // let's assume we are the best MASTER for this time
112 } else {
113 memset(&S.bmca.masterProps, 0xFF, sizeof(PtpMasterProperties)); // fill the master properties with the worst values regarding the comparison
114 }
115 state = PTP_BMCA_LISTENING;
116 }
117 } break;
118 default:
119 break;
120 }
121
122 // increase state duration
123 S.bmca.stateDuration++;
124
125 // handle possible state change
127}
128
136 PtpBmcaState *s = &(S.bmca);
137 bool masterChanged = false;
138 PtpBmcaFsmState state = s->state;
139 bool master_mode_enabled = PTP_ENABLE_MASTER_OPERATION && (!(S.profile.flags & PTP_PF_SLAVE_ONLY));
140
141 switch (state) {
143 if (master_mode_enabled) { // if master operation is enabled...
144 if (ptp_select_better_master(pAnn, &(s->masterProps)) == 0) { // compare the new master to the best one we've discovered so far
145 s->masterProps = *pAnn; // store remote master's capabilities if it's better then the former one
146 masterChanged = true; // signal that master has changed
147 }
148 } else { // slave only operation
149 s->masterProps = *pAnn; // retain remote master capabilities
150 state = PTP_BMCA_UNCALIBRATED; // change to uncalibrated state
151 masterChanged = true; // ...
152 }
153 break;
155 case PTP_BMCA_MASTER:
156 case PTP_BMCA_SLAVE: {
157 // if a better master is found, then switch over
158 if (ptp_select_better_master(pAnn, &(s->masterProps)) == 0) {
159 s->masterProps = *pAnn;
160 state = PTP_BMCA_UNCALIBRATED;
161 masterChanged = true;
162 }
163
164 // update UTC offset if necessary
165 if (pAnn->currentUTCOffset > S.capabilities.currentUTCOffset) {
166 S.capabilities.currentUTCOffset = pAnn->currentUTCOffset;
167 }
168 } break;
169 default:
170 break;
171 }
172
173 // if master has changed, then calculate Announce period
174 if (masterChanged) {
175 S.bmca.masterTOCntr = 0;
177 }
178
179 // clear Master timeout if relevant Announce has arrived
181 if (s->masterProps.currentUTCOffset != pAnn->currentUTCOffset) { // update current UTC offset
183 }
184 S.bmca.masterTOCntr = 0;
185 }
186
187 // handle possible state change
189}
190
192 // initialize device capabilities
193 PtpMasterProperties *caps = &S.capabilities;
200 caps->grandmasterClockIdentity = S.hwoptions.clockIdentity;
201 caps->localStepsRemoved = 0;
203}
204
206 return;
207}
208
210 memset(&S.bmca, 0, sizeof(PtpBmcaState)); // SBMC state
211 S.bmca.state = PTP_BMCA_INITIALIZING;
212}
void ptp_bmca_destroy()
Definition: bmca.c:205
void ptp_bmca_tick()
Definition: bmca.c:72
#define SBMC_PRINT_LOG(p, c)
Definition: bmca.c:52
#define COMPARE_AND_RETURN(pmp1, pmp2, field)
Definition: bmca.c:22
static void ptp_bmca_handle_state_change(PtpBmcaFsmState state)
Definition: bmca.c:57
void ptp_bmca_init()
Definition: bmca.c:191
void ptp_bmca_reset()
Definition: bmca.c:209
static char * BMCA_HINTS[]
Definition: bmca.c:41
void ptp_handle_announce_msg(PtpAnnounceBody *pAnn, PtpHeader *pHeader)
Definition: bmca.c:135
int ptp_select_better_master(PtpMasterProperties *pMP1, PtpMasterProperties *pMP2)
Definition: bmca.c:31
This module implements the Best Master Clock Algorithm.
This module defines clock identity related operations.
In this module are the core and user events defined.
@ PTP_CEV_BMCA_STATE_CHANGED
Definition: event.h:16
uint16_t ptp_logi2ms(int8_t logi)
Definition: format_utils.c:14
This module defines format conversion functions between network and host byte order and conversion fu...
Core of the PTP implementation. Defines functions for message processing, clock tuning,...
In here reside a multitude of fundamental PTP-related constants and definitions.
#define PTP_HEARTBEAT_TICKRATE_MS
Heartbeat ticking period.
Definition: ptp_defs.h:69
#define PTP_MASTER_QUALIFICATION_TIMEOUT
Number of Announce intervals.
Definition: ptp_defs.h:93
#define PTP_CLOCK_PRIORITY2
Clock priority2.
Definition: ptp_defs.h:109
#define PTP_ANNOUNCE_RECEIPT_TIMEOUT
Number of tolerated consecutive lost Announce messages.
Definition: ptp_defs.h:97
#define PTP_CLOCK_PRIORITY1
Clock priority1.
Definition: ptp_defs.h:105
#define PTP_BMCA_LISTENING_TIMEOUT_MS
BMCA LISTENING state timeout.
Definition: ptp_defs.h:89
#define PTP_TIME_SOURCE
Time source of this device.
Definition: ptp_defs.h:123
#define PTP_ENABLE_MASTER_OPERATION
By default, disable Master operation mode.
Definition: ptp_defs.h:101
#define PTP_WORST_ACCURACY
Worst accuracy of this device.
Definition: ptp_defs.h:119
#define PTP_FALLBACK_UTC_OFFSET
UTC offset caused by the accumulated leap seconds.
Definition: ptp_defs.h:127
#define PTP_BEST_CLOCK_CLASS
Best clock class of this device.
Definition: ptp_defs.h:115
This module defines the fundamental PTP message and state machine type, flags, bitfields and the PTP ...
PtpBmcaFsmState
Definition: ptp_types.h:284
@ PTP_BMCA_UNCALIBRATED
Definition: ptp_types.h:291
@ PTP_BMCA_MASTER
Definition: ptp_types.h:288
@ PTP_BMCA_LISTENING
Definition: ptp_types.h:286
@ PTP_BMCA_SLAVE
Definition: ptp_types.h:289
@ PTP_BMCA_INITIALIZING
Definition: ptp_types.h:285
@ PTP_BMCA_PRE_MASTER
Definition: ptp_types.h:287
#define PTP_VARIANCE_HAS_NOT_BEEN_COMPUTED
Definition: ptp_types.h:231
@ PTP_PF_SLAVE_ONLY
Operating only in SLAVE mode.
Definition: ptp_types.h:324
Contents of a PTP Announce message without the common PTP header.
Definition: ptp_types.h:236
uint16_t currentUTCOffset
Current UTC Offset.
Definition: ptp_types.h:237
uint64_t grandmasterClockIdentity
Grandmaster Clock Identity.
Definition: ptp_types.h:243
uint8_t grandmasterClockClass
Grandmaster Clock Class.
Definition: ptp_types.h:239
uint8_t grandmasterClockAccuracy
Grandmaster Clock Accuracy.
Definition: ptp_types.h:240
uint16_t localStepsRemoved
Local Steps Removed.
Definition: ptp_types.h:244
uint16_t grandmasterClockVariance
Grandmaster Clock Variance.
Definition: ptp_types.h:241
uint8_t priority2
Priority 2.
Definition: ptp_types.h:242
uint8_t timeSource
Time Source.
Definition: ptp_types.h:245
uint8_t priority1
Priority 1.
Definition: ptp_types.h:238
BMCA state.
Definition: ptp_types.h:299
PtpMasterProperties masterProps
Master clock properties.
Definition: ptp_types.h:301
PtpBmcaFsmState state
BMCA state.
Definition: ptp_types.h:300
uint16_t masterAnnPer_ms
Message period of current master.
Definition: ptp_types.h:302
uint16_t code
Event code.
Definition: event.h:21
PTP message header structure.
Definition: ptp_types.h:73
int8_t logMessagePeriod
Definition: ptp_types.h:114
bool ptp_event_enqueue(const PtpCoreEvent *event)
Definition: task_ptp.c:136
The entry point of the whole PTP-implementation. Calling reg_task_ptp() initializes the PTP-engine,...