Example #1
0
void issueDelayReq(PtpClock *ptpClock)
{
  TimeInternal internalTime;
  TimeRepresentation originTimestamp;
  
  ptpClock->sentDelayReq = TRUE;
  ptpClock->sentDelayReqSequenceId = ++ptpClock->last_sync_event_sequence_number;

  /* try to predict outgoing time stamp */
  getTime(&internalTime, ptpClock);
  fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
  msgPackDelayReq(ptpClock->msgObuf, FALSE, FALSE, &originTimestamp, ptpClock);
  
  if(!netSendEvent(ptpClock->msgObuf, DELAY_REQ_PACKET_LENGTH,
                   ptpClock->delayedTiming ? &internalTime : NULL,
                   ptpClock))
    toState(PTP_FAULTY, ptpClock);
  else
  {
    DBGV("sent delay request message\n");
    if(ptpClock->delayedTiming)
    {
      if (internalTime.seconds || internalTime.nanoseconds) {
        /* compensate with configurable latency, then store for later use */
        addTime(&internalTime, &internalTime, &ptpClock->runTimeOpts.outboundLatency);
        ptpClock->delay_req_send_time = internalTime;
      } else {
        NOTIFY("WARNING: delay request message without hardware time stamp, will skip response\n");
        ptpClock->sentDelayReq = FALSE;
      }
    }
  }
}
Example #2
0
/* pack and send various messages */
void issueSync(PtpClock *ptpClock)
{
  TimeInternal internalTime;
  TimeRepresentation originTimestamp;
  
  ++ptpClock->last_sync_event_sequence_number;
  ptpClock->grandmaster_sequence_number = ptpClock->last_sync_event_sequence_number;

  /* try to predict outgoing time stamp */
  getTime(&internalTime, ptpClock);
  fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
  msgPackSync(ptpClock->msgObuf, FALSE, TRUE, &originTimestamp, ptpClock);
  
  if(!netSendEvent(ptpClock->msgObuf, SYNC_PACKET_LENGTH,
                   ptpClock->delayedTiming ? &internalTime : NULL,
                   ptpClock))
    toState(PTP_FAULTY, ptpClock);
  else
  {
    DBGV("sent sync message\n");
    if(ptpClock->delayedTiming)
    {
      if (internalTime.seconds || internalTime.nanoseconds) {
        /* compensate with configurable latency, then tell client real time stamp */
        addTime(&internalTime, &internalTime, &ptpClock->runTimeOpts.outboundLatency);
        issueFollowup(&internalTime, ptpClock);
      } else {
        NOTIFY("WARNING: sync message without hardware time stamp, skipped followup\n");
      }
    }
  }
}
Example #3
0
/*Pack and send on event multicast ip adress a PDelayReq message*/
static void issuePDelayReq(PtpClock *ptpClock)
{
    Timestamp originTimestamp;
    TimeInternal internalTime;
    getTime(&internalTime);
    fromInternalTime(&internalTime, &originTimestamp);

    msgPackPDelayReq(ptpClock, ptpClock->msgObuf, &originTimestamp);

    if (!netSendPeerEvent(&ptpClock->netPath, ptpClock->msgObuf, PDELAY_REQ_LENGTH, &internalTime))
    {
        ERROR("issuePDelayReq: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        DBGV("issuePDelayReq\n");
        ptpClock->sentPDelayReqSequenceId++;

        /* Delay req TX timestamp is valid */

        if (internalTime.seconds != 0)
        {
            addTime(&internalTime, &internalTime, &ptpClock->outboundLatency);
            ptpClock->pdelay_t1 = internalTime;
        }
    }
}
Example #4
0
/*Pack and send on event multicast ip adress a Sync message*/
static void issueSync(PtpClock *ptpClock)
{
    Timestamp originTimestamp;
    TimeInternal internalTime;

    /* try to predict outgoing time stamp */
    getTime(&internalTime);
    fromInternalTime(&internalTime, &originTimestamp);

    msgPackSync(ptpClock, ptpClock->msgObuf, &originTimestamp);

    if (!netSendEvent(&ptpClock->netPath, ptpClock->msgObuf, SYNC_LENGTH, &internalTime))
    {
        ERROR("issueSync: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        DBGV("issueSync\n");
        ptpClock->sentSyncSequenceId++;

        /* sync TX timestamp is valid */

        if ((internalTime.seconds != 0) && (ptpClock->defaultDS.twoStepFlag))
        {
            // waitingForLoopback = false;
            addTime(&internalTime, &internalTime, &ptpClock->outboundLatency);
            issueFollowup(ptpClock, &internalTime);
        }
        else
        {
            // waitingForLoopback = ptpClock->twoStepFlag;
        }
    }
}
Example #5
0
void issueDelayResp(TimeInternal *time, MsgHeader *header, PtpClock *ptpClock)
{
  TimeRepresentation delayReceiptTimestamp;
  
  ++ptpClock->last_general_event_sequence_number;

  fromInternalTime(time, &delayReceiptTimestamp, ptpClock->halfEpoch);
  msgPackDelayResp(ptpClock->msgObuf, header, &delayReceiptTimestamp, ptpClock);
  
  if(!netSendGeneral(ptpClock->msgObuf, DELAY_RESP_PACKET_LENGTH, ptpClock))
    toState(PTP_FAULTY, ptpClock);
  else
    DBGV("sent delay response message\n");
}
Example #6
0
void issueFollowup(TimeInternal *time, PtpClock *ptpClock)
{
  TimeRepresentation preciseOriginTimestamp;
  
  ++ptpClock->last_general_event_sequence_number;
  
  fromInternalTime(time, &preciseOriginTimestamp, ptpClock->halfEpoch);
  msgPackFollowUp(ptpClock->msgObuf, ptpClock->last_sync_event_sequence_number, &preciseOriginTimestamp, ptpClock);
  
  if(!netSendGeneral(ptpClock->msgObuf, FOLLOW_UP_PACKET_LENGTH, ptpClock))
    toState(PTP_FAULTY, ptpClock);
  else
    DBGV("sent followup message\n");
}
Example #7
0
/*Pack and send on event multicast ip adress a DelayResp message*/
static void issueDelayResp(PtpClock *ptpClock, const TimeInternal *time, const MsgHeader * delayReqHeader)
{
    Timestamp requestReceiptTimestamp;
    fromInternalTime(time, &requestReceiptTimestamp);
    msgPackDelayResp(ptpClock, ptpClock->msgObuf, delayReqHeader, &requestReceiptTimestamp);

    if (!netSendGeneral(&ptpClock->netPath, ptpClock->msgObuf, PDELAY_RESP_LENGTH))
    {
        ERROR("issueDelayResp: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        DBGV("issueDelayResp\n");
    }
}
Example #8
0
/*Pack and send on general multicast ip adress a FollowUp message*/
void
issueFollowup(TimeInternal *time,RunTimeOpts *rtOpts,PtpClock *ptpClock)
{
	Timestamp preciseOriginTimestamp;
	fromInternalTime(time,&preciseOriginTimestamp);
	
	msgPackFollowUp(ptpClock->msgObuf,&preciseOriginTimestamp,ptpClock);
	
	if (!netSendGeneral(ptpClock->msgObuf,FOLLOW_UP_LENGTH,
			    &ptpClock->netPath, 0)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("FollowUp message can't be sent -> FAULTY state \n");
	} else {
		DBGV("FollowUp MSG sent ! \n");
	}
}
void issueDelayReq(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
  TimeInternal internalTime;
  TimeRepresentation originTimestamp;

  ptpClock->sentDelayReq = TRUE;
  ptpClock->sentDelayReqSequenceId = ++ptpClock->last_sync_event_sequence_number;

  getTime(&internalTime);
  fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
  msgPackDelayReq(ptpClock->msgObuf, FALSE, &originTimestamp, ptpClock);

  if(!netSendEvent(ptpClock->msgObuf, DELAY_REQ_PACKET_LENGTH, &ptpClock->netPath))
    toState(PTP_FAULTY, rtOpts, ptpClock);
  else
    DBGV("sent delay request message\n");
}
/* pack and send various messages */
void issueSync(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
  TimeInternal internalTime;
  TimeRepresentation originTimestamp;

  ++ptpClock->last_sync_event_sequence_number;
  ptpClock->grandmaster_sequence_number = ptpClock->last_sync_event_sequence_number;

  getTime(&internalTime);
  fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
  msgPackSync(ptpClock->msgObuf, FALSE, &originTimestamp, ptpClock);

  if(!netSendEvent(ptpClock->msgObuf, SYNC_PACKET_LENGTH, &ptpClock->netPath))
    toState(PTP_FAULTY, rtOpts, ptpClock);
  else
    DBGV("sent sync message\n");
}
Example #11
0
static void issuePDelayRespFollowUp(PtpClock *ptpClock, const TimeInternal *time, const MsgHeader * pDelayReqHeader)
{
    Timestamp responseOriginTimestamp;
    fromInternalTime(time, &responseOriginTimestamp);

    msgPackPDelayRespFollowUp(ptpClock->msgObuf, pDelayReqHeader, &responseOriginTimestamp);

    if (!netSendPeerGeneral(&ptpClock->netPath, ptpClock->msgObuf, PDELAY_RESP_FOLLOW_UP_LENGTH))
    {
        ERROR("issuePDelayRespFollowUp: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        DBGV("issuePDelayRespFollowUp\n");
    }
}
Example #12
0
/*Pack and send on general multicast ip adress a FollowUp message*/
static void issueFollowup(PtpClock *ptpClock, const TimeInternal *time)
{
    Timestamp preciseOriginTimestamp;
    fromInternalTime(time, &preciseOriginTimestamp);

    msgPackFollowUp(ptpClock, ptpClock->msgObuf, &preciseOriginTimestamp);

    if (!netSendGeneral(&ptpClock->netPath, ptpClock->msgObuf, FOLLOW_UP_LENGTH))
    {
        ERROR("issueFollowup: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        DBGV("issueFollowup\n");
    }
}
Example #13
0
/*Pack and send on event multicast ip adress a PDelayResp message*/
void
issuePDelayResp(TimeInternal *time,MsgHeader *header,RunTimeOpts *rtOpts,
		PtpClock *ptpClock)
{
	Timestamp requestReceiptTimestamp;
	fromInternalTime(time,&requestReceiptTimestamp);
	msgPackPDelayResp(ptpClock->msgObuf,header,
			  &requestReceiptTimestamp,ptpClock);

	if (!netSendPeerEvent(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
			      &ptpClock->netPath)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("PdelayResp message can't be sent -> FAULTY state \n");
	} else {
		DBGV("PDelayResp MSG sent ! \n");
	}
}
Example #14
0
/*Pack and send on event multicast ip adress a Sync message*/
void
issueSync(RunTimeOpts *rtOpts,PtpClock *ptpClock)
{
	Timestamp originTimestamp;
	TimeInternal internalTime;
	getTime(&internalTime);
	fromInternalTime(&internalTime,&originTimestamp);

	msgPackSync(ptpClock->msgObuf,&originTimestamp,ptpClock);

	if (!netSendEvent(ptpClock->msgObuf,SYNC_LENGTH,&ptpClock->netPath, 0)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("Sync message can't be sent -> FAULTY state \n");
	} else {
		DBGV("Sync MSG sent ! \n");
		ptpClock->sentSyncSequenceId++;
	}
}
Example #15
0
/*Pack and send on event multicast ip adress a PDelayReq message*/
void
issuePDelayReq(RunTimeOpts *rtOpts,PtpClock *ptpClock)
{
	Timestamp originTimestamp;
	TimeInternal internalTime;
	getTime(&internalTime);
	fromInternalTime(&internalTime,&originTimestamp);
	
	msgPackPDelayReq(ptpClock->msgObuf,&originTimestamp,ptpClock);

	if (!netSendPeerEvent(ptpClock->msgObuf,PDELAY_REQ_LENGTH,
			      &ptpClock->netPath)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("PdelayReq message can't be sent -> FAULTY state \n");
	} else {
		DBGV("PDelayReq MSG sent ! \n");
		ptpClock->sentPDelayReqSequenceId++;
	}
}
Example #16
0
/*Pack and send on event multicast ip adress a PDelayResp message*/
static void issuePDelayResp(PtpClock *ptpClock, TimeInternal *time, const MsgHeader * pDelayReqHeader)
{
    Timestamp requestReceiptTimestamp;
    fromInternalTime(time, &requestReceiptTimestamp);
    msgPackPDelayResp(ptpClock->msgObuf, pDelayReqHeader, &requestReceiptTimestamp);

    if (!netSendPeerEvent(&ptpClock->netPath, ptpClock->msgObuf, PDELAY_RESP_LENGTH, time))
    {
        ERROR("issuePDelayResp: can't sent\n");
        toState(ptpClock, PTP_FAULTY);
    }
    else
    {
        if (time->seconds != 0)
        {
            /*Add latency*/
            addTime(time, time, &ptpClock->outboundLatency);
        }

        DBGV("issuePDelayResp\n");
    }
}
Example #17
0
/*Pack and send on event multicast ip adress a DelayReq message*/
void
issueDelayReq(RunTimeOpts *rtOpts,PtpClock *ptpClock)
{
	Timestamp originTimestamp;
	TimeInternal internalTime;

	DBG("==> Issue DelayReq (%d)\n", ptpClock->sentDelayReqSequenceId );

	/* call GTOD. This time is later replaced on handle_delayreq, to get the actual send timestamp from the OS */
	getTime(&internalTime);
	fromInternalTime(&internalTime,&originTimestamp);

	// uses current sentDelayReqSequenceId
	msgPackDelayReq(ptpClock->msgObuf,&originTimestamp,ptpClock);

	Integer32 dst = 0;
#ifdef PTP_EXPERIMENTAL
	if (rtOpts->do_hybrid_mode) {
		dst = ptpClock->MasterAddr;
	}
#endif

	if (!netSendEvent(ptpClock->msgObuf,DELAY_REQ_LENGTH,
			  &ptpClock->netPath, dst)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("delayReq message can't be sent -> FAULTY state \n");
	} else {
		DBGV("DelayReq MSG sent ! \n");
		ptpClock->sentDelayReqSequenceId++;

		/* From now on, we will only accept delayreq and delayresp of (sentDelayReqSequenceId - 1) */

		/* Explicitelly re-arm timer for sending the next delayReq */
		timerStart_random(DELAYREQ_INTERVAL_TIMER,
		   pow(2,ptpClock->logMinDelayReqInterval),
		   ptpClock->itimer);
	}
}
Example #18
0
/*Pack and send on event multicast ip adress a DelayResp message*/
void
issueDelayResp(TimeInternal *time,MsgHeader *header,RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
	Timestamp requestReceiptTimestamp;
	fromInternalTime(time,&requestReceiptTimestamp);
	msgPackDelayResp(ptpClock->msgObuf,header,&requestReceiptTimestamp,
			 ptpClock);

	Integer32 dst = 0;
#ifdef PTP_EXPERIMENTAL
	if (rtOpts->do_hybrid_mode) {
		dst = ptpClock->LastSlaveAddr;
	}
#endif

	if (!netSendGeneral(ptpClock->msgObuf,PDELAY_RESP_LENGTH,
			    &ptpClock->netPath, dst)) {
		toState(PTP_FAULTY,rtOpts,ptpClock);
		DBGV("delayResp message can't be sent -> FAULTY state \n");
	} else {
		DBGV("PDelayResp MSG sent ! \n");
	}
}
Example #19
0
UInteger16 msgPackManagementResponse(void *buf, MsgHeader *header, MsgManagement *manage, PtpClock *ptpClock)
{
  TimeInternal internalTime;
  TimeRepresentation externalTime;
  
  *(UInteger8*)((char*)buf + 20) = 2;  /* messageType */
  *(Integer32*)((char*)buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
  *(UInteger8*)((char*)buf + 32) = PTP_MANAGEMENT_MESSAGE;  /* control */
  clearFlag(((char*)buf + 34), PTP_SYNC_BURST);
  clearFlag(((char*)buf + 34), PARENT_STATS);
  *(Integer32*)((char*)buf + 40) = shift8(header->sourceCommunicationTechnology, 1);
  memcpy((char*)buf + 42, header->sourceUuid, 6);
  *(Integer32*)((char*)buf + 48) = shift16(flip16(header->sourcePortId), 0) | shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 1);
  *(Integer32*)((char*)buf + 52) = shift16(flip16(manage->startingBoundaryHops - manage->boundaryHops + 1), 0);
  
  switch(manage->managementMessageKey)
  {
  case PTP_MM_OBTAIN_IDENTITY:
    *(UInteger8*)((char*)buf + 55) = PTP_MM_CLOCK_IDENTITY;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(64), 1);
    *(Integer32*)((char*)buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
    memcpy((char*)buf + 64, ptpClock->clock_uuid_field, 6);
    *(Integer32*)((char*)buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
    memcpy(((char*)buf + 76), MANUFACTURER_ID, 48);
    return 124;
    
  case PTP_MM_GET_DEFAULT_DATA_SET:
    *(UInteger8*)((char*)buf + 55) = PTP_MM_DEFAULT_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(76), 1);
    *(Integer32*)((char*)buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
    memcpy((char*)buf + 64, ptpClock->clock_uuid_field, 6);
    *(Integer32*)((char*)buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
    *(Integer32*)((char*)buf + 76) = shift8(ptpClock->clock_stratum, 3);
    memcpy((char*)buf + 80, ptpClock->clock_identifier, 4);
    *(Integer32*)((char*)buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
    *(Integer32*)((char*)buf + 88) = shift8(ptpClock->clock_followup_capable, 3);
    *(Integer32*)((char*)buf + 92) = shift8(ptpClock->preferred, 3);
    *(Integer32*)((char*)buf + 96) = shift8(ptpClock->initializable, 3);
    *(Integer32*)((char*)buf + 100) = shift8(ptpClock->external_timing, 3);
    *(Integer32*)((char*)buf + 104) = shift8(ptpClock->is_boundary_clock, 3);
    *(Integer32*)((char*)buf + 108) = shift8(ptpClock->sync_interval, 3);
    memcpy((char*)buf + 112, ptpClock->subdomain_name, 16);
    *(Integer32*)((char*)buf + 128) = shift16(flip16(ptpClock->number_ports), 1);
    *(Integer32*)((char*)buf + 132) = shift16(flip16(ptpClock->number_foreign_records), 1);
    return 136;
    
  case PTP_MM_GET_CURRENT_DATA_SET:
    *(UInteger8*)((char*)buf + 55) = PTP_MM_CURRENT_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(20), 1);
    *(Integer32*)((char*)buf + 60) = shift16(flip16(ptpClock->steps_removed), 1);
    
    fromInternalTime(&ptpClock->offset_from_master, &externalTime, 0);
    *(Integer32*)((char*)buf + 64) = flip32(externalTime.seconds);
    *(Integer32*)((char*)buf + 68) = flip32(externalTime.nanoseconds);
    
    fromInternalTime(&ptpClock->one_way_delay, &externalTime, 0);
    *(Integer32*)((char*)buf + 72) = flip32(externalTime.seconds);
    *(Integer32*)((char*)buf + 76) = flip32(externalTime.nanoseconds);
    return 80;
    
  case PTP_MM_GET_PARENT_DATA_SET:
    *(UInteger8*)((char*)buf + 55) = PTP_MM_PARENT_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(90), 1);
    *(Integer32*)((char*)buf + 60) = shift8(ptpClock->parent_communication_technology, 3);
    memcpy((char*)buf + 64, ptpClock->parent_uuid, 6);
    *(Integer32*)((char*)buf + 72) = shift16(flip16(ptpClock->parent_port_id), 1);
    *(Integer32*)((char*)buf + 76) = shift16(flip16(ptpClock->parent_last_sync_sequence_number), 1);
    *(Integer32*)((char*)buf + 80) = shift8(ptpClock->parent_followup_capable, 1);
    *(Integer32*)((char*)buf + 84) = shift8(ptpClock->parent_external_timing, 3);
    *(Integer32*)((char*)buf + 88) = shift16(flip16(ptpClock->parent_variance), 1);
    *(Integer32*)((char*)buf + 92) = shift8(ptpClock->parent_stats, 3);
    *(Integer32*)((char*)buf + 96) = shift16(flip16(ptpClock->observed_variance), 1);
    *(Integer32*)((char*)buf + 100) = flip32(ptpClock->observed_drift);
    *(Integer32*)((char*)buf + 104) = shift8(ptpClock->utc_reasonable, 3);
    *(Integer32*)((char*)buf + 108) = shift8(ptpClock->grandmaster_communication_technology, 3);
    memcpy((char*)buf + 112, ptpClock->grandmaster_uuid_field, 6);
    *(Integer32*)((char*)buf + 120) = shift16(flip16(ptpClock->grandmaster_port_id_field), 1);
    *(Integer32*)((char*)buf + 124) = shift8(ptpClock->grandmaster_stratum, 3);
    memcpy((char*)buf + 128, ptpClock->grandmaster_identifier, 4);
    *(Integer32*)((char*)buf + 132) = shift16(flip16(ptpClock->grandmaster_variance), 1);
    *(Integer32*)((char*)buf + 136) = shift8(ptpClock->grandmaster_preferred, 3);
    *(Integer32*)((char*)buf + 140) = shift8(ptpClock->grandmaster_is_boundary_clock, 3);
    *(Integer32*)((char*)buf + 144) = shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
    return 148;
    
  case PTP_MM_GET_PORT_DATA_SET:
    if(manage->targetPortId && manage->targetPortId != ptpClock->port_id_field)
    {
      *(UInteger8*)((char*)buf + 55) = PTP_MM_NULL;
      *(Integer32*)((char*)buf + 56) = shift16(flip16(0), 1);
      return 0;
    }
    
    *(UInteger8*)((char*)buf + 55) = PTP_MM_PORT_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(52), 1);
    *(Integer32*)((char*)buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
    *(Integer32*)((char*)buf + 64) = shift8(ptpClock->port_state, 3);
    *(Integer32*)((char*)buf + 68) = shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
    *(Integer32*)((char*)buf + 72) = shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
    *(Integer32*)((char*)buf + 76) = shift8(ptpClock->port_communication_technology, 3);
    memcpy((char*)buf + 80, ptpClock->port_uuid_field, 6);
    *(Integer32*)((char*)buf + 88) = shift16(flip16(ptpClock->port_id_field), 1);
    *(Integer32*)((char*)buf + 92) = shift8(ptpClock->burst_enabled, 3);
    *(Integer32*)((char*)buf + 96) = shift8(4, 1) | shift8(2, 2) | shift8(2, 3);
    memcpy((char*)buf + 100, ptpClock->subdomain_address, 4);
    memcpy((char*)buf + 106, ptpClock->event_port_address, 2);
    memcpy((char*)buf + 110, ptpClock->general_port_address, 2);
    return 112;
    
  case PTP_MM_GET_GLOBAL_TIME_DATA_SET:
    *(UInteger8*)((char*)buf + 55) = PTP_MM_GLOBAL_TIME_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(24), 1);
    
    getTime(&internalTime);
    fromInternalTime(&internalTime, &externalTime, ptpClock->halfEpoch);
    *(Integer32*)((char*)buf + 60) = flip32(externalTime.seconds);
    *(Integer32*)((char*)buf + 64) = flip32(externalTime.nanoseconds);
    
    *(Integer32*)((char*)buf + 68) = shift16(flip16(ptpClock->current_utc_offset), 1);
    *(Integer32*)((char*)buf + 72) = shift8(ptpClock->leap_59, 3);
    *(Integer32*)((char*)buf + 76) = shift8(ptpClock->leap_61, 3);
    *(Integer32*)((char*)buf + 80) = shift16(flip16(ptpClock->epoch_number), 1);
    return 84;
    
  case PTP_MM_GET_FOREIGN_DATA_SET:
    if((manage->targetPortId && manage->targetPortId != ptpClock->port_id_field)
      || !manage->recordKey || manage->recordKey > ptpClock->number_foreign_records)
    {
      *(UInteger8*)((char*)buf + 55) = PTP_MM_NULL;
      *(Integer32*)((char*)buf + 56) = shift16(flip16(0), 1);
      return 0;
    }
    
    *(UInteger8*)((char*)buf + 55) = PTP_MM_FOREIGN_DATA_SET;
    *(Integer32*)((char*)buf + 56) = shift16(flip16(28), 1);
    *(Integer32*)((char*)buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
    *(Integer32*)((char*)buf + 64) = shift16(flip16(manage->recordKey - 1), 1);
    *(Integer32*)((char*)buf + 68) = shift8(ptpClock->foreign[manage->recordKey - 1].foreign_master_communication_technology, 3);
    memcpy((char*)buf + 72, ptpClock->foreign[manage->recordKey - 1].foreign_master_uuid, 6);
    *(Integer32*)((char*)buf + 80) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_port_id), 1);
    *(Integer32*)((char*)buf + 84) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_syncs), 1);
    return 88;
    
  default:
    return 0;
  }
}