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 CLILOG(S.logging.logid, "[LOG-BMCA] ") \
55 MSG("%s -> %s\n", BMCA_HINTS[(p)], BMCA_HINTS[(c)]); \
56 }
57
58// handle possible state change
60 if (S.bmca.state != state) {
61 // print log
62 SBMC_PRINT_LOG(S.bmca.state, state);
63
64 // store state
65 S.bmca.stateDuration = 0;
66 S.bmca.state = state;
67
68 // dispatch event
69 PtpCoreEvent event = {.code = PTP_CEV_BMCA_STATE_CHANGED, .w = state, .dw = 0};
70 ptp_event_enqueue(&event);
71 }
72}
73
75 PtpBmcaFsmState state = S.bmca.state;
76 uint32_t sd = S.bmca.stateDuration;
77 bool master_mode_enabled = PTP_ENABLE_MASTER_OPERATION && (!(S.profile.flags & PTP_PF_SLAVE_ONLY));
78
79 uint64_t bmCI, ourCI;
80 bmCI = S.bmca.masterProps.grandmasterClockIdentity;
81 ourCI = S.capabilities.grandmasterClockIdentity;
82
83 switch (state) {
85 state = PTP_BMCA_LISTENING; // next state should be LISTENING
86
87 if (master_mode_enabled) { // if master operation is enabled
88 S.bmca.masterProps = S.capabilities; // in the beginning, let's assume we're the best master
89 }
90 } break;
91 case PTP_BMCA_LISTENING: {
92 if (sd > (PTP_BMCA_LISTENING_TIMEOUT_MS / PTP_HEARTBEAT_TICKRATE_MS)) { // if the LISTENING state residence time has expired...
93 if (master_mode_enabled && (bmCI == ourCI)) { // if it's us who takes the MASTER role...
94 state = PTP_BMCA_PRE_MASTER;
95 } else { // if we should follow a remote master
96 if ((bmCI != ourCI) && (bmCI != ~((uint64_t)0)) && (bmCI != 0)) { // us as a master and extrema cases exluded
97 state = PTP_BMCA_UNCALIBRATED; // leave only listening state if some remote master has ennounced itself
98 }
99 }
100 }
101 } break;
102 case PTP_BMCA_PRE_MASTER: {
103 if (sd > (PTP_MASTER_QUALIFICATION_TIMEOUT * ptp_logi2ms(S.profile.logAnnouncePeriod) / PTP_HEARTBEAT_TICKRATE_MS)) {
104 state = PTP_BMCA_MASTER;
105 }
106 } break;
108 state = PTP_BMCA_SLAVE;
109 } break;
110 case PTP_BMCA_SLAVE: {
111 if (S.bmca.masterTOCntr++ > (PTP_ANNOUNCE_RECEIPT_TIMEOUT * S.bmca.masterAnnPer_ms / PTP_HEARTBEAT_TICKRATE_MS)) { // if a master dropout is detected
112 if (master_mode_enabled) {
113 S.bmca.masterProps = S.capabilities; // let's assume we are the best MASTER for this time
114 } else {
115 memset(&S.bmca.masterProps, 0xFF, sizeof(PtpMasterProperties)); // fill the master properties with the worst values regarding the comparison
116 }
117 state = PTP_BMCA_LISTENING;
118 }
119 } break;
120 default:
121 break;
122 }
123
124 // increase state duration
125 S.bmca.stateDuration++;
126
127 // handle possible state change
129}
130
138 PtpBmcaState *s = &(S.bmca);
139 bool masterChanged = false;
140 PtpBmcaFsmState state = s->state;
141 bool master_mode_enabled = PTP_ENABLE_MASTER_OPERATION && (!(S.profile.flags & PTP_PF_SLAVE_ONLY));
142
143 switch (state) {
145 if (master_mode_enabled) { // if master operation is enabled...
146 if (ptp_select_better_master(pAnn, &(s->masterProps)) == 0) { // compare the new master to the best one we've discovered so far
147 s->masterProps = *pAnn; // store remote master's capabilities if it's better then the former one
148 masterChanged = true; // signal that master has changed
149 }
150 } else { // slave only operation
151 s->masterProps = *pAnn; // retain remote master capabilities
152 state = PTP_BMCA_UNCALIBRATED; // change to uncalibrated state
153 masterChanged = true; // ...
154 }
155 break;
157 case PTP_BMCA_MASTER:
158 case PTP_BMCA_SLAVE: {
159 // if a better master is found, then switch over
160 if (ptp_select_better_master(pAnn, &(s->masterProps)) == 0) {
161 s->masterProps = *pAnn;
162 state = PTP_BMCA_UNCALIBRATED;
163 masterChanged = true;
164 }
165
166 // update UTC offset if necessary
167 if (pAnn->currentUTCOffset > S.capabilities.currentUTCOffset) {
168 S.capabilities.currentUTCOffset = pAnn->currentUTCOffset;
169 }
170 } break;
171 default:
172 break;
173 }
174
175 // if master has changed, then calculate Announce period
176 if (masterChanged) {
177 S.bmca.masterTOCntr = 0;
179 }
180
181 // clear Master timeout if relevant Announce has arrived
183 if (s->masterProps.currentUTCOffset != pAnn->currentUTCOffset) { // update current UTC offset
185 }
186 S.bmca.masterTOCntr = 0;
187 }
188
189 // handle possible state change
191}
192
194 // initialize device capabilities
195 PtpMasterProperties *caps = &S.capabilities;
202 caps->grandmasterClockIdentity = S.hwoptions.clockIdentity;
203 caps->localStepsRemoved = 0;
205}
206
208 return;
209}
210
212 memset(&S.bmca, 0, sizeof(PtpBmcaState)); // SBMC state
213 S.bmca.state = PTP_BMCA_INITIALIZING;
214}
void ptp_bmca_destroy()
Definition: bmca.c:207
void ptp_bmca_tick()
Definition: bmca.c:74
#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:59
void ptp_bmca_init()
Definition: bmca.c:193
void ptp_bmca_reset()
Definition: bmca.c:211
static char * BMCA_HINTS[]
Definition: bmca.c:41
void ptp_handle_announce_msg(PtpAnnounceBody *pAnn, PtpHeader *pHeader)
Definition: bmca.c:137
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
The BMCA state has changed.
Definition: event.h:20
#define PTP_CLOCK_PRIORITY2
#define PTP_CLOCK_PRIORITY1
#define PTP_TIME_SOURCE
#define PTP_ENABLE_MASTER_OPERATION
#define PTP_WORST_ACCURACY
#define PTP_BEST_CLOCK_CLASS
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:128
#define PTP_MASTER_QUALIFICATION_TIMEOUT
Number of Announce intervals.
Definition: ptp_defs.h:152
#define PTP_ANNOUNCE_RECEIPT_TIMEOUT
Number of tolerated consecutive lost Announce messages.
Definition: ptp_defs.h:156
#define PTP_BMCA_LISTENING_TIMEOUT_MS
BMCA LISTENING state timeout.
Definition: ptp_defs.h:148
#define PTP_FALLBACK_UTC_OFFSET
UTC offset caused by the accumulated leap seconds.
Definition: ptp_defs.h:186
This module defines the fundamental PTP message and state machine type, flags, bitfields and the PTP ...
PtpBmcaFsmState
Definition: ptp_types.h:310
@ PTP_BMCA_UNCALIBRATED
Definition: ptp_types.h:317
@ PTP_BMCA_MASTER
Definition: ptp_types.h:314
@ PTP_BMCA_LISTENING
Definition: ptp_types.h:312
@ PTP_BMCA_SLAVE
Definition: ptp_types.h:315
@ PTP_BMCA_INITIALIZING
Definition: ptp_types.h:311
@ PTP_BMCA_PRE_MASTER
Definition: ptp_types.h:313
#define PTP_VARIANCE_HAS_NOT_BEEN_COMPUTED
Definition: ptp_types.h:257
@ PTP_PF_SLAVE_ONLY
Operating only in SLAVE mode.
Definition: ptp_types.h:350
Contents of a PTP Announce message without the common PTP header.
Definition: ptp_types.h:262
uint16_t currentUTCOffset
Current UTC Offset.
Definition: ptp_types.h:263
uint64_t grandmasterClockIdentity
Grandmaster Clock Identity.
Definition: ptp_types.h:269
uint8_t grandmasterClockClass
Grandmaster Clock Class.
Definition: ptp_types.h:265
uint8_t grandmasterClockAccuracy
Grandmaster Clock Accuracy.
Definition: ptp_types.h:266
uint16_t localStepsRemoved
Local Steps Removed.
Definition: ptp_types.h:270
uint16_t grandmasterClockVariance
Grandmaster Clock Variance.
Definition: ptp_types.h:267
uint8_t priority2
Priority 2.
Definition: ptp_types.h:268
uint8_t timeSource
Time Source.
Definition: ptp_types.h:271
uint8_t priority1
Priority 1.
Definition: ptp_types.h:264
BMCA state.
Definition: ptp_types.h:325
PtpMasterProperties masterProps
Master clock properties.
Definition: ptp_types.h:327
PtpBmcaFsmState state
BMCA state.
Definition: ptp_types.h:326
uint16_t masterAnnPer_ms
Message period of current master.
Definition: ptp_types.h:328
uint16_t code
Event code.
Definition: event.h:27
PTP message header structure.
Definition: ptp_types.h:81
int8_t logMessagePeriod
Definition: ptp_types.h:122
bool ptp_event_enqueue(const PtpCoreEvent *event)
Definition: task_ptp.c:445
The entry point of the whole PTP-implementation. Calling reg_task_ptp() initializes the PTP-engine,...