void *IEEE1588Port::openPort(void) { port_ready_condition->signal(); while (1) { PTPMessageCommon *msg; uint8_t buf[128]; LinkLayerAddress remote; net_result rrecv; size_t length = sizeof(buf); if ((rrecv = net_iface->nrecv(&remote, buf, length)) == net_succeed) { XPTPD_INFO("Processing network buffer"); msg = buildPTPMessage((char *)buf, (int)length, &remote, this); if (msg != NULL) { XPTPD_INFO("Processing message"); msg->processMessage(this); if (msg->garbage()) { delete msg; } } else { XPTPD_ERROR("Discarding invalid message"); } } else if (rrecv == net_fatal) { XPTPD_ERROR("read from network interface failed"); this->processEvent(FAULT_DETECTED); break; } } return NULL; }
FrequencyRatio IEEE1588Clock::calcMasterLocalClockRateDifference( Timestamp master_time, Timestamp sync_time ) { unsigned long long inter_sync_time; unsigned long long inter_master_time; FrequencyRatio ppt_offset; XPTPD_INFO( "Calculated master to local clock rate difference" ); if( !_master_local_freq_offset_init ) { _prev_sync_time = sync_time; _prev_master_time = master_time; _master_local_freq_offset_init = true; return 1.0; } inter_sync_time = TIMESTAMP_TO_NS(sync_time) - TIMESTAMP_TO_NS(_prev_sync_time); inter_master_time = TIMESTAMP_TO_NS(master_time) - TIMESTAMP_TO_NS(_prev_master_time); if( inter_sync_time != 0 ) { ppt_offset = ((FrequencyRatio)inter_master_time)/inter_sync_time; } else { ppt_offset = 1.0; } _prev_sync_time = sync_time; _prev_master_time = master_time; return ppt_offset; }
FrequencyRatio IEEE1588Clock::calcLocalSystemClockRateDifference( Timestamp local_time, Timestamp system_time ) { unsigned long long inter_system_time; unsigned long long inter_local_time; FrequencyRatio ppt_offset; XPTPD_INFO( "Calculated local to system clock rate difference" ); if( !_local_system_freq_offset_init ) { _prev_system_time = system_time; _prev_local_time = local_time; _local_system_freq_offset_init = true; return 1.0; } inter_system_time = TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(_prev_system_time); inter_local_time = TIMESTAMP_TO_NS(local_time) - TIMESTAMP_TO_NS(_prev_local_time); if( inter_system_time != 0 ) { ppt_offset = ((FrequencyRatio)inter_local_time)/inter_system_time; } else { ppt_offset = 1.0; } _prev_system_time = system_time; _prev_local_time = local_time; return ppt_offset; }
void IEEE1588Port::recommendState ( PortState state, bool changed_external_master ) { bool reset_sync = false; switch (state) { case PTP_MASTER: if (port_state != PTP_MASTER) { port_state = PTP_MASTER; // Start announce receipt timeout timer // Start sync receipt timeout timer becomeMaster( true ); reset_sync = true; } break; case PTP_SLAVE: if (port_state != PTP_SLAVE) { becomeSlave( true ); reset_sync = true; } else { if( changed_external_master ) { fprintf( stderr, "Changed master!\n" ); clock->newSyntonizationSetPoint(); reset_sync = true; } } break; default: XPTPD_INFO ("Invalid state change requested by call to " "1588Port::recommendState()"); break; } if( reset_sync ) sync_count = 0; return; }
void IEEE1588Port::processEvent(Event e) { bool changed_external_master; OSTimer *timer = timer_factory->createTimer(); switch (e) { case POWERUP: case INITIALIZE: XPTPD_INFO("Received POWERUP/INITIALIZE event"); clock->getTimerQLock(); { unsigned long long interval3; unsigned long long interval4; Event e3 = NULL_EVENT; Event e4 = NULL_EVENT; if( port_state != PTP_MASTER ) { _accelerated_sync_count = -1; } if( port_state != PTP_SLAVE && port_state != PTP_MASTER ) { fprintf( stderr, "Starting PDelay\n" ); startPDelay(); } if( clock->getPriority1() == 255 || port_state == PTP_SLAVE ) { becomeSlave( false ); } else if( port_state == PTP_MASTER ) { becomeMaster( true ); } else { //e3 = SYNC_RECEIPT_TIMEOUT_EXPIRES; e4 = ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES; interval3 = (unsigned long long) (SYNC_RECEIPT_TIMEOUT_MULTIPLIER* pow((double)2,getSyncInterval())*1000000000.0); interval4 = (unsigned long long) (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER* pow((double)2,getAnnounceInterval())*1000000000.0); } port_ready_condition->wait_prelock(); listening_thread = thread_factory->createThread(); if (!listening_thread-> start (openPortWrapper, (void *)this)) { XPTPD_ERROR("Error creating port thread"); return; } port_ready_condition->wait(); if (e3 != NULL_EVENT) clock->addEventTimer(this, e3, interval3); if (e4 != NULL_EVENT) clock->addEventTimer(this, e4, interval4); } clock->putTimerQLock(); break; case STATE_CHANGE_EVENT: if ( clock->getPriority1() != 255 ) { int number_ports, j; PTPMessageAnnounce *EBest = NULL; char EBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH]; IEEE1588Port **ports; clock->getPortList(number_ports, ports); /* Find EBest for all ports */ j = 0; for (int i = 0; i < number_ports; ++i) { while (ports[j] == NULL) ++j; if (ports[j]->port_state == PTP_DISABLED || ports[j]->port_state == PTP_FAULTY) { continue; } if (EBest == NULL) { EBest = ports[j]->calculateERBest(); } else { if (ports[j]->calculateERBest()->isBetterThan(EBest)) { EBest = ports[j]->calculateERBest(); } } } /* Check if we've changed */ { uint8_t LastEBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH]; clock->getLastEBestIdentity(). getIdentityString( LastEBestClockIdentity ); EBest->getGrandmasterIdentity( EBestClockIdentity ); if( memcmp ( EBestClockIdentity, LastEBestClockIdentity, PTP_CLOCK_IDENTITY_LENGTH ) != 0 ) { ClockIdentity newGM; changed_external_master = true; newGM.set((uint8_t *) EBestClockIdentity ); clock->setLastEBestIdentity( newGM ); } else { changed_external_master = false; } } if( clock->isBetterThan( EBest )) { // We're Grandmaster, set grandmaster info to me ClockIdentity clock_identity; unsigned char priority1; unsigned char priority2; ClockQuality clock_quality; clock_identity = getClock()->getClockIdentity(); getClock()->setGrandmasterClockIdentity( clock_identity ); priority1 = getClock()->getPriority1(); getClock()->setGrandmasterPriority1( priority1 ); priority2 = getClock()->getPriority2(); getClock()->setGrandmasterPriority2( priority2 ); clock_quality = getClock()->getClockQuality(); getClock()->setGrandmasterClockQuality( clock_quality ); } j = 0; for (int i = 0; i < number_ports; ++i) { while (ports[j] == NULL) ++j; if (ports[j]->port_state == PTP_DISABLED || ports[j]->port_state == PTP_FAULTY) { continue; } if (clock->isBetterThan(EBest)) { // We are the GrandMaster, all ports are master EBest = NULL; // EBest == NULL : we were grandmaster ports[j]->recommendState(PTP_MASTER, changed_external_master); } else { if( EBest == ports[j]->calculateERBest() ) { // The "best" Announce was recieved on this port ClockIdentity clock_identity; unsigned char priority1; unsigned char priority2; ClockQuality *clock_quality; ports[j]->recommendState ( PTP_SLAVE, changed_external_master ); clock_identity = EBest->getGrandmasterClockIdentity(); getClock()->setGrandmasterClockIdentity(clock_identity); priority1 = EBest->getGrandmasterPriority1(); getClock()->setGrandmasterPriority1( priority1 ); priority2 = EBest->getGrandmasterPriority2(); getClock()->setGrandmasterPriority2( priority2 ); clock_quality = EBest->getGrandmasterClockQuality(); getClock()->setGrandmasterClockQuality(*clock_quality); } else { /* Otherwise we are the master because we have sync'd to a better clock */ ports[j]->recommendState (PTP_MASTER, changed_external_master); } } } } break; case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: case SYNC_RECEIPT_TIMEOUT_EXPIRES: { if( clock->getPriority1() == 255 ) { // Restart timer if( e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ) { clock->addEventTimer (this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES, (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER* (unsigned long long) (pow((double)2,getAnnounceInterval())* 1000000000.0))); } else { clock->addEventTimer (this, SYNC_RECEIPT_TIMEOUT_EXPIRES, (SYNC_RECEIPT_TIMEOUT_MULTIPLIER* (unsigned long long) (pow((double)2,getSyncInterval())* 1000000000.0))); } return; } if (port_state == PTP_INITIALIZING || port_state == PTP_UNCALIBRATED || port_state == PTP_SLAVE || port_state == PTP_PRE_MASTER) { Timestamp tsTmp(0,0,0); if(NULL!=p_dbg_HoldLastFollowup) { tsTmp = p_dbg_HoldLastFollowup->getPreciseOriginTimestamp(); } fprintf (stderr, "*** %s Timeout Expired - Becoming Master LastFollowUpPOT=%16llu\n", e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ? "Announce" : "Sync", tsTmp ); { // We're Grandmaster, set grandmaster info to me ClockIdentity clock_identity; unsigned char priority1; unsigned char priority2; ClockQuality clock_quality; clock_identity = getClock()->getClockIdentity(); getClock()->setGrandmasterClockIdentity( clock_identity ); priority1 = getClock()->getPriority1(); getClock()->setGrandmasterPriority1( priority1 ); priority2 = getClock()->getPriority2(); getClock()->setGrandmasterPriority2( priority2 ); clock_quality = getClock()->getClockQuality(); getClock()->setGrandmasterClockQuality( clock_quality ); } port_state = PTP_MASTER; Timestamp system_time; Timestamp device_time; uint32_t local_clock, nominal_clock_rate; getDeviceTime(system_time, device_time, local_clock, nominal_clock_rate); (void) clock->calcLocalSystemClockRateDifference ( device_time, system_time ); delete qualified_announce; qualified_announce = NULL; // Add timers for Announce and Sync, this is as close to immediately as we get clock->addEventTimer ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, 16000000 ); startAnnounce(); // } } break; case PDELAY_INTERVAL_TIMEOUT_EXPIRES: XPTPD_INFO("PDELAY_INTERVAL_TIMEOUT_EXPIRES occured"); { int ts_good; Timestamp req_timestamp; int iter = TX_TIMEOUT_ITER; long req = TX_TIMEOUT_BASE; unsigned req_timestamp_counter_value; long long wait_time = 0; PTPMessagePathDelayReq *pdelay_req = new PTPMessagePathDelayReq(this); PortIdentity dest_id; getPortIdentity(dest_id); pdelay_req->setPortIdentity(&dest_id); { Timestamp pending = PDELAY_PENDING_TIMESTAMP; pdelay_req->setTimestamp(pending); } if (last_pdelay_req != NULL) { delete last_pdelay_req; } setLastPDelayReq(pdelay_req); getTxLock(); pdelay_req->sendPort(this, NULL); XPTPD_INFO("Sent PDelay Request"); ts_good = getTxTimestamp (pdelay_req, req_timestamp, req_timestamp_counter_value, false); while (ts_good != 0 && iter-- != 0) { timer->sleep(req); wait_time += req; if (ts_good != -72 && iter < 1) fprintf (stderr, "Error (TX) timestamping PDelay request " "(Retrying-%d), error=%d\n", iter, ts_good); ts_good = getTxTimestamp (pdelay_req, req_timestamp, req_timestamp_counter_value, iter == 0); req *= 2; } putTxLock(); if (ts_good == 0) { pdelay_req->setTimestamp(req_timestamp); } else { Timestamp failed = INVALID_TIMESTAMP; pdelay_req->setTimestamp(failed); fprintf( stderr, "Invalid TX\n" ); } if (ts_good != 0) { char msg [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; getExtendedError(msg); XPTPD_ERROR( "Error (TX) timestamping PDelay request, error=%d\t%s", ts_good, msg); } #ifdef DEBUG if (ts_good == 0) { XPTPD_INFO ("Successful PDelay Req timestamp, %u,%u", req_timestamp.seconds_ls, req_timestamp.nanoseconds); } else { XPTPD_INFO ("*** Unsuccessful PDelay Req timestamp"); } #endif { long long timeout; long long interval; timeout = PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER * ((long long) (pow((double)2,getPDelayInterval())*1000000000.0)) - wait_time*1000; timeout = timeout > EVENT_TIMER_GRANULARITY ? timeout : EVENT_TIMER_GRANULARITY; clock->addEventTimer (this, PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, timeout ); interval = ((long long) (pow((double)2,getPDelayInterval())*1000000000.0)) - wait_time*1000; interval = interval > EVENT_TIMER_GRANULARITY ? interval : EVENT_TIMER_GRANULARITY; clock->addEventTimer (this, PDELAY_INTERVAL_TIMEOUT_EXPIRES, interval ); } } break; case SYNC_INTERVAL_TIMEOUT_EXPIRES: XPTPD_INFO("SYNC_INTERVAL_TIMEOUT_EXPIRES occured"); fprintf(stderr, "STO\n"); { #ifdef OLD_GPTP /* Set offset from master to zero, update device vs system time offset */ Timestamp system_time; Timestamp device_time; FrequencyRatio local_system_freq_offset; int64_t local_system_offset; long long wait_time = 0; uint32_t local_clock, nominal_clock_rate; // Send a sync message and then a followup to broadcast if (asCapable) { PTPMessageSync *sync = new PTPMessageSync(this); PortIdentity dest_id; getPortIdentity(dest_id); sync->setPortIdentity(&dest_id); getTxLock(); sync->sendPort(this, NULL); XPTPD_INFO("Sent SYNC message"); int ts_good; Timestamp sync_timestamp; unsigned sync_timestamp_counter_value; int iter = TX_TIMEOUT_ITER; long req = TX_TIMEOUT_BASE; ts_good = getTxTimestamp(sync, sync_timestamp, sync_timestamp_counter_value, false); while (ts_good != 0 && iter-- != 0) { timer->sleep(req); wait_time += req; if (ts_good != -72 && iter < 1) XPTPD_ERROR( "Error (TX) timestamping Sync (Retrying), " "error=%d", ts_good); ts_good = getTxTimestamp (sync, sync_timestamp, sync_timestamp_counter_value, iter == 0); req *= 2; } putTxLock(); if (ts_good != 0) { char msg [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; getExtendedError(msg); fprintf (stderr, "Error (TX) timestamping Sync, error=" "%d\n%s", ts_good, msg ); } if (ts_good == 0) { XPTPD_INFO("Successful Sync timestamp"); XPTPD_INFO("Seconds: %u", sync_timestamp.seconds_ls); XPTPD_INFO("Nanoseconds: %u", sync_timestamp.nanoseconds); } else { XPTPD_INFO ("*** Unsuccessful Sync timestamp"); } PTPMessageFollowUp *follow_up; if (ts_good == 0) { follow_up = new PTPMessageFollowUp(this); PortIdentity dest_id; getPortIdentity(dest_id); follow_up->setPortIdentity(&dest_id); follow_up->setSequenceId(sync->getSequenceId()); follow_up->setPreciseOriginTimestamp(sync_timestamp); follow_up->sendPort(this, NULL); delete follow_up; } else { } delete sync; } /* Do getDeviceTime() after transmitting sync frame causing an update to local/system timestamp */ getDeviceTime (system_time, device_time, local_clock, nominal_clock_rate); XPTPD_INFO ("port::processEvent(): System time: %u,%u Device Time: %u,%u", system_time.seconds_ls, system_time.nanoseconds, device_time.seconds_ls, device_time.nanoseconds); local_system_offset = TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(device_time); local_system_freq_offset = clock->calcLocalSystemClockRateDifference ( device_time, system_time ); clock->setMasterOffset (0, device_time, 1.0, local_system_offset, system_time, local_system_freq_offset, sync_count, pdelay_count, port_state , 0/*DEBUG*/, system_time, system_time, 0, 0, 0 ); /* If accelerated_sync is non-zero then start 16 ms sync timer, subtract 1, for last one start PDelay also */ if( _accelerated_sync_count > 0 ) { clock->addEventTimer ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, 8000000 ); --_accelerated_sync_count; } else { syncDone(); if( _accelerated_sync_count == 0 ) { --_accelerated_sync_count; } wait_time *= 1000; // to ns wait_time = ((long long) (pow((double)2,getSyncInterval())*1000000000.0)) - wait_time; wait_time = wait_time > EVENT_TIMER_GRANULARITY ? wait_time : EVENT_TIMER_GRANULARITY; clock->addEventTimer ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, wait_time ); } #else /* Set offset from master to zero, update device vs system time offset */ Timestamp system_time; Timestamp device_time; Timestamp sync_timestamp; long long wait_time = 0; uint32_t local_clock, nominal_clock_rate; struct masterToLocal master_to_local; struct localToSystem local_to_system; // Send a sync message and then a followup to broadcast if (asCapable) { PTPMessageSync *sync = new PTPMessageSync(this); PortIdentity dest_id; getPortIdentity(dest_id); sync->setPortIdentity(&dest_id); getTxLock(); sync->sendPort(this, NULL); XPTPD_INFO("Sent SYNC message"); int ts_good; unsigned sync_timestamp_counter_value; int iter = TX_TIMEOUT_ITER; long req = TX_TIMEOUT_BASE; ts_good = getTxTimestamp(sync, sync_timestamp, sync_timestamp_counter_value, false); while (ts_good != 0 && iter-- != 0) { timer->sleep(req); wait_time += req; if (ts_good != -72 && iter < 1) XPTPD_ERROR( "Error (TX) timestamping Sync (Retrying), " "error=%d", ts_good); ts_good = getTxTimestamp (sync, sync_timestamp, sync_timestamp_counter_value, iter == 0); req *= 2; } putTxLock(); if (ts_good != 0) { char msg [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; getExtendedError(msg); fprintf (stderr, "Error (TX) timestamping Sync, error=" "%d\n%s", ts_good, msg ); } if (ts_good == 0) { XPTPD_INFO("Successful Sync timestamp"); XPTPD_INFO("Seconds: %u", sync_timestamp.seconds_ls); XPTPD_INFO("Nanoseconds: %u", sync_timestamp.nanoseconds); } else { XPTPD_INFO ("*** Unsuccessful Sync timestamp"); } PTPMessageFollowUp *follow_up; if (ts_good == 0) { follow_up = new PTPMessageFollowUp(this); PortIdentity dest_id; getPortIdentity(dest_id); follow_up->setPortIdentity(&dest_id); follow_up->setSequenceId(sync->getSequenceId()); follow_up->setPreciseOriginTimestamp(sync_timestamp); follow_up->sendPort(this, NULL); delete follow_up; } else { } delete sync; } /* Do getDeviceTime() after transmitting sync frame causing an update to local/system timestamp */ getDeviceTime (system_time, device_time, local_clock, nominal_clock_rate); XPTPD_INFO ("port::processEvent(): System time: %u,%u Device Time: %u,%u", system_time.seconds_ls, system_time.nanoseconds, device_time.seconds_ls, device_time.nanoseconds); master_to_local.preciseOriginTimestamp = sync_timestamp; master_to_local.sync_arrival = sync_timestamp; master_to_local.freq_ratio = 1.0; local_to_system.device_time = device_time; local_to_system.system_time = system_time; local_to_system.freq_ratio = clock->calcLocalSystemClockRateDifference( device_time, system_time );; clock->setMasterOffset(master_to_local, local_to_system, sync_count, pdelay_count, port_state ); /* If accelerated_sync is non-zero then start 16 ms sync timer, subtract 1, for last one start PDelay also */ if( _accelerated_sync_count > 0 ) { clock->addEventTimer( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, 8000000 ); --_accelerated_sync_count; } else { syncDone(); if( _accelerated_sync_count == 0 ) { --_accelerated_sync_count; } wait_time *= 1000; // to ns wait_time = ((long long) (pow((double)2,getSyncInterval())*1000000000.0)) - wait_time; wait_time = wait_time > EVENT_TIMER_GRANULARITY ? wait_time : EVENT_TIMER_GRANULARITY; clock->addEventTimer ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, wait_time ); } #endif } break; case ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES: if (asCapable) { // Send an announce message PTPMessageAnnounce *annc = new PTPMessageAnnounce(this); PortIdentity dest_id; PortIdentity gmId; ClockIdentity clock_id = clock->getClockIdentity(); gmId.setClockIdentity(clock_id); getPortIdentity(dest_id); annc->setPortIdentity(&dest_id); annc->sendPort(this, NULL); delete annc; } clock->addEventTimer (this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, (unsigned) (pow ((double)2, getAnnounceInterval()) * 1000000000.0)); break; case FAULT_DETECTED: XPTPD_INFO("Received FAULT_DETECTED event"); break; case PDELAY_DEFERRED_PROCESSING: pdelay_rx_lock->lock(); if (last_pdelay_resp_fwup == NULL) { fprintf(stderr, "PDelay Response Followup is NULL!\n"); abort(); } last_pdelay_resp_fwup->processMessage(this); if (last_pdelay_resp_fwup->garbage()) { delete last_pdelay_resp_fwup; this->setLastPDelayRespFollowUp(NULL); } pdelay_rx_lock->unlock(); break; case PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES: setAsCapable(false); pdelay_count = 0; break; default: XPTPD_INFO ("Unhandled event type in IEEE1588Port::processEvent(), %d", e); break; } delete timer; return; }