vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Shared.C
Go to the documentation of this file.
1#include <math.h> // for floor, fmod
2#include <stddef.h> // for size_t
3#include <stdio.h> // for fprintf() and such
4#include <ctime>
5
6#ifdef _MSC_VER
7// Don't tell us about strcpy being dangerous.
8#define _CRT_SECURE_NO_WARNINGS 1
9#pragma warning(disable : 4996)
10#endif
11
12#include "vrpn_Shared.h"
13
14#if defined(__APPLE__) || defined(__ANDROID__)
15#include <unistd.h>
16#endif
17
18#if !(defined(_WIN32) && defined(VRPN_USE_WINSOCK_SOCKETS))
19#include <sys/select.h> // for select
20#include <netinet/in.h> // for htonl, htons
21#endif
22
23#define CHECK(a) \
24 if (a == -1) return -1
25
26#if defined(VRPN_USE_WINSOCK_SOCKETS)
27/* from HP-UX */
28struct timezone {
29 int tz_minuteswest; /* minutes west of Greenwich */
30 int tz_dsttime; /* type of dst correction */
31};
32#endif
33
34// perform normalization of a timeval
35// XXX this still needs to be checked for errors if the timeval
36// or the rate is negative
37static inline void timevalNormalizeInPlace(timeval &in_tv)
38{
39 const long div_77777 = (in_tv.tv_usec / 1000000);
40 in_tv.tv_sec += div_77777;
41 in_tv.tv_usec -= (div_77777 * 1000000);
42}
43timeval vrpn_TimevalNormalize(const timeval &in_tv)
44{
45 timeval out_tv = in_tv;
46 timevalNormalizeInPlace(out_tv);
47 return out_tv;
48}
49
50// Calcs the sum of tv1 and tv2. Returns the sum in a timeval struct.
51// Calcs negative times properly, with the appropriate sign on both tv_sec
52// and tv_usec (these signs will match unless one of them is 0).
53// NOTE: both abs(tv_usec)'s must be < 1000000 (ie, normal timeval format)
54timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
55{
56 timeval tvSum = tv1;
57
58 tvSum.tv_sec += tv2.tv_sec;
59 tvSum.tv_usec += tv2.tv_usec;
60
61 // do borrows, etc to get the time the way i want it: both signs the same,
62 // and abs(usec) less than 1e6
63 if (tvSum.tv_sec > 0) {
64 if (tvSum.tv_usec < 0) {
65 tvSum.tv_sec--;
66 tvSum.tv_usec += 1000000;
67 }
68 else if (tvSum.tv_usec >= 1000000) {
69 tvSum.tv_sec++;
70 tvSum.tv_usec -= 1000000;
71 }
72 }
73 else if (tvSum.tv_sec < 0) {
74 if (tvSum.tv_usec > 0) {
75 tvSum.tv_sec++;
76 tvSum.tv_usec -= 1000000;
77 }
78 else if (tvSum.tv_usec <= -1000000) {
79 tvSum.tv_sec--;
80 tvSum.tv_usec += 1000000;
81 }
82 }
83 else {
84 // == 0, so just adjust usec
85 if (tvSum.tv_usec >= 1000000) {
86 tvSum.tv_sec++;
87 tvSum.tv_usec -= 1000000;
88 }
89 else if (tvSum.tv_usec <= -1000000) {
90 tvSum.tv_sec--;
91 tvSum.tv_usec += 1000000;
92 }
93 }
94
95 return tvSum;
96}
97
98// Calcs the diff between tv1 and tv2. Returns the diff in a timeval struct.
99// Calcs negative times properly, with the appropriate sign on both tv_sec
100// and tv_usec (these signs will match unless one of them is 0)
101timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
102{
103 timeval tv;
104
105 tv.tv_sec = -tv2.tv_sec;
106 tv.tv_usec = -tv2.tv_usec;
107
108 return vrpn_TimevalSum(tv1, tv);
109}
110
111timeval vrpn_TimevalScale(const timeval &tv, double scale)
112{
113 timeval result;
114 result.tv_sec = (long)(tv.tv_sec * scale);
115 result.tv_usec =
116 (long)(tv.tv_usec * scale + fmod(tv.tv_sec * scale, 1.0) * 1000000.0);
117 timevalNormalizeInPlace(result);
118 return result;
119}
120
121// returns 1 if tv1 is greater than tv2; 0 otherwise
122bool vrpn_TimevalGreater(const timeval &tv1, const timeval &tv2)
123{
124 if (tv1.tv_sec > tv2.tv_sec) return 1;
125 if ((tv1.tv_sec == tv2.tv_sec) && (tv1.tv_usec > tv2.tv_usec)) return 1;
126 return 0;
127}
128
129// return 1 if tv1 is equal to tv2; 0 otherwise
130bool vrpn_TimevalEqual(const timeval &tv1, const timeval &tv2)
131{
132 if (tv1.tv_sec == tv2.tv_sec && tv1.tv_usec == tv2.tv_usec)
133 return true;
134 else
135 return false;
136}
137
138unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
139{
140 return (endT.tv_usec - startT.tv_usec) +
141 1000000L * (endT.tv_sec - startT.tv_sec);
142}
143
144double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
145{
146 return (endT.tv_usec - startT.tv_usec) / 1000000.0 +
147 (endT.tv_sec - startT.tv_sec);
148}
149
150double vrpn_TimevalMsecs(const timeval &tv)
151{
152 return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
153}
154
155timeval vrpn_MsecsTimeval(const double dMsecs)
156{
157 timeval tv;
158 tv.tv_sec = (long)floor(dMsecs / 1000.0);
159 tv.tv_usec = (long)((dMsecs / 1000.0 - tv.tv_sec) * 1e6);
160 return tv;
161}
162
163// Sleep for dMsecs milliseconds, freeing up the processor while you
164// are doing so.
165
166void vrpn_SleepMsecs(double dMilliSecs)
167{
168#if defined(_WIN32)
169 Sleep((DWORD)dMilliSecs);
170#else
171 timeval timeout;
172
173 // Convert milliseconds to seconds
174 timeout.tv_sec = (int)(dMilliSecs / 1000.0);
175
176 // Subtract of whole number of seconds
177 dMilliSecs -= timeout.tv_sec * 1000;
178
179 // Convert remaining milliseconds to microsec
180 timeout.tv_usec = (int)(dMilliSecs * 1000);
181
182 // A select() with NULL file descriptors acts like a microsecond
183 // timer.
184 select(0, 0, 0, 0, &timeout); // wait for that long;
185#endif
186}
187
188// convert vrpn_float64 to/from network order
189// I have chosen big endian as the network order for vrpn_float64
190// to match the standard for htons() and htonl().
191// NOTE: There is an added complexity when we are using an ARM
192// processor in mixed-endian mode for the doubles, whereby we need
193// to not just swap all of the bytes but also swap the two 4-byte
194// words to get things in the right order.
195#if defined(__arm__)
196#include <endian.h>
197#endif
198
199vrpn_float64 vrpn_htond(vrpn_float64 d)
200{
201 if (!vrpn_big_endian) {
202 vrpn_float64 dSwapped;
203 char *pchSwapped = (char *)&dSwapped;
204 char *pchOrig = (char *)&d;
205
206 // swap to big-endian order.
207 unsigned i;
208 for (i = 0; i < sizeof(vrpn_float64); i++) {
209 pchSwapped[i] = pchOrig[sizeof(vrpn_float64) - i - 1];
210 }
211
212#if defined(__arm__) && !defined(__ANDROID__)
213// On ARM processor, see if we're in mixed mode. If so,
214// we need to swap the two words after doing the total
215// swap of bytes.
216#if __FLOAT_WORD_ORDER != __BYTE_ORDER
217 {
218 /* Fixup mixed endian floating point machines */
219 vrpn_uint32 *pwSwapped = (vrpn_uint32 *)&dSwapped;
220 vrpn_uint32 scratch = pwSwapped[0];
221 pwSwapped[0] = pwSwapped[1];
222 pwSwapped[1] = scratch;
223 }
224#endif
225#endif
226
227 return dSwapped;
228 }
229 else {
230 return d;
231 }
232}
233
234// they are their own inverses, so ...
235vrpn_float64 vrpn_ntohd(vrpn_float64 d) { return vrpn_htond(d); }
236
250VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
251{
252 vrpn_int32 sec, usec;
253
254 // tv_sec and usec are 64 bits on some architectures, but we
255 // define them as 32 bit for network transmission
256
257 sec = t.tv_sec;
258 usec = t.tv_usec;
259
260 if (vrpn_buffer(insertPt, buflen, sec)) return -1;
261 return vrpn_buffer(insertPt, buflen, usec);
262}
263
280VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen,
281 const char *string, vrpn_int32 length)
282{
283 if (length > *buflen) {
284 fprintf(stderr, "vrpn_buffer: buffer not long enough for string.\n");
285 return -1;
286 }
287
288 if (length == -1) {
289 size_t len =
290 strlen(string) + 1; // +1 for the NULL terminating character
291 if (len > (unsigned)*buflen) {
292 fprintf(stderr,
293 "vrpn_buffer: buffer not long enough for string.\n");
294 return -1;
295 }
296 strcpy(*insertPt, string);
297 *insertPt += len;
298 *buflen -= static_cast<vrpn_int32>(len);
299 }
300 else {
301 memcpy(*insertPt, string, length);
302 *insertPt += length;
303 *buflen -= length;
304 }
305
306 return 0;
307}
308
321VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
322{
323 vrpn_int32 sec, usec;
324
325 CHECK(vrpn_unbuffer(buffer, &sec));
326 CHECK(vrpn_unbuffer(buffer, &usec));
327
328 t->tv_sec = sec;
329 t->tv_usec = usec;
330
331 return 0;
332}
333
356VRPN_API int vrpn_unbuffer(const char **buffer, char *string, vrpn_int32 length)
357{
358 if (!string) return -1;
359
360 if (length < 0) {
361 // Read the string up to maximum length, then check to make sure we
362 // found the null-terminator in the length we read.
363 size_t max_len = static_cast<size_t>(-length);
364 strncpy(string, *buffer, max_len);
365 size_t i;
366 bool found = false;
367 for (i = 0; i < max_len; i++) {
368 if (string[i] == '\0') {
369 found = true;
370 break;
371 }
372 }
373 if (!found) {
374 return -1;
375 }
376 *buffer += strlen(*buffer) + 1; // +1 for NULL terminating character
377 } else {
378 memcpy(string, *buffer, length);
379 *buffer += length;
380 }
381
382 return 0;
383}
384
385//=====================================================================
386// This section contains various implementations of vrpn_gettimeofday().
387// Which one is selected depends on various #defines. There is a second
388// section that deals with handling various configurations on Windows.
389// The first section deals with the fact that we may want to use the
390// std::chrono classes introduced in C++-11 as a cross-platform (even
391// Windows) solution to timing. If VRPN_USE_STD_CHRONO is defined, then
392// we do this -- converting from chrono epoch and interval into the
393// gettimeofday() standard tick of microseconds and epoch start of
394// midnight, January 1, 1970.
395
397// Implementation with std::chrono follows, and overrides any of
398// the Windows-specific definitions if it is present.
400
401#ifdef VRPN_USE_STD_CHRONO
402#include <chrono>
403
405// With Visual Studio 2013 64-bit, the hires clock produces a clock that has a
406// tick interval of around 15.6 MILLIseconds, repeating the same
407// time between them.
409// With Visual Studio 2015 64-bit, the hires clock produces a good, high-
410// resolution clock with no blips. However, its epoch seems to
411// restart when the machine boots, whereas the system clock epoch
412// starts at the standard midnight January 1, 1970.
414
416// Helper function to convert from the high-resolution clock
417// time to the equivalent system clock time (assuming no clock
418// adjustment on the system clock since program start).
419// To make this thread safe, we semaphore the determination of
420// the offset to be applied. To handle a slow-ticking system
421// clock, we repeatedly sample it until we get a change.
422// This assumes that the high-resolution clock on different
423// threads has the same epoch.
425
426static bool hr_offset_determined = false;
427static vrpn_Semaphore hr_offset_semaphore;
428static struct timeval hr_offset;
429
430static struct timeval high_resolution_time_to_system_time(
431 struct timeval hi_res_time //< Time computed from high-resolution clock
432 )
433{
434 // If we haven't yet determined the offset between the high-resolution
435 // clock and the system clock, do so now. Avoid a race between threads
436 // using the semaphore and checking the boolean both before and after
437 // grabbing the semaphore (in case someone beat us to it).
438 if (!hr_offset_determined) {
439 hr_offset_semaphore.p();
440 // Someone else who had the semaphore may have beaten us to this.
441 if (!hr_offset_determined) {
442 // Watch the system clock until it changes; this will put us
443 // at a tick boundary. On many systems, this will change right
444 // away, but on Windows 8 it will only tick every 16ms or so.
445 std::chrono::system_clock::time_point pre =
446 std::chrono::system_clock::now();
447 std::chrono::system_clock::time_point post;
448 // On Windows 8.1, this took from 1-16 ticks, and seemed to
449 // get offsets to the epoch that were consistent to within
450 // around 1ms.
451 do {
452 post = std::chrono::system_clock::now();
453 } while (pre == post);
454
455 // Now read the high-resolution timer to find out the time
456 // equivalent to the post time on the system clock.
457 std::chrono::high_resolution_clock::time_point high =
458 std::chrono::high_resolution_clock::now();
459
460 // Now convert both the hi-resolution clock time and the
461 // post-tick system clock time into struct timevals and
462 // store the difference between them as the offset.
463 std::time_t high_secs =
464 std::chrono::duration_cast<std::chrono::seconds>(
465 high.time_since_epoch())
466 .count();
467 std::chrono::high_resolution_clock::time_point
468 fractional_high_secs = high - std::chrono::seconds(high_secs);
469 struct timeval high_time;
470 high_time.tv_sec = static_cast<unsigned long>(high_secs);
471 high_time.tv_usec = static_cast<unsigned long>(
472 std::chrono::duration_cast<std::chrono::microseconds>(
473 fractional_high_secs.time_since_epoch())
474 .count());
475
476 std::time_t post_secs =
477 std::chrono::duration_cast<std::chrono::seconds>(
478 post.time_since_epoch())
479 .count();
480 std::chrono::system_clock::time_point fractional_post_secs =
481 post - std::chrono::seconds(post_secs);
482 struct timeval post_time;
483 post_time.tv_sec = static_cast<unsigned long>(post_secs);
484 post_time.tv_usec = static_cast<unsigned long>(
485 std::chrono::duration_cast<std::chrono::microseconds>(
486 fractional_post_secs.time_since_epoch())
487 .count());
488
489 hr_offset = vrpn_TimevalDiff(post_time, high_time);
490
491 // We've found our offset ... re-use it from here on.
492 hr_offset_determined = true;
493 }
494 hr_offset_semaphore.v();
495 }
496
497 // The offset has been determined, by us or someone else. Apply it.
498 return vrpn_TimevalSum(hi_res_time, hr_offset);
499}
500
501int vrpn_gettimeofday(timeval *tp, void *tzp)
502{
503 // If we have nothing to fill in, don't try.
504 if (tp == NULL) {
505 return 0;
506 }
507 struct timezone *timeZone = reinterpret_cast<struct timezone *>(tzp);
508
509 // Find out the time, and how long it has been in seconds since the
510 // epoch.
511 std::chrono::high_resolution_clock::time_point now =
512 std::chrono::high_resolution_clock::now();
513 std::time_t secs =
514 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch())
515 .count();
516
517 // Subtract the time in seconds from the full time to get a
518 // remainder that is a fraction of a second since the epoch.
519 std::chrono::high_resolution_clock::time_point fractional_secs =
520 now - std::chrono::seconds(secs);
521
522 // Store the seconds and the fractional seconds as microseconds into
523 // the timeval structure. Then convert from the hi-res clock time
524 // to system clock time.
525 struct timeval hi_res_time;
526 hi_res_time.tv_sec = static_cast<unsigned long>(secs);
527 hi_res_time.tv_usec = static_cast<unsigned long>(
528 std::chrono::duration_cast<std::chrono::microseconds>(
529 fractional_secs.time_since_epoch())
530 .count());
531 *tp = high_resolution_time_to_system_time(hi_res_time);
532
533 // @todo Fill in timezone structure with relevant info.
534 if (timeZone != NULL) {
535 timeZone->tz_minuteswest = 0;
536 timeZone->tz_dsttime = 0;
537 }
538
539 return 0;
540}
541
542#else // VRPN_USE_STD_CHRONO
543
545// Implementation without std::chrono follows.
547
549// More accurate gettimeofday() on some Windows operating systems
550// and machines can be gotten by using the Performance Counter
551// on the CPU. This doesn't seem to work in NT/2000 for some
552// computers, so the code to do it is #defined out by default.
553// To put it back back, #define VRPN_UNSAFE_WINDOWS_CLOCK and
554// the following code will use the performance counter (which it
555// takes a second to calibrate at program start-up).
557
558#ifndef VRPN_UNSAFE_WINDOWS_CLOCK
559
560#if defined(_WIN32) && !defined(__CYGWIN__)
561#include <math.h> // for floor, fmod
562
563#pragma optimize("", on)
564
565#ifdef _WIN32
566void get_time_using_GetLocalTime(unsigned long &sec, unsigned long &usec)
567{
568 SYSTEMTIME stime; // System time in funky structure
569 FILETIME ftime; // Time in 100-nsec intervals since Jan 1 1601
570 ULARGE_INTEGER tics; // ftime stored into a 64-bit quantity
571
572 GetLocalTime(&stime);
573 SystemTimeToFileTime(&stime, &ftime);
574
575 // Copy the data into a structure that can be treated as a 64-bit integer
576 tics.HighPart = ftime.dwHighDateTime;
577 tics.LowPart = ftime.dwLowDateTime;
578
579 // Change units (100 nanoseconds --> microseconds)
580 tics.QuadPart /= 10;
581
582 // Subtract the offset between the two clock bases (Jan 1, 1601 --> Jan 1, 1970)
583 tics.QuadPart -= 11644473600000000ULL;
584
585 // Convert the 64-bit time into seconds and microseconds since Jan 1 1970
586 sec = (unsigned long)(tics.QuadPart / 1000000UL);
587 usec = (unsigned long)(tics.QuadPart % 1000000UL);
588}
589#endif
590
592// Although VC++ doesn't include a gettimeofday
593// call, Cygnus Solutions Cygwin32 environment does,
594// so this is not used when compiling with gcc under WIN32.
595// XXX Note that the cygwin one was wrong in an earlier
596// version. It is claimed that they have fixed it now, but
597// better check.
599int vrpn_gettimeofday(timeval *tp, void *tzp)
600{
601 struct timezone *timeZone = reinterpret_cast<struct timezone *>(tzp);
602
603 if (tp != NULL) {
604#ifdef _WIN32_WCE
605 unsigned long sec, usec;
606 get_time_using_GetLocalTime(sec, usec);
607 tp->tv_sec = sec;
608 tp->tv_usec = usec;
609#else
610 struct _timeb t;
611 _ftime(&t);
612 tp->tv_sec = t.time;
613 tp->tv_usec = (long)t.millitm * 1000;
614#endif
615 }
616 if (tzp != NULL) {
617 TIME_ZONE_INFORMATION tz;
618 GetTimeZoneInformation(&tz);
619 timeZone->tz_minuteswest = tz.Bias;
620 timeZone->tz_dsttime = (tz.StandardBias != tz.Bias);
621 }
622 return 0;
623}
624
625#endif // defined(_WIN32)
626
627#else // In the case that VRPN_UNSAFE_WINDOWS_CLOCK is defined
628
629// Although VC++ doesn't include a gettimeofday
630// call, Cygnus Solutions Cygwin32 environment does.
631// XXX AND ITS WRONG in the current release 10/11/99, version b20.1
632// They claim it will be fixed in the next release, version b21
633// so until then, we will make it right using our solution.
634#if defined(_WIN32) && !defined(__CYGWIN__)
635#include <math.h> // for floor, fmod
636
637// utility routines to read the pentium time stamp counter
638// QueryPerfCounter drifts too much -- others have documented this
639// problem on the net
640
641// This is all based on code extracted from the UNC hiball tracker cib lib
642
643// 200 mhz pentium default -- we change this based on our calibration
644static __int64 VRPN_CLOCK_FREQ = 200000000;
645
646// Helium to histidine
647// __int64 FREQUENCY = 199434500;
648
649// tori -- but queryperfcounter returns this for us
650// __int64 FREQUENCY = 198670000;
651
652// Read Time Stamp Counter
653#define rdtsc(li) \
654 { \
655 _asm _emit 0x0f _asm _emit 0x31 _asm mov li.LowPart, \
656 eax _asm mov li.HighPart, edx \
657 }
658
659/*
660 * calculate the time stamp counter register frequency (clock freq)
661 */
662#ifndef VRPN_WINDOWS_CLOCK_V2
663#pragma optimize("", off)
664static int vrpn_AdjustFrequency(void)
665{
666 const int loops = 2;
667 const int tPerLoop = 500; // milliseconds for Sleep()
668 fprintf(stderr, "vrpn vrpn_gettimeofday: determining clock frequency...");
669
670 LARGE_INTEGER startperf, endperf;
671 LARGE_INTEGER perffreq;
672
673 // See if the hardware supports the high-resolution performance counter.
674 // If so, get the frequency of it. If not, we can't use it and so return
675 // -1.
676 if (QueryPerformanceFrequency(&perffreq) == 0) {
677 return -1;
678 }
679
680 // don't optimize away these variables
681 double sum = 0;
682 volatile LARGE_INTEGER liStart, liEnd;
683
684 DWORD dwPriorityClass = GetPriorityClass(GetCurrentProcess());
685 int iThreadPriority = GetThreadPriority(GetCurrentThread());
686 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
687 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
688
689 // pull all into cache and do rough test to see if tsc and perf counter
690 // are one and the same
691 rdtsc(liStart);
692 QueryPerformanceCounter(&startperf);
693 Sleep(100);
694 rdtsc(liEnd);
695 QueryPerformanceCounter(&endperf);
696
697 double freq = perffreq.QuadPart * (liEnd.QuadPart - liStart.QuadPart) /
698 ((double)(endperf.QuadPart - startperf.QuadPart));
699
700 if (fabs(perffreq.QuadPart - freq) < 0.05 * freq) {
701 VRPN_CLOCK_FREQ = (__int64)perffreq.QuadPart;
702 fprintf(stderr, "\nvrpn vrpn_gettimeofday: perf clock is tsc -- using "
703 "perf clock freq ( %lf MHz)\n",
704 perffreq.QuadPart / 1e6);
705 SetPriorityClass(GetCurrentProcess(), dwPriorityClass);
706 SetThreadPriority(GetCurrentThread(), iThreadPriority);
707 return 0;
708 }
709
710 // either tcs and perf clock are not the same, or we could not
711 // tell accurately enough with the short test. either way we now
712 // need an accurate frequency measure, so ...
713
714 fprintf(stderr, " (this will take %lf seconds)...\n",
715 loops * tPerLoop / 1000.0);
716
717 for (int j = 0; j < loops; j++) {
718 rdtsc(liStart);
719 QueryPerformanceCounter(&startperf);
720 Sleep(tPerLoop);
721 rdtsc(liEnd);
722 QueryPerformanceCounter(&endperf);
723
724 // perf counter timer ran for one call to Query and one call to
725 // tcs read in addition to the time between the tsc readings
726 // tcs read did the same
727
728 // endperf - startperf / perf freq = time between perf queries
729 // endtsc - starttsc = clock ticks between perf queries
730 // sum += (endtsc - starttsc) / ((double)(endperf -
731 // startperf)/perffreq);
732 sum += perffreq.QuadPart * (liEnd.QuadPart - liStart.QuadPart) /
733 ((double)(endperf.QuadPart - startperf.QuadPart));
734 }
735
736 SetPriorityClass(GetCurrentProcess(), dwPriorityClass);
737 SetThreadPriority(GetCurrentThread(), iThreadPriority);
738
739 // might want last, not sum -- just get into cache and run
740 freq = (sum / loops);
741
742 // if we are on a uniprocessor system, then use the freq estimate
743 // This used to check against a 200 mhz assumed clock, but now
744 // we assume the routine works and trust the result.
745 // if (fabs(freq - VRPN_CLOCK_FREQ) > 0.05 * VRPN_CLOCK_FREQ) {
746 // cerr << "vrpn vrpn_gettimeofday: measured freq is " << freq/1e6
747 // << " MHz - DOES NOT MATCH" << endl;
748 // return -1;
749 // }
750
751 // if we are in a system where the perf clock is the tsc, then use the
752 // rate the perf clock returns (or rather, if the freq we measure is
753 // approx the perf clock freq).
754 if (fabs(perffreq.QuadPart - freq) < 0.05 * freq) {
755 VRPN_CLOCK_FREQ = perffreq.QuadPart;
756 fprintf(stderr, "vrpn vrpn_gettimeofday: perf clock is tsc -- using "
757 "perf clock freq ( %lf MHz)\n",
758 perffreq.QuadPart / 1e6);
759 }
760 else {
761 fprintf(stderr, "vrpn vrpn_gettimeofday: adjusted clock freq to "
762 "measured freq ( %lf MHz )\n",
763 freq / 1e6);
764 }
765 VRPN_CLOCK_FREQ = (__int64)freq;
766 return 0;
767}
768#pragma optimize("", on)
769#endif
770
771// The pc has no gettimeofday call, and the closest thing to it is _ftime.
772// _ftime, however, has only about 6 ms resolution, so we use the peformance
773// as an offset from a base time which is established by a call to by _ftime.
774
775// The first call to vrpn_gettimeofday will establish a new time frame
776// on which all later calls will be based. This means that the time returned
777// by vrpn_gettimeofday will not always match _ftime (even at _ftime's
778// resolution),
779// but it will be consistent across all vrpn_gettimeofday calls.
780
782// Although VC++ doesn't include a gettimeofday
783// call, Cygnus Solutions Cygwin32 environment does,
784// so this is not used when compiling with gcc under WIN32
785
786// XXX AND ITS WRONG in the current release 10/11/99
787// They claim it will be fixed in the next release,
788// so until then, we will make it right using our solution.
790#ifndef VRPN_WINDOWS_CLOCK_V2
791int vrpn_gettimeofday(timeval *tp, void *tzp)
792{
793 struct timezone *timeZone = reinterpret_cast<struct timezone *>(tzp);
794 static int fFirst = 1;
795 static int fHasPerfCounter = 1;
796 static struct _timeb tbInit;
797 static LARGE_INTEGER liInit;
798 static LARGE_INTEGER liNow;
799 static LARGE_INTEGER liDiff;
800 timeval tvDiff;
801
802 if (!fHasPerfCounter) {
803 _ftime(&tbInit);
804 tp->tv_sec = tbInit.time;
805 tp->tv_usec = tbInit.millitm * 1000;
806 return 0;
807 }
808
809 if (fFirst) {
810 LARGE_INTEGER liTemp;
811 // establish a time base
812 fFirst = 0;
813
814 // Check to see if we are on a Windows NT machine (as opposed to a
815 // Windows 95/98 machine). If we are not, then use the _ftime code
816 // because the hi-perf clock does not work under Windows 98SE on my
817 // laptop, although the query for one seems to indicate that it is
818 // available.
819
820 {
821 OSVERSIONINFO osvi;
822
823 memset(&osvi, 0, sizeof(OSVERSIONINFO));
824 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
825 GetVersionEx(&osvi);
826
827 if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
828 fprintf(stderr,
829 "\nvrpn_gettimeofday: disabling hi performance clock "
830 "on non-NT system. "
831 "Defaulting to _ftime (~6 ms resolution) ...\n");
832 fHasPerfCounter = 0;
833 vrpn_gettimeofday(tp, tzp);
834 return 0;
835 }
836 }
837
838 // check that hi-perf clock is available
839 if (!(fHasPerfCounter = QueryPerformanceFrequency(&liTemp))) {
840 fprintf(stderr,
841 "\nvrpn_gettimeofday: no hi performance clock available. "
842 "Defaulting to _ftime (~6 ms resolution) ...\n");
843 fHasPerfCounter = 0;
844 vrpn_gettimeofday(tp, tzp);
845 return 0;
846 }
847
848 if (vrpn_AdjustFrequency() < 0) {
849 fprintf(stderr,
850 "\nvrpn_gettimeofday: can't verify clock frequency. "
851 "Defaulting to _ftime (~6 ms resolution) ...\n");
852 fHasPerfCounter = 0;
853 vrpn_gettimeofday(tp, tzp);
854 return 0;
855 }
856 // get current time
857 // We assume this machine has a time stamp counter register --
858 // I don't know of an easy way to check for this
859 rdtsc(liInit);
860 _ftime(&tbInit);
861
862 // we now consider it to be exactly the time _ftime returned
863 // (beyond the resolution of _ftime, down to the perfCounter res)
864 }
865
866 // now do the regular get time call to get the current time
867 rdtsc(liNow);
868
869 // find offset from initial value
870 liDiff.QuadPart = liNow.QuadPart - liInit.QuadPart;
871
872 tvDiff.tv_sec = (long)(liDiff.QuadPart / VRPN_CLOCK_FREQ);
873 tvDiff.tv_usec =
874 (long)(1e6 * ((liDiff.QuadPart - VRPN_CLOCK_FREQ * tvDiff.tv_sec) /
875 (double)VRPN_CLOCK_FREQ));
876
877 // pack the value and clean it up
878 tp->tv_sec = tbInit.time + tvDiff.tv_sec;
879 tp->tv_usec = tbInit.millitm * 1000 + tvDiff.tv_usec;
880 while (tp->tv_usec >= 1000000) {
881 tp->tv_sec++;
882 tp->tv_usec -= 1000000;
883 }
884
885 return 0;
886}
887#else // VRPN_WINDOWS_CLOCK_V2 is defined
888
889void get_time_using_GetLocalTime(unsigned long &sec, unsigned long &usec)
890{
891 static LARGE_INTEGER first_count = {0, 0};
892 static unsigned long first_sec, first_usec;
893 static LARGE_INTEGER perf_freq; //< Frequency of the performance counter.
894 SYSTEMTIME stime; // System time in funky structure
895 FILETIME ftime; // Time in 100-nsec intervals since Jan 1 1601
896 LARGE_INTEGER tics; // ftime stored into a 64-bit quantity
897 LARGE_INTEGER perf_counter;
898
899 // The first_count value will be zero only the first time through; we
900 // rely on this to set up the structures needed to interpret the data
901 // that we get from querying the performance counter.
902 if (first_count.QuadPart == 0) {
903 QueryPerformanceCounter(&first_count);
904
905 // Find out how fast the performance counter runs. Store this for later
906 // runs.
907 QueryPerformanceFrequency(&perf_freq);
908
909 // Find out what time it is in a Windows structure.
910 GetLocalTime(&stime);
911 SystemTimeToFileTime(&stime, &ftime);
912
913 // Copy the data into a structure that can be treated as a 64-bit
914 // integer
915 tics.HighPart = ftime.dwHighDateTime;
916 tics.LowPart = ftime.dwLowDateTime;
917
918 // Convert the 64-bit time into seconds and microseconds since July 1
919 // 1601
920 sec = (long)(tics.QuadPart / 10000000L);
921 usec = (long)((tics.QuadPart - (((LONGLONG)(sec)) * 10000000L)) / 10);
922 first_sec = sec;
923 first_usec = usec;
924 }
925 else {
926 QueryPerformanceCounter(&perf_counter);
927 if (perf_counter.QuadPart >= first_count.QuadPart) {
928 perf_counter.QuadPart =
929 perf_counter.QuadPart - first_count.QuadPart;
930 }
931 else {
932 // Take care of the case when the counter rolls over.
933 perf_counter.QuadPart = 0x7fffffffffffffffLL -
934 first_count.QuadPart +
935 perf_counter.QuadPart;
936 }
937
938 // Reinterpret the performance counter into seconds and microseconds
939 // by dividing by the performance counter. Microseconds is placed
940 // into perf_counter by subtracting the seconds value out, then
941 // multiplying by 1 million and re-dividing by the performance counter.
942 sec = (long)(perf_counter.QuadPart / perf_freq.QuadPart);
943 perf_counter.QuadPart -= perf_freq.QuadPart * sec;
944 perf_counter.QuadPart *= 1000000L; //< Turn microseconds into seconds
945 usec = first_usec + (long)(perf_counter.QuadPart / perf_freq.QuadPart);
946 sec += first_sec;
947
948 // Make sure that we've not got more than a million microseconds.
949 // If so, then shift it into seconds. We don't expect it to be above
950 // more than 1 million because we added two things, each of which were
951 // less than 1 million.
952 if (usec > 1000000L) {
953 usec -= 1000000L;
954 sec++;
955 }
956 }
957
958 // Translate the time to be based on January 1, 1970 (_ftime base)
959 // The offset here is gotten by using the "time_test" program to report the
960 // difference in seconds between the two clocks.
961 sec -= 3054524608L;
962}
963
964int vrpn_gettimeofday(timeval *tp, void *tzp)
965{
966 struct timezone *timeZone = reinterpret_cast<struct timezone *>(tzp);
967 unsigned long sec, usec;
968 get_time_using_GetLocalTime(sec, usec);
969 tp->tv_sec = sec;
970 tp->tv_usec = usec;
971 if (tzp != NULL) {
972 TIME_ZONE_INFORMATION tz;
973 GetTimeZoneInformation(&tz);
974 timeZone->tz_minuteswest = tz.Bias;
975 timeZone->tz_dsttime = (tz.StandardBias != tz.Bias);
976 }
977 return 0;
978}
979
980#endif // defined(VRPN_WINDOWS_CLOCK_V2)
981
982#endif // defined(_WIN32)
983
984// do the calibration before the program ever starts up
985static timeval __tv;
986static int __iTrash = vrpn_gettimeofday(&__tv, (struct timezone *)NULL);
987
988#endif // VRPN_UNSAFE_WINDOWS_CLOCK
989
990#endif // VRPN_USE_STD_CHRONO
991
992// End of the section dealing with vrpn_gettimeofday()
993//=====================================================================
994
996{
997 // Get a buffer to use that is large enough to test all of the routines.
998 vrpn_float64 dbuffer[256];
999 vrpn_int32 buflen;
1000
1001 vrpn_float64 in_float64 = 42.1;
1002 vrpn_int32 in_int32 = 17;
1003 vrpn_uint16 in_uint16 = 397;
1004 vrpn_uint8 in_uint8 = 1;
1005
1006 vrpn_float64 out_float64;
1007 vrpn_int32 out_int32;
1008 vrpn_uint16 out_uint16;
1009 vrpn_uint8 out_uint8;
1010
1011 // Test packing using little-endian routines.
1012 // IMPORTANT: Do these from large to small to get good alignment.
1013 char *bufptr = (char *)dbuffer;
1014 buflen = sizeof(dbuffer);
1015 if (vrpn_buffer_to_little_endian(&bufptr, &buflen, in_float64) != 0) {
1016 fprintf(stderr,
1017 "vrpn_test_pack_unpack(): Could not buffer little endian\n");
1018 return false;
1019 }
1020 if (vrpn_buffer_to_little_endian(&bufptr, &buflen, in_int32) != 0) {
1021 fprintf(stderr,
1022 "vrpn_test_pack_unpack(): Could not buffer little endian\n");
1023 return false;
1024 }
1025 if (vrpn_buffer_to_little_endian(&bufptr, &buflen, in_uint16) != 0) {
1026 fprintf(stderr,
1027 "vrpn_test_pack_unpack(): Could not buffer little endian\n");
1028 return false;
1029 }
1030 if (vrpn_buffer_to_little_endian(&bufptr, &buflen, in_uint8) != 0) {
1031 fprintf(stderr,
1032 "vrpn_test_pack_unpack(): Could not buffer little endian\n");
1033 return false;
1034 }
1035
1036 // Test unpacking using little-endian routines.
1037 bufptr = (char *)dbuffer;
1038 if (in_float64 !=
1039 (out_float64 =
1040 vrpn_unbuffer_from_little_endian<vrpn_float64>(bufptr))) {
1041 fprintf(stderr,
1042 "vrpn_test_pack_unpack(): Could not unbuffer little endian\n");
1043 return false;
1044 }
1045 if (in_int32 !=
1046 (out_int32 = vrpn_unbuffer_from_little_endian<vrpn_int32>(bufptr))) {
1047 fprintf(stderr,
1048 "vrpn_test_pack_unpack(): Could not unbuffer little endian\n");
1049 return false;
1050 }
1051 if (in_uint16 !=
1052 (out_uint16 = vrpn_unbuffer_from_little_endian<vrpn_uint16>(bufptr))) {
1053 fprintf(stderr,
1054 "vrpn_test_pack_unpack(): Could not unbuffer little endian\n");
1055 return false;
1056 }
1057 if (in_uint8 !=
1058 (out_uint8 = vrpn_unbuffer_from_little_endian<vrpn_uint8>(bufptr))) {
1059 fprintf(stderr,
1060 "vrpn_test_pack_unpack(): Could not unbuffer little endian\n");
1061 return false;
1062 }
1063
1064 // Test packing using big-endian routines.
1065 bufptr = (char *)dbuffer;
1066 buflen = sizeof(dbuffer);
1067 if (vrpn_buffer(&bufptr, &buflen, in_float64) != 0) {
1068 fprintf(stderr,
1069 "vrpn_test_pack_unpack(): Could not buffer big endian\n");
1070 return false;
1071 }
1072 if (vrpn_buffer(&bufptr, &buflen, in_int32) != 0) {
1073 fprintf(stderr,
1074 "vrpn_test_pack_unpack(): Could not buffer big endian\n");
1075 return false;
1076 }
1077 if (vrpn_buffer(&bufptr, &buflen, in_uint16) != 0) {
1078 fprintf(stderr,
1079 "vrpn_test_pack_unpack(): Could not buffer big endian\n");
1080 return false;
1081 }
1082 if (vrpn_buffer(&bufptr, &buflen, in_uint8) != 0) {
1083 fprintf(stderr,
1084 "vrpn_test_pack_unpack(): Could not buffer big endian\n");
1085 return false;
1086 }
1087
1088 // Test unpacking using big-endian routines.
1089 bufptr = (char *)dbuffer;
1090 if (in_float64 != (out_float64 = vrpn_unbuffer<vrpn_float64>(bufptr))) {
1091 fprintf(stderr,
1092 "vrpn_test_pack_unpack(): Could not unbuffer big endian\n");
1093 return false;
1094 }
1095 if (in_int32 != (out_int32 = vrpn_unbuffer<vrpn_int32>(bufptr))) {
1096 fprintf(stderr,
1097 "vrpn_test_pack_unpack(): Could not unbuffer big endian\n");
1098 return false;
1099 }
1100 if (in_uint16 != (out_uint16 = vrpn_unbuffer<vrpn_uint16>(bufptr))) {
1101 fprintf(stderr,
1102 "vrpn_test_pack_unpack(): Could not unbuffer big endian\n");
1103 return false;
1104 }
1105 if (in_uint8 != (out_uint8 = vrpn_unbuffer<vrpn_uint8>(bufptr))) {
1106 fprintf(stderr,
1107 "vrpn_test_pack_unpack(): Could not unbuffer big endian\n");
1108 return false;
1109 }
1110
1111 // XXX Test pack/unpack of all other types.
1112
1113 // Test packing little-endian and unpacking big-endian; they should
1114 // be different.
1115 bufptr = (char *)dbuffer;
1116 buflen = sizeof(dbuffer);
1117 if (vrpn_buffer_to_little_endian(&bufptr, &buflen, in_float64) != 0) {
1118 fprintf(stderr,
1119 "vrpn_test_pack_unpack(): Could not buffer little endian\n");
1120 return false;
1121 }
1122 bufptr = (char *)dbuffer;
1123 if (in_float64 == (out_float64 = vrpn_unbuffer<vrpn_float64>(bufptr))) {
1124 fprintf(
1125 stderr,
1126 "vrpn_test_pack_unpack(): Cross-packing produced same result\n");
1127 return false;
1128 }
1129
1130 return true;
1131}
int v()
Release of resource. ("up")
Definition: vrpn_Thread.C:292
int p()
Blocking acquire of resource. ("down")
Definition: vrpn_Thread.C:232
#define VRPN_API
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
Definition: vrpn_Shared.C:321
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:138
bool vrpn_test_pack_unpack(void)
Definition: vrpn_Shared.C:995
double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
Return the number of seconds between startT and endT as a floating-point value.
Definition: vrpn_Shared.C:144
#define CHECK(a)
Definition: vrpn_Shared.C:23
bool vrpn_TimevalGreater(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:122
timeval vrpn_TimevalScale(const timeval &tv, double scale)
Definition: vrpn_Shared.C:111
VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
Utility routine for placing a timeval struct into a buffer that is to be sent as a message.
Definition: vrpn_Shared.C:250
vrpn_float64 vrpn_ntohd(vrpn_float64 d)
Definition: vrpn_Shared.C:235
vrpn_float64 vrpn_htond(vrpn_float64 d)
Definition: vrpn_Shared.C:199
double vrpn_TimevalMsecs(const timeval &tv)
Definition: vrpn_Shared.C:150
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:101
timeval vrpn_TimevalNormalize(const timeval &in_tv)
Definition: vrpn_Shared.C:43
bool vrpn_TimevalEqual(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:130
void vrpn_SleepMsecs(double dMilliSecs)
Definition: vrpn_Shared.C:166
timeval vrpn_MsecsTimeval(const double dMsecs)
Definition: vrpn_Shared.C:155
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:54
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:99
int vrpn_buffer_to_little_endian(ByteT **insertPt, vrpn_int32 *buflen, const T inVal)
Function template to buffer values to a buffer stored in little- endian order. Specify the type to bu...
Definition: vrpn_Shared.h:415