mirror of
https://github.com/stargieg/bacnet-stack
synced 2025-10-26 23:35:52 +08:00
282 lines
8.6 KiB
C
282 lines
8.6 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
|
* Multimedia Timer contribution by Cameron Crothers, 2008
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*********************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define STRICT 1
|
|
#include <windows.h>
|
|
#include "net.h"
|
|
#include <MMSystem.h>
|
|
#include "timer.h"
|
|
|
|
/* Offset between Windows epoch 1/1/1601 and
|
|
Unix epoch 1/1/1970 in 100 nanosec units */
|
|
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__BORLANDC__)
|
|
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
|
#else
|
|
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
|
#endif
|
|
|
|
/* counter for the various timers */
|
|
static volatile uint32_t Millisecond_Counter[MAX_MILLISECOND_TIMERS];
|
|
|
|
/* Windows timer period - in milliseconds */
|
|
static uint32_t Timer_Period = 1;
|
|
|
|
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
|
struct timezone {
|
|
int tz_minuteswest; /* minutes W of Greenwich */
|
|
int tz_dsttime; /* type of dst correction */
|
|
};
|
|
|
|
/*************************************************************************
|
|
* Description: simulate the gettimeofday Linux function
|
|
* Returns: zero
|
|
* Note: The resolution of GetSystemTimeAsFileTime() is 15625 microseconds.
|
|
* The resolution of _ftime() is about 16 milliseconds.
|
|
* To get microseconds accuracy we need to use QueryPerformanceCounter or
|
|
* timeGetTime for the elapsed time.
|
|
*************************************************************************/
|
|
|
|
int gettimeofday(
|
|
struct timeval *tp,
|
|
void *tzp)
|
|
{
|
|
static int tzflag = 0;
|
|
struct timezone *tz;
|
|
/* start calendar time in microseconds */
|
|
static LONGLONG usec_timer = 0;
|
|
LONGLONG usec_elapsed = 0;
|
|
/* elapsed time in milliseconds */
|
|
static uint32_t time_start = 0;
|
|
/* semi-accurate time from File Timer */
|
|
FILETIME ft;
|
|
uint32_t elapsed_milliseconds = 0;
|
|
|
|
tzp = tzp;
|
|
if (usec_timer == 0) {
|
|
/* a 64-bit value representing the number of
|
|
100-nanosecond intervals since January 1, 1601 (UTC). */
|
|
GetSystemTimeAsFileTime(&ft);
|
|
usec_timer = ft.dwHighDateTime;
|
|
usec_timer <<= 32;
|
|
usec_timer |= ft.dwLowDateTime;
|
|
/*converting file time to unix epoch 1970 */
|
|
usec_timer /= 10; /*convert into microseconds */
|
|
usec_timer -= DELTA_EPOCH_IN_MICROSECS;
|
|
tp->tv_sec = (long) (usec_timer / 1000000UL);
|
|
tp->tv_usec = (long) (usec_timer % 1000000UL);
|
|
time_start = timeGetTime();
|
|
} else {
|
|
elapsed_milliseconds = timeGetTime() - time_start;
|
|
usec_elapsed = usec_timer + ((LONGLONG) elapsed_milliseconds * 1000UL);
|
|
tp->tv_sec = (long) (usec_elapsed / 1000000UL);
|
|
tp->tv_usec = (long) (usec_elapsed % 1000000UL);
|
|
}
|
|
if (tzp) {
|
|
if (!tzflag) {
|
|
_tzset();
|
|
tzflag++;
|
|
}
|
|
tz = tzp;
|
|
tz->tz_minuteswest = _timezone / 60;
|
|
tz->tz_dsttime = _daylight;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*************************************************************************
|
|
* Description: returns the current millisecond count
|
|
* Returns: none
|
|
* Notes: none
|
|
*************************************************************************/
|
|
uint32_t timer_milliseconds(
|
|
unsigned index)
|
|
{
|
|
uint32_t now = timeGetTime();
|
|
uint32_t delta_time = 0;
|
|
|
|
|
|
if (index < MAX_MILLISECOND_TIMERS) {
|
|
if (Millisecond_Counter[index] <= now) {
|
|
delta_time = now - Millisecond_Counter[index];
|
|
} else {
|
|
delta_time = (UINT32_MAX - Millisecond_Counter[index]) + now + 1;
|
|
}
|
|
}
|
|
|
|
return delta_time;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: compares the current time count with a value
|
|
* Returns: true if the time has elapsed
|
|
* Notes: none
|
|
*************************************************************************/
|
|
bool timer_elapsed_milliseconds(
|
|
unsigned index,
|
|
uint32_t value)
|
|
{
|
|
return (timer_milliseconds(index) >= value);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: compares the current time count with a value
|
|
* Returns: true if the time has elapsed
|
|
* Notes: none
|
|
*************************************************************************/
|
|
bool timer_elapsed_seconds(
|
|
unsigned index,
|
|
uint32_t seconds)
|
|
{
|
|
return ((timer_milliseconds(index) / 1000) >= seconds);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: compares the current time count with a value
|
|
* Returns: true if the time has elapsed
|
|
* Notes: none
|
|
*************************************************************************/
|
|
bool timer_elapsed_minutes(
|
|
unsigned index,
|
|
uint32_t minutes)
|
|
{
|
|
return ((timer_milliseconds(index) / (1000 * 60)) >= minutes);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: Sets the timer counter to zero.
|
|
* Returns: none
|
|
* Notes: none
|
|
*************************************************************************/
|
|
uint32_t timer_reset(
|
|
unsigned index)
|
|
{
|
|
uint32_t timer_value = timer_milliseconds(index);
|
|
if (index < MAX_MILLISECOND_TIMERS) {
|
|
Millisecond_Counter[index] = timeGetTime();
|
|
}
|
|
return timer_value;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: Shut down for timer
|
|
* Returns: none
|
|
* Notes: none
|
|
*************************************************************************/
|
|
static void timer_cleanup(
|
|
void)
|
|
{
|
|
timeEndPeriod(Timer_Period);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* Description: Initialization for timer
|
|
* Returns: none
|
|
* Notes: none
|
|
*************************************************************************/
|
|
void timer_init(
|
|
void)
|
|
{
|
|
TIMECAPS tc;
|
|
|
|
/* set timer resolution */
|
|
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
|
|
fprintf(stderr, "Failed to get timer resolution parameters\n");
|
|
}
|
|
/* configure for 1ms resolution - if possible */
|
|
Timer_Period = min(max(tc.wPeriodMin, 1L), tc.wPeriodMax);
|
|
if (Timer_Period != 1L) {
|
|
fprintf(stderr,
|
|
"Failed to set timer to 1ms. " "Time period set to %ums\n",
|
|
(unsigned) Timer_Period);
|
|
}
|
|
timeBeginPeriod(Timer_Period);
|
|
atexit(timer_cleanup);
|
|
}
|
|
|
|
#ifdef TEST_TIMER_WIN
|
|
static uint32_t timeval_diff_ms(
|
|
struct timeval *old,
|
|
struct timeval *now)
|
|
{
|
|
uint32_t ms = 0;
|
|
|
|
/* convert to milliseconds */
|
|
ms = (now->tv_sec - old->tv_sec) * 1000 + (now->tv_usec -
|
|
old->tv_usec) / 1000;
|
|
|
|
return ms;
|
|
}
|
|
|
|
int main(
|
|
int argc,
|
|
char *argv[])
|
|
{
|
|
long now = 0, last = 0, delta = 0;
|
|
struct timeval tv;
|
|
struct timeval old_tv = { 0 };
|
|
|
|
timer_init();
|
|
printf("Testing granularity of timeGetTime()...\n");
|
|
timer_reset(0);
|
|
for (;;) {
|
|
now = timeGetTime();
|
|
delta = now - last;
|
|
if (delta) {
|
|
if (delta > 1) {
|
|
printf("Delta is %ld.\n", delta);
|
|
}
|
|
last = now;
|
|
}
|
|
if (timer_elapsed_milliseconds(0, 5000)) {
|
|
break;
|
|
}
|
|
}
|
|
printf("Testing granularity of gettimeofday()...\n");
|
|
for (;;) {
|
|
gettimeofday(&tv, NULL);
|
|
delta = timeval_diff_ms(&old_tv, &tv);
|
|
if (delta) {
|
|
if (delta > 1) {
|
|
printf("Delta is %ld.\n", delta);
|
|
}
|
|
old_tv.tv_sec = tv.tv_sec;
|
|
old_tv.tv_usec = tv.tv_usec;
|
|
}
|
|
if (timer_elapsed_milliseconds(0, 10000)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|