RTI Connext Micro
Version 2.4.1.0
|
Data Structures | |
struct | OSAPI_NtpTime |
NtpTime API. More... |
Macros | |
#define | OSAPI_NTP_TIME_SEC_MAX ((RTI_INT32)0x7fffffff) |
#define | OSAPI_NTP_TIME_FRAC_MAX ((RTI_UINT32)0xffffffff) |
#define | OSAPI_NtpTime_zero(time) |
Set struct OSAPI_NtpTime time to zero. | |
#define | OSAPI_NtpTime_set_max(time) |
Set struct OSAPI_NtpTime time to maximum value. | |
#define | OSAPI_NtpTime_from_millisec(time, s, msec) |
Macro to convert from seconds and milliseconds to struct OSAPI_NtpTime format. | |
#define | OSAPI_NtpTime_to_millisec(s, msec, time) |
Macro to convert from struct OSAPI_NtpTime to seconds and milliseconds. | |
#define | OSAPI_NtpTime_from_microsec(time, s, usec) |
Macro to convert from seconds and microseconds to struct OSAPI_NtpTime format. | |
#define | OSAPI_NtpTime_to_microsec(s, usec, time) |
Macro to convert from struct OSAPI_NtpTime to seconds and microseconds. | |
#define | OSAPI_NtpTime_from_nanosec(time, s, nsec) |
Macro to convert from seconds and nanoseconds to struct OSAPI_NtpTime format. | |
#define | OSAPI_NtpTime_to_nanosec(s, nsec, time) |
Macro to convert from struct OSAPI_NtpTime to seconds and nanoseconds. | |
#define | OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT 7 |
Precision used in bit manipulation for struct OSAPI_NtpTime fraction conversions. | |
#define | OSAPI_NtpTime_from_fraction(time, numerator, denominator_per_sec) |
Macro to convert numerator/denom_per_sec into NTP time. | |
#define | OSAPI_NtpTime_to_fraction(numerator, denominator_per_sec, time) |
Transforms from struct OSAPI_NtpTime to any integral fraction of a second without using floating point operations. | |
#define | OSAPI_NtpTime_compare(time1, time2) |
Compare two OSAPI_NtpTimes. | |
#define | OSAPI_NtpTime_is_infinite(time) |
#define | OSAPI_NtpTime_add(answer, t1, t2) |
answer = t1 + t2. | |
#define | OSAPI_NtpTime_subtract(answer, t1, t2) |
answer = t1 - t2. | |
#define | OSAPI_NtpTime_left_shift(answer, time, shift) |
answer = time << shift. | |
#define | OSAPI_NtpTime_right_shift(answer, time, shift) |
answer = time >> shift. | |
#define | OSAPI_NtpTime_increment(answer, time) |
answer += time. | |
#define | OSAPI_NtpTime_decrement(answer, time) |
Decrement one struct OSAPI_NtpTime value by another struct OSAPI_NtpTime value. | |
#define | OSAPI_NtpTime_increment_infinitesimally(time) ((++((time)->frac)) == 0) ? ++(time)->sec : 0 |
time = time + 1 fraction (~200 picoseconds). | |
#define | OSAPI_NtpTime_is_zero(time) |
#define | OSAPI_NTP_TIME_ZERO {0,0} |
Zero time. | |
#define | OSAPI_NTP_TIME_MAX {OSAPI_NTP_TIME_SEC_MAX,OSAPI_NTP_TIME_FRAC_MAX} |
#define | OSAPI_NTP_TIME_NSEC_PER_SEC (1000000000) |
#define | OSAPI_NTP_TIME_USEC_PER_SEC (1000000) |
#define | OSAPI_NTP_TIME_MSEC_PER_SEC (1000) |
#define | OSAPI_NTP_TIME_NSEC_PER_USEC (1000) |
#define | OSAPI_NTP_TIME_USEC_PER_MSEC (1000) |
#define | OSAPI_NTP_TIME_SEC_PER_SEC (1) |
#define | OSAPI_NTP_TIME_NSEC_PER_MSEC (1000000) |
Typedefs | |
typedef struct OSAPI_NtpTime | OSAPI_NtpTime |
NtpTime API. |
#define OSAPI_NTP_TIME_SEC_MAX ((RTI_INT32)0x7fffffff) |
The maximum number of seconds that can be represented using NTP time.
#define OSAPI_NTP_TIME_FRAC_MAX ((RTI_UINT32)0xffffffff) |
The largest possible value of the fraction field in NTP time.
#define OSAPI_NtpTime_zero | ( | time | ) |
Set struct OSAPI_NtpTime time to zero.
time | (struct OSAPI_NtpTime*) Pointer to struct OSAPI_NtpTime struct that needs to be set to zero. |
#define OSAPI_NtpTime_set_max | ( | time | ) |
Set struct OSAPI_NtpTime time to maximum value.
time | (struct OSAPI_NtpTime*) Pointer to struct OSAPI_NtpTime struct that needs to be set to its maximum possible value. |
The maximum possible value equals:
(time).sec = OSAPI_NTP_TIME_SEC_MAX (time).frac = OSAPI_NTP_TIME_FRAC_MAX
#define OSAPI_NtpTime_from_millisec | ( | time, | |
s, | |||
msec | |||
) |
Macro to convert from seconds and milliseconds to struct OSAPI_NtpTime format.
time | (struct OSAPI_NtpTime) contains the answer. |
s | (integer) Seconds to convert. |
msec | (millisecond) Fraction portion (less than 1000). |
struct OSAPI_NtpTime time; long sec, msec; sec = 10; msec = 577; OSAPI_NtpTime_packFromMillisec(time, sec, msec);
After the above call is made, the variable time will contain the equivalent timestamp in struct OSAPI_NtpTime representation.
This macro assumes that msec<1000. It is the caller's responsibility to ensure this. This is done for performance reasons (the extra check slows the execution by a factor of 5). If msec may be greater than 1000, you can invoke the macro as follows:
OSAPI_NtpTime_packFromMillisec(time, sec + msec/1000, msec%1000);
This macro only evaluates its arguments once, so it is safe to invoke it with an argument that has side effects; that is, if you write:
RTI_UINT32 count = 10; OSAPI_NtpTime_packFromMillisec(time, sec, count++)
After the macro count is guaranteed to be 11.
The accuracy of this conversion over the whole range of millisecond values is 0.013 milliseconds.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.06 usec.
2^22*time.frac = ms + ms/2^6 + ms/2^7 + ms/2^11 + ms/2^14 + 1.3e-5 = ms + ms*393/2^14; time.frac = (ms<<22) + (ms<<16) + (ms<<15) + (ms<<11) + (ms<<8) = (ms<<22) + ((ms*393)<<8)
#define OSAPI_NtpTime_to_millisec | ( | s, | |
msec, | |||
time | |||
) |
Macro to convert from struct OSAPI_NtpTime to seconds and milliseconds.
s | (integer) Holds the seconds answer. |
msec | (integer) Holds the millisecond answer. |
time | (struct OSAPI_NtpTime) The time to convert to seconds and milliseconds. |
This macro does not check for overflow, so for a near-infinite time value, the conversion result may end up being negative. It is the responsibility of the user to avoid passing these large time values.
Use as indicated by the following code:
} struct OSAPI_NtpTime time; long sec, msec; time.sec = 10; time.frac = 577; OSAPI_NtpTime_unpackToMillisec(sec, msec, time);
After the above call is made, the variables "sec" and "msec" will contain the equivalent timestamp.
The accuracy of this conversion over the whole range of struct OSAPI_NtpTime values is 0.5 milliseconds, except for ntp values above {0x7fffffff, 0x7fffffff}, accuracy is up to nearly 1 millisecond.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.08 usec.
ms/2^22 = frac*1000/1024 = frac*(1 - 24/1024) = frac*(1 - 3/2^7) = frac*(1 - 1/2^6 - 1/2^7)
#define OSAPI_NtpTime_from_microsec | ( | time, | |
s, | |||
usec | |||
) |
Macro to convert from seconds and microseconds to struct OSAPI_NtpTime format.
time | (struct OSAPI_NtpTime) to contain the answer. |
s | (integer) seconds of the time to covert. |
usec | (integer) microseconds fraction to convert from. |
This macro does not check for overflow, so for a near-infinite time value, the conversion result may end up being negative. It is the caller's responsibility to avoid passing these large time values.
Use as indicated by the following code:
struct OSAPI_NtpTime ntp; long sec, usec; sec = 10; usec = 577; OSAPI_NtpTime_packFromMicrosec(ntp, sec, usec);
After the above call is made, the variable ntp will contain the equivalent time stamp in struct OSAPI_NtpTime representation.
This macro assumes that msec<1000000. It is the caller's responsibility to ensure this. This is done for performance reasons, the extra check slows the execution a factor of 5! If msec may be greater than 1000000, you can invoke the macro as follows:
OSAPI_NtpTime_packFromMicrosec(ntp, sec + usec/1000000, usec%1000000);
This macro only evaluates its arguments once, so it is safe to invoke it with an argument that has side effects; that is, if you write:
RTI_UINT32 count = 10; OSAPI_NtpTime_packFromMicrosec(ntp, sec, count++)
After the macro, count is guaranteed to be 11.
The accuracy of this conversion over the whole range of microsecond values is 0.0028 microseconds.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.08 usec.
2^12 * ntp.frac = us + us/2^5 + us/2^6 + us/2^10 + us/2^11 + us/2^13 + us/2^14 + us/2^15 + us/2^16 + us/2^18 + us/2^19 + us/2^20 + us/2^21 + us/2^23 + 3e-9 = us + us*99/2^11 + us*15/2^16 + us*61/2^23 ntp.frac = (us<<12) + (us<<7) + (us<<6) + (us<<2) + (us<<1) + (us>>1) + (us>>2) + (us>>3) + (us>>4) + (us>>6) + (us>>7) + (us>>8) + (us>>9) + (us>>11) = (us<<12) + ((us*99)<<1)+ ((us*15)>>4)+ ((us*61)>>11)
#define OSAPI_NtpTime_to_microsec | ( | s, | |
usec, | |||
time | |||
) |
Macro to convert from struct OSAPI_NtpTime to seconds and microseconds.
s | (integer) Holds the second portion. |
usec | (integer) holds the microsecond fraction. |
time | (struct OSAPI_NtpTime) to be converted. |
This macro does not check for overflow, so for a near-infinite time value, the conversion result may end up being negative. It is the caller's responsibility to avoid passing these large time values.
Use as indicated by the following code:
struct OSAPI_NtpTime ntp; long sec, usec; ntp.sec = 10; ntp.frac = 577; OSAPI_NtpTime_unpackToMicrosec(sec, usec, ntp);
After the above call is made, the variables "sec" and "usec" will contain the equivalent timestamp.
The accuracy of this conversion over the whole range of struct OSAPI_NtpTime values is 0.5 microseconds, except for ntp value above {0x7fffffff, 0x7fffffff}, accuracy is up to nearly 1 millisecond.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.12 usec.
us = frac*1000000/2^20 = frac*( 1 - 48576/2^20 ) = frac*(1 - 47/2^10 - 7/2^14) = frac - ((47*frac)>>10) - ((7*frac)>>14) = frac - (frac>>5)-(frac>>7)-(frac>>8)-(frac>>9)-(frac>>10) - (frac>>12)-(frac>>13)-(frac>>14)
#define OSAPI_NtpTime_from_nanosec | ( | time, | |
s, | |||
nsec | |||
) |
Macro to convert from seconds and nanoseconds to struct OSAPI_NtpTime format.
time | (struct OSAPI_NtpTime) Holds the answer. |
s | (integer) Seconds to convert from. |
nsec | (integer) Nanosecond fraction to convert from. |
Use as indicated by the following code:
struct OSAPI_NtpTime time; long sec, nsec; sec = 10; nsec = 577; OSAPI_NtpTime_packFromNanosec(time, sec, msec);
After the above call is made, the variable time will contain the equivalent timestamp in struct OSAPI_NtpTime representation.
This macro assumes that nsec<1000000000. It is the caller's responsibility to ensure this. This is done for performance reasons (the extra check slows the execution a factor of 5). If msec may be greater than 1000000, you can invoke the macro as follows:
} OSAPI_NtpTime_packFromNanosec(time, sec + nsec/1000000000, nsec%1000000000);
This macro only evaluates its arguments once, so it is safe to invoke it with an argument that has side effects; that is, if you write:
RTI_UINT32 count = 10; OSAPI_NtpTime_packFromNanosec(time, sec, count++)
After the macro, count is guaranteed to be 11.
The accuracy of this conversion over the whole range of nanosecond values is 0.5 nanoseconds, except for ntp value above {0x7fffffff, 0x7fffffff}, accuracy is up to nearly 1 millisecond.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.10 usec.
2^32/10^9 ns = 4*ns + ns/2^2 + ns/2^5 + ns/2^7 + ns/2^8 + ns/2^9 + ns/2^15 + ns/2^17 + ns/2^18 + ns/2^19 + ns/2^20 + ns/2^21 + ns/2^23 + ns/2^29 + ns/2^32 2^32/10^9 ns = 4*ns + (ns + ns/2^3 + ns/2^5 + ns/2^6 + ns/2^7 + ns/2^13 + ns/2^15 + ns/2^16 + ns/2^17 + ns/2^18 + ns/2^19 + ns/2^21 + ns/2^27 + ns/2^30)*(1/2^2)
#define OSAPI_NtpTime_to_nanosec | ( | s, | |
nsec, | |||
time | |||
) |
Macro to convert from struct OSAPI_NtpTime to seconds and nanoseconds.
s | (integer) Second of the time to covert. |
nsec | (integer) Nanosecond fraction to convert. |
time | (struct OSAPI_NtpTime) to convert from. |
Use as indicated by the following code:
struct OSAPI_NtpTime time; long sec, nsec; time.sec = 10; time.frac = 577; OSAPI_NtpTime_unpackToNanosec(sec, nsec, time);
After the above call is made, the variables "sec" and "nsec" will contain the equivalent timestamp.
The accuracy of this conversion over the whole range of struct OSAPI_NtpTime values is 0.5 nsec.
This is a fairly efficient macro. On a 400MHz Pentium-II Linux box the execution time is about 0.09 usec.
Given that 294967296 = 0x1194d800 and:
4*ns = frac*4000000000/2^32 = frac*(1 - 294967296/2^32) = frac*(1 - 1/2^4 - 1/2^8 - 9/2^12 - 4/2^16 - 13/2^20 - 8/2^24) = frac*(1 - 1>>4 - 1>>8 - 1>>9 - 1>>12 - 1>>14 - 1>>17 - 1>>18 - 1>>20 - 1>>21)
#define OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT 7 |
Precision used in bit manipulation for struct OSAPI_NtpTime fraction conversions.
The larger the precision, the more bits you pick up in the long division to get the fraction. If the precision is too large, so that the denominator shifted by the precision bits exceeds the 2^32 limit, the result will be incorrect. For example, if the denominator is 60 (such as for the VxWorks sysClkRate), precision_bits larger than 27 exceed the limit and produce an incorrect result. In general:
maximum precision_bits = 32 - (int)log2(denominator_per_sec),
where log2(x) can be calculated by:
int log2answer = 0; while (x >>= 1) {1 log2answer++; }
For 60 (sysClkRateGet()), this would be 27. For gettimeofday() with microsec resolution, this would be 12.
But in practice, that kind of precision is not necessary nor desirable since the conversion would be slower. Instead, the precision is only important relative to the denominator. If your clock frequency is low (e.g., 60 Hz), you only have 16.6 ms resolution anyway. If you are within a tenth of your clock resolution, that is probably good enough.
If we generalized too much and tried to handle nanosec resolution "ticks," we could not guarantee adequate accuracy for all ranges. So internally, we selected a reasonable number that gives us adequate accuracy over large ranges. We wanted a precision that will work well up to 1e6 tick rate (thinking about UNIX gettimeofday()); 7 passed the test.
#define OSAPI_NtpTime_from_fraction | ( | time, | |
numerator, | |||
denominator_per_sec | |||
) |
Macro to convert numerator/denom_per_sec into NTP time.
time | struct OSAPI_NtpTime to contain the result. The existing content of time does not affect the result. |
numerator | May be larger than denominator. Since this is a macro and the numerator is evaluated multiple times, you should not specify things like (i++). |
denominator_per_sec | Denominator. Physically, this means ticks per sec. Since this is a macro and the denominator is evaluated multiple times, you should not specify things like (i++). |
#define OSAPI_NtpTime_to_fraction | ( | numerator, | |
denominator_per_sec, | |||
time | |||
) |
Transforms from struct OSAPI_NtpTime to any integral fraction of a second without using floating point operations.
numerator | RTI_UINT32 where to put the result of the conversion. |
denominator_per_sec | The number of units of the fraction contained in a second. For example, this should be 1000 to convert to milliseconds, or 60 if you are using the default VxWorks clock rate. |
time | struct OSAPI_NtpTime to unpack |
The algoritm is based on the observation that the time.frac looked at as a sequence of bits: b[1], b[2], b[3], ... represents the following expansion:
time_in_sec = b[1]*1/2 + b[1]*1/4 +...+ b[2]*1/8 = Sum{i=1..32} b[i]*1/2^i
Since we want to obtain the time in units of which there are denominator_per_sec units in a second, the arithmetic is:
time_in_units = denominator_per_sec*time_in_sec = denominator_per_sec*time.sec+denominator_per_sec*time.frac
And denominator_per_sec*time.frac = Sum{i=1..32} b[i]*(denominator_per_sec/2^i)
The key here is that b[i] is easily computed as (1<<31)>>(i-1) and (denominator_per_sec/2^i) is easily computed as denominator_per_sec>>i.
Note that each time we compute (denominator_per_sec/2^i) to add it, we may be off by one unit. Therefore, at the end of the computation we may be off by log2(denominator_per_sec) units, which means we should in fact perform each step with an accuracy of log2(2*denominator_per_sec) greater. In other words, we should use units a factor log2(2*denominator_per_sec) greater than the ones we require at the end of the conversion.
Another key observation is that the computation can end as soon as (denominator_per_sec<<OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT)>>i becomes zero because that means what is left has a significance of less than one unit>>OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT. This will give a conversion that is strictly smaller than the NTP timestamp. For example, for millisecond conversion log2(1000) = 10, we will do 10 operations so we need a precision of 1/20 or 5 bits (4 bits gives 1/16, 5 gives 1/32).
The final operation: (precision_units + (1<<OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT-1))>> OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT; makes sure that the integer division by 2^(OSAPI_NTP_TIME_PRECISION_BITS_DEFAULT) is rounded off to the closest number.
#define OSAPI_NtpTime_compare | ( | time1, | |
time2 | |||
) |
Compare two OSAPI_NtpTimes.
time1 | struct OSAPI_NtpTime, NOT NULL. |
time2 | struct OSAPI_NtpTime, NOT NULL. |
#define OSAPI_NtpTime_is_infinite | ( | time | ) |
A NULL struct OSAPI_NtpTime pointer is considered infinity. This is consistent with the concept of infinite time on UNIX systems.
In addition, if the seconds field equals OSAPI_NTP_TIME_SEC_MAX, the time value is also considered infinite.
time | Pointer to RTITime. |
#define OSAPI_NtpTime_add | ( | answer, | |
t1, | |||
t2 | |||
) |
answer = t1 + t2.
This macro does not check for overflow.
answer | struct OSAPI_NtpTime |
t1 | struct OSAPI_NtpTime |
t2 | struct OSAPI_NtpTime |
#define OSAPI_NtpTime_subtract | ( | answer, | |
t1, | |||
t2 | |||
) |
answer = t1 - t2.
answer | struct OSAPI_NtpTime |
t1 | struct OSAPI_NtpTime` |
t2 | struct OSAPI_NtpTime |
#define OSAPI_NtpTime_left_shift | ( | answer, | |
time, | |||
shift | |||
) |
answer = time << shift.
To use this macro for multiplying by num, shift can be calculated as log10(num)/log10(2).
answer | struct OSAPI_NtpTime |
time | struct OSAPI_NtpTime |
shift | int |
#define OSAPI_NtpTime_right_shift | ( | answer, | |
time, | |||
shift | |||
) |
answer = time >> shift.
To use this macro for dividing by num, shift can be calculated as log10(num)/log10(2).
answer | struct OSAPI_NtpTime |
time | struct OSAPI_NtpTime |
shift | int |
#define OSAPI_NtpTime_increment | ( | answer, | |
time | |||
) |
answer += time.
This macro does not check for overflow.
answer | struct OSAPI_NtpTime |
time | struct OSAPI_NtpTime |
#define OSAPI_NtpTime_decrement | ( | answer, | |
time | |||
) |
Decrement one struct OSAPI_NtpTime value by another struct OSAPI_NtpTime value.
Precondition: Postcondition: answer -= time.
answer | struct OSAPI_NtpTime |
time | struct OSAPI_NtpTime |
#define OSAPI_NtpTime_increment_infinitesimally | ( | time | ) | ((++((time)->frac)) == 0) ? ++(time)->sec : 0 |
time = time + 1 fraction (~200 picoseconds).
This macro does not check for overflow, so time cannot be infinite.
time |
#define OSAPI_NtpTime_is_zero | ( | time | ) |
Checks if the time structure represents zero time. Zero time may be useful when getting the sign of the time quantity.
time | Pointer to struct OSAPI_NtpTime. Must not be NULL. |
#define OSAPI_NTP_TIME_ZERO {0,0} |
Zero time.
This global variable is for convenience. It allows you to see if a RTITime variable is negative or positive by comparing against this.
#define OSAPI_NTP_TIME_MAX {OSAPI_NTP_TIME_SEC_MAX,OSAPI_NTP_TIME_FRAC_MAX} |
Represents the maximum timevalue that can be represented using the NTP time format. For all practical purposes, it can be considered equivalent to infinity.
#define OSAPI_NTP_TIME_NSEC_PER_SEC (1000000000) |
The number of nanoseconds per second. 1e9.
#define OSAPI_NTP_TIME_USEC_PER_SEC (1000000) |
The number of microseconds per second. 1e6.
#define OSAPI_NTP_TIME_MSEC_PER_SEC (1000) |
The number of milliseconds per second. 1e3.
#define OSAPI_NTP_TIME_NSEC_PER_USEC (1000) |
The number of microseconds per milliseconds. 1e3.
#define OSAPI_NTP_TIME_USEC_PER_MSEC (1000) |
The number of microseconds per milliseconds. 1e3.
#define OSAPI_NTP_TIME_SEC_PER_SEC (1) |
The number of seconds per second. 1.
#define OSAPI_NTP_TIME_NSEC_PER_MSEC (1000000) |
The number of nano seconds per milli second. 1e6.
typedef struct OSAPI_NtpTime OSAPI_NtpTime |
NtpTime API.
NTP Time representation.
Expresses time in NTP format. The second field is simply an integer expressing seconds. The fraction field expresses 1/2^32 of a second. We strongly urge customers to use our provided macros to convert this format to and from human readable form.
OSAPI_NtpTime_init must be called before OSAPI_NtpTime_get. Creating a domain has the side-effect of calling OSAPI_NtpTime_init.
Example:
The following is a simple example on how to prepare a struct OSAPI_NtpTime structure to be 1.5 seconds.
struct OSAPI_NtpTime ntpTime; OSAPI_NtpTime_packFromMillisec(ntpTime, 1, 500);