On Windows systems, the function ecx_configdc uses osal_current_time() to initialize the mastertime variable:
mastertime = osal_current_time();
The function osal_current_time calls osal_gettimeofday which relies on QueryPerformanceFrequency and QueryPerformanceCounter. When precise but relative time is needed (e.g. for timers), QueryPerformanceCounter is a good choice. But for initialization of DC, an absolute time would be more meaningful.
Here is a guidance on how to get time stamps in windows. In section Guidance for acquiring time stamps you find the following statements:
When you need time stamps with a resolution of 1 microsecond or better and you don't need the time stamps to be synchronized to an external time reference, choose QueryPerformanceCounter, KeQueryPerformanceCounter, or KeQueryInterruptTimePrecise.
[...]
If resolution of 10 to 16 milliseconds is sufficient, you can use GetTickCount64, QueryInterruptTime, QueryUnbiasedInterruptTime, KeQueryInterruptTime, or KeQueryUnbiasedInterruptTime to obtain time stamps that aren't synchronized to an external time reference. For UTC-synchronized time stamps, use GetSystemTimeAsFileTime or KeQuerySystemTime.
The Ke*-functions are for kernel mode, which is not applicable here.
So, for versions <= Windows 7, there is a trade-off between precision and synchronization:
QueryPerformanceCounter: precise, not synchronized (relative time since windows boot)
GetSystemTimeAsFileTime: unprecise, UTC synchronized
So I would propose to use GetSystemTimeAsFileTime for DC initialization and GetSystemTimeAsPreciseFileTime when version >= Windows 8 because it combines both advantages.
In windows 7, I use the following function:
int osal_getabsolutetimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME SystemTime;
int64 SystemTime64, usecs;
int64 Offset = -134774LL * 86400LL * 1000LL * 1000LL * 10LL; // Difference between 1601 and 1970 in 100 ns.
timeBeginPeriod(1);
GetSystemTimeAsFileTime(&SystemTime);
timeEndPeriod(1);
SystemTime64 = ((int64)(SystemTime.dwHighDateTime) << 32) + (int64)SystemTime.dwLowDateTime;
SystemTime64 = SystemTime64 + Offset;
usecs = SystemTime64 / 10;
tv->tv_sec = (long)(usecs / 1000000);
tv->tv_usec = (long)(usecs - (tv->tv_sec * 1000000));
return 1;
}
This function is a workaround and I posted it just as an example. Some comments:
- I am not sure if timeBeginPeriod(1) and timeEndPeriod(1) have any effect. I think they would have an effect, if they have been called long before, e.g. during software startup because the underlying timer gets updated the next time when the OS wakes up (after 1 ms). So it is likely that the old time (~15 ms ago) is provided.
- I am calculating from year 1601 to 1970 instead of 2000 to be compatible with ecx_configdc.
One comment to the original function osal_gettimeofday. I think timeBeginPeriod(1) has no effect, since QueryPerformanceCounter does not depend on the multimedia timer and QueryPerformanceFrequency is determined and fixed during operating system boot.
int osal_gettimeofday (struct timeval *tv, struct timezone *tz)
{
int64_t wintime, usecs;
if(!sysfrequency)
{
timeBeginPeriod(1); // May this line has no effect
QueryPerformanceFrequency((LARGE_INTEGER *)&sysfrequency);
qpc2usec = 1000000.0 / sysfrequency;
}
QueryPerformanceCounter((LARGE_INTEGER *)&wintime);
usecs = (int64_t)((double)wintime * qpc2usec);
tv->tv_sec = (long)(usecs / 1000000);
tv->tv_usec = (long)(usecs - (tv->tv_sec * 1000000));
return 1;
}
Thank you
Vincent