2025-09-30 11:56:06 +08:00
|
|
|
/* bmc.c */
|
|
|
|
|
|
|
|
|
|
#include "ptpd.h"
|
|
|
|
|
|
|
|
|
|
/* Convert EUI48 format to EUI64 */
|
|
|
|
|
void EUI48toEUI64(const octet_t * eui48, octet_t * eui64)
|
|
|
|
|
{
|
|
|
|
|
eui64[0] = eui48[0];
|
|
|
|
|
eui64[1] = eui48[1];
|
|
|
|
|
eui64[2] = eui48[2];
|
|
|
|
|
eui64[3] = 0xff;
|
|
|
|
|
eui64[4] = 0xfe;
|
|
|
|
|
eui64[5] = eui48[3];
|
|
|
|
|
eui64[6] = eui48[4];
|
|
|
|
|
eui64[7] = eui48[5];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Init ptpClock with run time values (initialization constants are in constants.h) */
|
|
|
|
|
void initData(PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
RunTimeOpts * rtOpts;
|
|
|
|
|
|
|
|
|
|
DBG("initData\n");
|
|
|
|
|
rtOpts = ptpClock->rtOpts;
|
|
|
|
|
|
|
|
|
|
/* Default data set */
|
|
|
|
|
ptpClock->defaultDS.twoStepFlag = DEFAULT_TWO_STEP_FLAG;
|
|
|
|
|
|
|
|
|
|
/* Init clockIdentity with MAC address and 0xFF and 0xFE. see spec 7.5.2.2.2 */
|
|
|
|
|
if ((CLOCK_IDENTITY_LENGTH == 8) && (PTP_UUID_LENGTH == 6))
|
|
|
|
|
{
|
|
|
|
|
DBGVV("initData: EUI48toEUI64\n");
|
|
|
|
|
EUI48toEUI64(ptpClock->portUuidField, ptpClock->defaultDS.clockIdentity);
|
|
|
|
|
}
|
|
|
|
|
else if (CLOCK_IDENTITY_LENGTH == PTP_UUID_LENGTH)
|
|
|
|
|
{
|
|
|
|
|
memcpy(ptpClock->defaultDS.clockIdentity, ptpClock->portUuidField, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ERROR("initData: UUID length is not valid");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptpClock->defaultDS.numberPorts = NUMBER_PORTS;
|
|
|
|
|
|
|
|
|
|
ptpClock->defaultDS.clockQuality.clockAccuracy = rtOpts->clockQuality.clockAccuracy;
|
|
|
|
|
ptpClock->defaultDS.clockQuality.clockClass = rtOpts->clockQuality.clockClass;
|
|
|
|
|
ptpClock->defaultDS.clockQuality.offsetScaledLogVariance = rtOpts->clockQuality.offsetScaledLogVariance;
|
|
|
|
|
|
|
|
|
|
ptpClock->defaultDS.priority1 = rtOpts->priority1;
|
|
|
|
|
ptpClock->defaultDS.priority2 = rtOpts->priority2;
|
|
|
|
|
|
|
|
|
|
ptpClock->defaultDS.domainNumber = rtOpts->domainNumber;
|
|
|
|
|
ptpClock->defaultDS.slaveOnly = rtOpts->slaveOnly;
|
|
|
|
|
|
|
|
|
|
/* Port configuration data set */
|
|
|
|
|
|
|
|
|
|
/* PortIdentity Init (portNumber = 1 for an ardinary clock spec 7.5.2.3)*/
|
|
|
|
|
memcpy(ptpClock->portDS.portIdentity.clockIdentity, ptpClock->defaultDS.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->portDS.portIdentity.portNumber = NUMBER_PORTS;
|
|
|
|
|
ptpClock->portDS.logMinDelayReqInterval = DEFAULT_DELAYREQ_INTERVAL;
|
|
|
|
|
ptpClock->portDS.peerMeanPathDelay.seconds = ptpClock->portDS.peerMeanPathDelay.nanoseconds = 0;
|
|
|
|
|
ptpClock->portDS.logAnnounceInterval = rtOpts->announceInterval;
|
|
|
|
|
ptpClock->portDS.announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
|
|
|
|
|
ptpClock->portDS.logSyncInterval = rtOpts->syncInterval;
|
|
|
|
|
ptpClock->portDS.delayMechanism = rtOpts->delayMechanism;
|
|
|
|
|
ptpClock->portDS.logMinPdelayReqInterval = DEFAULT_PDELAYREQ_INTERVAL;
|
|
|
|
|
ptpClock->portDS.versionNumber = VERSION_PTP;
|
|
|
|
|
|
|
|
|
|
/* Init other stuff */
|
|
|
|
|
ptpClock->foreignMasterDS.count = 0;
|
|
|
|
|
ptpClock->foreignMasterDS.capacity = rtOpts->maxForeignRecords;
|
|
|
|
|
|
|
|
|
|
ptpClock->inboundLatency = rtOpts->inboundLatency;
|
|
|
|
|
ptpClock->outboundLatency = rtOpts->outboundLatency;
|
|
|
|
|
|
|
|
|
|
ptpClock->servo.sDelay = rtOpts->servo.sDelay;
|
|
|
|
|
ptpClock->servo.sOffset = rtOpts->servo.sOffset;
|
|
|
|
|
ptpClock->servo.ai = rtOpts->servo.ai;
|
|
|
|
|
ptpClock->servo.ap = rtOpts->servo.ap;
|
|
|
|
|
ptpClock->servo.noAdjust = rtOpts->servo.noAdjust;
|
|
|
|
|
ptpClock->servo.noResetClock = rtOpts->servo.noResetClock;
|
|
|
|
|
|
|
|
|
|
ptpClock->stats = rtOpts->stats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isSamePortIdentity(const PortIdentity * A, const PortIdentity * B)
|
|
|
|
|
{
|
|
|
|
|
return (bool)(0 == memcmp(A->clockIdentity, B->clockIdentity, CLOCK_IDENTITY_LENGTH) && (A->portNumber == B->portNumber));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addForeign(PtpClock *ptpClock, const MsgHeader *header, const MsgAnnounce * announce)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
bool found = FALSE;
|
|
|
|
|
|
|
|
|
|
j = ptpClock->foreignMasterDS.best;
|
|
|
|
|
|
|
|
|
|
/* Check if Foreign master is already known */
|
|
|
|
|
for (i = 0; i < ptpClock->foreignMasterDS.count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (isSamePortIdentity(&header->sourcePortIdentity, &ptpClock->foreignMasterDS.records[j].foreignMasterPortIdentity))
|
|
|
|
|
{
|
|
|
|
|
/* Foreign Master is already in Foreignmaster data set */
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].foreignMasterAnnounceMessages++;
|
|
|
|
|
found = TRUE;
|
|
|
|
|
DBGV("addForeign: AnnounceMessage incremented \n");
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].header = *header;
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].announce = *announce;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j = (j + 1) % ptpClock->foreignMasterDS.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* New Foreign Master */
|
|
|
|
|
if (!found)
|
|
|
|
|
{
|
|
|
|
|
if (ptpClock->foreignMasterDS.count < ptpClock->foreignMasterDS.capacity)
|
|
|
|
|
{
|
|
|
|
|
ptpClock->foreignMasterDS.count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j = ptpClock->foreignMasterDS.i;
|
|
|
|
|
|
|
|
|
|
/* Copy new foreign master data set from Announce message */
|
|
|
|
|
memcpy(ptpClock->foreignMasterDS.records[j].foreignMasterPortIdentity.clockIdentity, header->sourcePortIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].foreignMasterPortIdentity.portNumber = header->sourcePortIdentity.portNumber;
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].foreignMasterAnnounceMessages = 0;
|
|
|
|
|
|
|
|
|
|
/* Header and announce field of each Foreign Master are usefull to run Best Master Clock Algorithm */
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].header = *header;
|
|
|
|
|
ptpClock->foreignMasterDS.records[j].announce = *announce;
|
|
|
|
|
DBGV("addForeign: New foreign Master added \n");
|
|
|
|
|
|
|
|
|
|
ptpClock->foreignMasterDS.i = (ptpClock->foreignMasterDS.i + 1) % ptpClock->foreignMasterDS.capacity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define m2 m1
|
|
|
|
|
|
|
|
|
|
/* Local clock is becoming Master. Table 13 (9.3.5) of the spec.*/
|
|
|
|
|
void m1(PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
DBGV("bmc: m1\n");
|
|
|
|
|
|
|
|
|
|
/* Current data set update */
|
|
|
|
|
ptpClock->currentDS.stepsRemoved = 0;
|
|
|
|
|
ptpClock->currentDS.offsetFromMaster.seconds = ptpClock->currentDS.offsetFromMaster.nanoseconds = 0;
|
|
|
|
|
ptpClock->currentDS.meanPathDelay.seconds = ptpClock->currentDS.meanPathDelay.nanoseconds = 0;
|
|
|
|
|
|
|
|
|
|
/* Parent data set */
|
|
|
|
|
memcpy(ptpClock->parentDS.parentPortIdentity.clockIdentity, ptpClock->defaultDS.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->parentDS.parentPortIdentity.portNumber = 0;
|
|
|
|
|
memcpy(ptpClock->parentDS.grandmasterIdentity, ptpClock->defaultDS.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.clockAccuracy = ptpClock->defaultDS.clockQuality.clockAccuracy;
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.clockClass = ptpClock->defaultDS.clockQuality.clockClass;
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.offsetScaledLogVariance = ptpClock->defaultDS.clockQuality.offsetScaledLogVariance;
|
|
|
|
|
ptpClock->parentDS.grandmasterPriority1 = ptpClock->defaultDS.priority1;
|
|
|
|
|
ptpClock->parentDS.grandmasterPriority2 = ptpClock->defaultDS.priority2;
|
|
|
|
|
|
|
|
|
|
/* Time Properties data set */
|
|
|
|
|
ptpClock->timePropertiesDS.currentUtcOffset = ptpClock->rtOpts->currentUtcOffset;
|
|
|
|
|
ptpClock->timePropertiesDS.currentUtcOffsetValid = DEFAULT_UTC_VALID;
|
|
|
|
|
ptpClock->timePropertiesDS.leap59 = FALSE;
|
|
|
|
|
ptpClock->timePropertiesDS.leap61 = FALSE;
|
|
|
|
|
ptpClock->timePropertiesDS.timeTraceable = DEFAULT_TIME_TRACEABLE;
|
|
|
|
|
ptpClock->timePropertiesDS.frequencyTraceable = DEFAULT_FREQUENCY_TRACEABLE;
|
|
|
|
|
ptpClock->timePropertiesDS.ptpTimescale = (bool)(DEFAULT_TIMESCALE == PTP_TIMESCALE);
|
|
|
|
|
ptpClock->timePropertiesDS.timeSource = DEFAULT_TIME_SOURCE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void p1(PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
DBGV("bmc: p1\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Local clock is synchronized to Ebest Table 16 (9.3.5) of the spec */
|
|
|
|
|
void s1(PtpClock *ptpClock, const MsgHeader *header, const MsgAnnounce *announce)
|
|
|
|
|
{
|
|
|
|
|
bool isFromCurrentParent;
|
|
|
|
|
|
|
|
|
|
DBGV("bmc: s1\n");
|
|
|
|
|
|
|
|
|
|
/* Current DS */
|
|
|
|
|
ptpClock->currentDS.stepsRemoved = announce->stepsRemoved + 1;
|
|
|
|
|
|
|
|
|
|
isFromCurrentParent = isSamePortIdentity(&ptpClock->parentDS.parentPortIdentity, &header->sourcePortIdentity);
|
|
|
|
|
|
|
|
|
|
if (!isFromCurrentParent)
|
|
|
|
|
{
|
|
|
|
|
setFlag(ptpClock->events, MASTER_CLOCK_CHANGED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parent DS */
|
|
|
|
|
memcpy(ptpClock->parentDS.parentPortIdentity.clockIdentity, header->sourcePortIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->parentDS.parentPortIdentity.portNumber = header->sourcePortIdentity.portNumber;
|
|
|
|
|
memcpy(ptpClock->parentDS.grandmasterIdentity, announce->grandmasterIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.clockAccuracy = announce->grandmasterClockQuality.clockAccuracy;
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.clockClass = announce->grandmasterClockQuality.clockClass;
|
|
|
|
|
ptpClock->parentDS.grandmasterClockQuality.offsetScaledLogVariance = announce->grandmasterClockQuality.offsetScaledLogVariance;
|
|
|
|
|
ptpClock->parentDS.grandmasterPriority1 = announce->grandmasterPriority1;
|
|
|
|
|
ptpClock->parentDS.grandmasterPriority2 = announce->grandmasterPriority2;
|
|
|
|
|
|
|
|
|
|
/* Timeproperties DS */
|
|
|
|
|
ptpClock->timePropertiesDS.currentUtcOffset = announce->currentUtcOffset;
|
|
|
|
|
ptpClock->timePropertiesDS.currentUtcOffsetValid = getFlag(header->flagField[1], FLAG1_UTC_OFFSET_VALID);
|
|
|
|
|
ptpClock->timePropertiesDS.leap59 = getFlag(header->flagField[1], FLAG1_LEAP59);
|
|
|
|
|
ptpClock->timePropertiesDS.leap61 = getFlag(header->flagField[1], FLAG1_LEAP61);
|
|
|
|
|
ptpClock->timePropertiesDS.timeTraceable = getFlag(header->flagField[1], FLAG1_TIME_TRACEABLE);
|
|
|
|
|
ptpClock->timePropertiesDS.frequencyTraceable = getFlag(header->flagField[1], FLAG1_FREQUENCY_TRACEABLE);
|
|
|
|
|
ptpClock->timePropertiesDS.ptpTimescale = getFlag(header->flagField[1], FLAG1_PTP_TIMESCALE);
|
|
|
|
|
ptpClock->timePropertiesDS.timeSource = announce->timeSource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Copy local data set into header and announce message. 9.3.4 table 12
|
|
|
|
|
*/
|
|
|
|
|
void copyD0(MsgHeader *header, MsgAnnounce *announce, PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
announce->grandmasterPriority1 = ptpClock->defaultDS.priority1;
|
|
|
|
|
memcpy(announce->grandmasterIdentity, ptpClock->defaultDS.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
announce->grandmasterClockQuality.clockClass = ptpClock->defaultDS.clockQuality.clockClass;
|
|
|
|
|
announce->grandmasterClockQuality.clockAccuracy = ptpClock->defaultDS.clockQuality.clockAccuracy;
|
|
|
|
|
announce->grandmasterClockQuality.offsetScaledLogVariance = ptpClock->defaultDS.clockQuality.offsetScaledLogVariance;
|
|
|
|
|
announce->grandmasterPriority2 = ptpClock->defaultDS.priority2;
|
|
|
|
|
announce->stepsRemoved = 0;
|
|
|
|
|
memcpy(header->sourcePortIdentity.clockIdentity, ptpClock->defaultDS.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define A_better_then_B 1
|
|
|
|
|
#define B_better_then_A -1
|
|
|
|
|
#define A_better_by_topology_then_B 1
|
|
|
|
|
#define B_better_by_topology_then_A -1
|
|
|
|
|
#define ERROR_1 0
|
|
|
|
|
#define ERROR_2 -0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define COMPARE_AB_RETURN_BETTER(cond, msg) \
|
|
|
|
|
if ((announceA->cond) > (announceB->cond)) { \
|
|
|
|
|
DBGVV("bmcDataSetComparison: " msg ": B better then A\n"); \
|
|
|
|
|
return B_better_then_A; \
|
|
|
|
|
} \
|
|
|
|
|
if ((announceB->cond) > (announceA->cond)) { \
|
|
|
|
|
DBGVV("bmcDataSetComparison: " msg ": A better then B\n"); \
|
|
|
|
|
return A_better_then_B; \
|
|
|
|
|
} \
|
|
|
|
|
|
|
|
|
|
/* Data set comparison bewteen two foreign masters (9.3.4 fig 27) return similar to memcmp() */
|
|
|
|
|
int8_t bmcDataSetComparison(MsgHeader *headerA, MsgAnnounce *announceA,
|
|
|
|
|
MsgHeader *headerB, MsgAnnounce *announceB, PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
int grandmasterIdentityComp;
|
|
|
|
|
short comp = 0;
|
|
|
|
|
|
|
|
|
|
DBGV("bmcDataSetComparison\n");
|
|
|
|
|
/* Identity comparison */
|
|
|
|
|
|
|
|
|
|
/* GM identity of A == GM identity of B */
|
|
|
|
|
/* TODO: zkontrolovat memcmp, co vraci za vysledky !*/
|
|
|
|
|
grandmasterIdentityComp = memcmp(announceA->grandmasterIdentity, announceB->grandmasterIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
|
|
|
|
|
if (0 != grandmasterIdentityComp)
|
|
|
|
|
{
|
|
|
|
|
/* Algoritgm part 1 - Figure 27 */
|
|
|
|
|
COMPARE_AB_RETURN_BETTER(grandmasterPriority1,"grandmaster.Priority1");
|
|
|
|
|
COMPARE_AB_RETURN_BETTER(grandmasterClockQuality.clockClass,"grandmaster.clockClass");
|
|
|
|
|
COMPARE_AB_RETURN_BETTER(grandmasterClockQuality.clockAccuracy,"grandmaster.clockAccuracy");
|
|
|
|
|
COMPARE_AB_RETURN_BETTER(grandmasterClockQuality.offsetScaledLogVariance,"grandmaster.Variance");
|
|
|
|
|
COMPARE_AB_RETURN_BETTER(grandmasterPriority2,"grandmaster.Priority2");
|
|
|
|
|
|
|
|
|
|
if (grandmasterIdentityComp > 0)
|
|
|
|
|
{
|
|
|
|
|
DBGVV("bmcDataSetComparison: grandmaster.Identity: B better then A\n");
|
|
|
|
|
return B_better_then_A;
|
|
|
|
|
}
|
|
|
|
|
else if (grandmasterIdentityComp < 0)
|
|
|
|
|
{
|
|
|
|
|
DBGVV("bmcDataSetComparison: grandmaster.Identity: A better then B\n");
|
|
|
|
|
return A_better_then_B;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Algoritgm part 2 - Figure 28 */
|
|
|
|
|
if ((announceA->stepsRemoved) > (announceB->stepsRemoved + 1))
|
|
|
|
|
{
|
|
|
|
|
DBGVV("bmcDataSetComparison: stepsRemoved: B better then A\n");
|
|
|
|
|
return B_better_then_A;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((announceB->stepsRemoved) > (announceA->stepsRemoved + 1))
|
|
|
|
|
{
|
|
|
|
|
DBGVV("bmcDataSetComparison: stepsRemoved: A better then B\n");
|
|
|
|
|
return A_better_then_B;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((announceA->stepsRemoved) > (announceB->stepsRemoved))
|
|
|
|
|
{
|
|
|
|
|
comp = memcmp(headerA->sourcePortIdentity.clockIdentity, ptpClock->portDS.portIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
|
|
|
|
|
if (comp > 0)
|
|
|
|
|
{
|
|
|
|
|
/* reciever < sender */
|
|
|
|
|
DBGVV("bmcDataSetComparison: PortIdentity: B better then A\n");
|
|
|
|
|
return B_better_then_A;
|
|
|
|
|
}
|
|
|
|
|
else if (comp < 0)
|
|
|
|
|
{
|
|
|
|
|
/* reciever > sender */
|
|
|
|
|
DBGVV("bmcDataSetComparison: PortIdentity: B better by topology then A\n");
|
|
|
|
|
return B_better_by_topology_then_A;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DBGVV("bmcDataSetComparison: ERROR 1\n");
|
|
|
|
|
return ERROR_1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((announceA->stepsRemoved) < (announceB->stepsRemoved))
|
|
|
|
|
{
|
|
|
|
|
comp = memcmp(headerB->sourcePortIdentity.clockIdentity, ptpClock->portDS.portIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
if (comp > 0)
|
|
|
|
|
{
|
|
|
|
|
/* reciever < sender */
|
|
|
|
|
DBGVV("bmcDataSetComparison: PortIdentity: A better then B\n");
|
|
|
|
|
return A_better_then_B;
|
|
|
|
|
}
|
|
|
|
|
else if (comp < 0)
|
|
|
|
|
{
|
|
|
|
|
/* reciever > sender */
|
|
|
|
|
DBGVV("bmcDataSetComparison: PortIdentity: A better by topology then B\n");
|
|
|
|
|
return A_better_by_topology_then_B;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DBGV("bmcDataSetComparison: ERROR 1\n");
|
|
|
|
|
return ERROR_1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
comp = memcmp(headerA->sourcePortIdentity.clockIdentity, headerB->sourcePortIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH);
|
|
|
|
|
if (comp > 0)
|
|
|
|
|
{
|
|
|
|
|
/* A > B */
|
|
|
|
|
DBGVV("bmcDataSetComparison: sourcePortIdentity: B better by topology then A\n");
|
|
|
|
|
return B_better_by_topology_then_A;
|
|
|
|
|
}
|
|
|
|
|
else if (comp < 0)
|
|
|
|
|
{
|
|
|
|
|
/* B > A */
|
|
|
|
|
DBGVV("bmcDataSetComparison: sourcePortIdentity: A better by topology then B\n");
|
|
|
|
|
return A_better_by_topology_then_B;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* compare port numbers of recievers of A and B - same as we have only one port */
|
|
|
|
|
DBGV("bmcDataSetComparison: ERROR 2\n");
|
|
|
|
|
return ERROR_2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* State decision algorithm 9.3.3 Fig 26 */
|
|
|
|
|
uint8_t bmcStateDecision(MsgHeader *header, MsgAnnounce *announce, PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
int comp;
|
|
|
|
|
|
|
|
|
|
if ((!ptpClock->foreignMasterDS.count) && (ptpClock->portDS.portState == PTP_LISTENING))
|
|
|
|
|
{
|
|
|
|
|
return PTP_LISTENING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copyD0(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.announce, ptpClock);
|
|
|
|
|
|
|
|
|
|
comp = bmcDataSetComparison(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.announce, header, announce, ptpClock);
|
|
|
|
|
|
|
|
|
|
DBGV("bmcStateDecision: %d\n", comp);
|
|
|
|
|
|
|
|
|
|
if (ptpClock->defaultDS.clockQuality.clockClass < 128)
|
|
|
|
|
{
|
|
|
|
|
if (A_better_then_B == comp)
|
|
|
|
|
{
|
|
|
|
|
m1(ptpClock); /* M1 */
|
|
|
|
|
return PTP_MASTER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p1(ptpClock);
|
|
|
|
|
return PTP_PASSIVE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (A_better_then_B == comp)
|
|
|
|
|
{
|
|
|
|
|
m2(ptpClock); /* M2 */
|
|
|
|
|
return PTP_MASTER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s1(ptpClock, header, announce);
|
|
|
|
|
return PTP_SLAVE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t bmc(PtpClock *ptpClock)
|
|
|
|
|
{
|
|
|
|
|
int16_t i, best;
|
|
|
|
|
|
|
|
|
|
/* Starting from i = 1, not necessery to test record[i = 0] against record[best = 0] -> they are the same */
|
|
|
|
|
for (i = 1, best = 0; i < ptpClock->foreignMasterDS.count; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((bmcDataSetComparison(&ptpClock->foreignMasterDS.records[i].header, &ptpClock->foreignMasterDS.records[i].announce,
|
|
|
|
|
&ptpClock->foreignMasterDS.records[best].header, &ptpClock->foreignMasterDS.records[best].announce, ptpClock)) < 0)
|
|
|
|
|
{
|
|
|
|
|
best = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DBGV("bmc: best record %d\n", best);
|
|
|
|
|
ptpClock->foreignMasterDS.best = best;
|
|
|
|
|
|
|
|
|
|
return bmcStateDecision(&ptpClock->foreignMasterDS.records[best].header, &ptpClock->foreignMasterDS.records[best].announce, ptpClock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|