1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifdef SDL_TIMER_WINCE
25
26#define WIN32_LEAN_AND_MEAN
27#include <windows.h>
28#include <mmsystem.h>
29
30#include "SDL_thread.h"
31#include "SDL_timer.h"
32#include "../SDL_timer_c.h"
33
34static Uint64 start_date;
35static Uint64 start_ticks;
36
37static Uint64 wce_ticks(void)
38{
39  return((Uint64)GetTickCount());
40}
41
42static Uint64 wce_date(void)
43{
44  union
45  {
46	FILETIME ftime;
47	Uint64 itime;
48  } ftime;
49  SYSTEMTIME stime;
50
51  GetSystemTime(&stime);
52  SystemTimeToFileTime(&stime,&ftime.ftime);
53  ftime.itime/=10000; // Convert 100ns intervals to 1ms intervals
54  // Remove ms portion, which can't be relied on
55  ftime.itime -= (ftime.itime % 1000);
56  return(ftime.itime);
57}
58
59static Sint32 wce_rel_ticks(void)
60{
61  return((Sint32)(wce_ticks()-start_ticks));
62}
63
64static Sint32 wce_rel_date(void)
65{
66  return((Sint32)(wce_date()-start_date));
67}
68
69/* Return time in ms relative to when SDL was started */
70Uint32 SDL_GetTicks()
71{
72  Sint32 offset=wce_rel_date()-wce_rel_ticks();
73  if((offset < -1000) || (offset > 1000))
74  {
75//    fprintf(stderr,"Time desync(%+d), resyncing\n",offset/1000);
76	start_ticks-=offset;
77  }
78
79  return((Uint32)wce_rel_ticks());
80}
81
82/* Give up approx. givem milliseconds to the OS. */
83void SDL_Delay(Uint32 ms)
84{
85  Sleep(ms);
86}
87
88/* Recard start-time of application for reference */
89void SDL_StartTicks(void)
90{
91  start_date=wce_date();
92  start_ticks=wce_ticks();
93}
94
95static UINT WIN_timer;
96
97#if ( _WIN32_WCE <= 420 )
98
99static HANDLE timersThread = 0;
100static HANDLE timersQuitEvent = 0;
101
102DWORD TimersThreadProc(void *data)
103{
104	while(WaitForSingleObject(timersQuitEvent, 10) == WAIT_TIMEOUT)
105	{
106		SDL_ThreadedTimerCheck();
107	}
108	return 0;
109}
110
111int SDL_SYS_TimerInit(void)
112{
113	// create a thread to process a threaded timers
114	// SetTimer does not suit the needs because
115	// TimerCallbackProc will be called only when WM_TIMER occured
116
117	timersQuitEvent = CreateEvent(0, TRUE, FALSE, 0);
118	if( !timersQuitEvent )
119	{
120		SDL_SetError("Cannot create event for timers thread");
121		return -1;
122	}
123	timersThread = CreateThread(NULL, 0, TimersThreadProc, 0, 0, 0);
124	if( !timersThread )
125	{
126		SDL_SetError("Cannot create timers thread, check amount of RAM available");
127		return -1;
128	}
129	SetThreadPriority(timersThread, THREAD_PRIORITY_HIGHEST);
130
131	return(SDL_SetTimerThreaded(1));
132}
133
134void SDL_SYS_TimerQuit(void)
135{
136	SetEvent(timersQuitEvent);
137	if( WaitForSingleObject(timersThread, 2000) == WAIT_TIMEOUT )
138		TerminateThread(timersThread, 0);
139	CloseHandle(timersThread);
140	CloseHandle(timersQuitEvent);
141	return;
142}
143
144#else
145
146#pragma comment(lib, "mmtimer.lib")
147
148/* Data to handle a single periodic alarm */
149static UINT timerID = 0;
150
151static void CALLBACK HandleAlarm(UINT uID,  UINT uMsg, DWORD dwUser,
152						DWORD dw1, DWORD dw2)
153{
154	SDL_ThreadedTimerCheck();
155}
156
157
158int SDL_SYS_TimerInit(void)
159{
160	MMRESULT result;
161
162	/* Set timer resolution */
163	result = timeBeginPeriod(TIMER_RESOLUTION);
164	if ( result != TIMERR_NOERROR ) {
165		SDL_SetError("Warning: Can't set %d ms timer resolution",
166							TIMER_RESOLUTION);
167	}
168	/* Allow 10 ms of drift so we don't chew on CPU */
169	timerID = timeSetEvent(TIMER_RESOLUTION,1,HandleAlarm,0,TIME_PERIODIC);
170	if ( ! timerID ) {
171		SDL_SetError("timeSetEvent() failed");
172		return(-1);
173	}
174	return(SDL_SetTimerThreaded(1));
175}
176
177void SDL_SYS_TimerQuit(void)
178{
179	if ( timerID ) {
180		timeKillEvent(timerID);
181	}
182	timeEndPeriod(TIMER_RESOLUTION);
183}
184
185#endif
186
187int SDL_SYS_StartTimer(void)
188{
189	SDL_SetError("Internal logic error: WinCE uses threaded timer");
190	return(-1);
191}
192
193void SDL_SYS_StopTimer(void)
194{
195	return;
196}
197
198#endif /* SDL_TIMER_WINCE */
199