]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - drivers/timers_win32/timers_win32.cpp
d3f5febe2773b605f076b4032c55c0baa4dd244c
[CanFestival-3.git] / drivers / timers_win32 / timers_win32.cpp
1 /*
2 This file is part of CanFestival, a library implementing CanOpen Stack.
3
4 Copyright (C): Edouard TISSERANT and Francis DUPIN
5 Copyright (C) Win32 Port Leonid Tochinski
6
7 See COPYING file for copyrights details.
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 */
23
24
25
26 #include <windows.h>
27 #include <stdlib.h>
28
29 extern "C"
30 {
31 #include "applicfg.h"
32 #include "can_driver.h"
33 #include "timer.h"
34 #include "timers_driver.h"
35 };
36
37 // --------------- Synchronization Object Implementation ---------------
38 class ccritical_section
39    {
40    public:
41       ccritical_section()
42          {
43          ::InitializeCriticalSection(&m_cs);
44          }
45       ~ccritical_section()
46          {
47          ::DeleteCriticalSection(&m_cs);
48          }
49       void enter()
50          {
51          ::EnterCriticalSection(&m_cs);
52          }
53       void leave()
54          {
55          ::LeaveCriticalSection(&m_cs);
56          }
57    private:
58       CRITICAL_SECTION m_cs;
59    };
60
61 static ccritical_section g_cs;
62
63
64 void EnterMutex(void)
65    {
66    g_cs.enter();
67    }
68
69 void LeaveMutex(void)
70    {
71    g_cs.leave();
72    }
73 // --------------- Synchronization Object Implementation ---------------
74
75
76 // --------------- CAN Receive Thread Implementation ---------------
77
78 void CreateReceiveTask(CAN_HANDLE fd0, TASK_HANDLE* Thread, void* ReceiveLoopPtr)
79    {
80    unsigned long thread_id = 0;
81    *Thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveLoopPtr, fd0, 0, &thread_id);
82    }
83
84 void WaitReceiveTaskEnd(TASK_HANDLE *Thread)
85    {
86    ::WaitForSingleObject(*Thread, INFINITE);
87    ::CloseHandle(*Thread);
88    //*Thread = NULL;
89    }
90 // --------------- CAN Receive Thread Implementation ---------------
91
92
93 // --------------- Timer Thread Implementation ---------------
94 class class_timers
95    {
96    public:
97       class_timers();
98       ~class_timers();
99       void start_timer_thread();
100       void resume_timer_thread();
101       void stop_timer_thread();
102       void set_timer(TIMEVAL value);
103       TIMEVAL get_elapsed_time();
104    private:
105       TIMEVAL get_timer() const;   
106       static DWORD WINAPI timer_loop_thread_proc(void* arg);
107    private:
108       TIMEVAL m_last_occured_alarm_time;
109       volatile TIMEVAL m_last_alarm_set_time;
110       HANDLE m_timer_thread;
111       volatile bool m_continue_timer_loop;
112       bool m_use_hi_res_timer;
113       double m_counts_per_usec;
114    };
115
116 class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX),
117       m_last_alarm_set_time(TIMEVAL_MAX),
118       m_timer_thread(0),
119       m_continue_timer_loop(false),
120       m_use_hi_res_timer(false),
121       m_counts_per_usec(0.)
122    {
123    // initialize hi resolution timer
124    LARGE_INTEGER counts_per_sec = {0, 0};
125    if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0)
126       {
127       m_use_hi_res_timer = true;
128       m_counts_per_usec = counts_per_sec.QuadPart / 1000000.;
129       }
130    m_use_hi_res_timer = true;
131    }
132
133 class_timers::~class_timers()
134    {
135    stop_timer_thread();
136    }
137
138 // time is in micro seconds
139 TIMEVAL class_timers::get_timer() const
140    {
141    if (m_use_hi_res_timer)
142       {
143       LARGE_INTEGER performance_count = {0, 0};
144       ::QueryPerformanceCounter(&performance_count);
145       return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec);
146       }
147    // hi-res timer is unavailable
148    return 1000 * ::GetTickCount();
149    }
150
151 DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg)
152    {
153    class_timers* This = reinterpret_cast<class_timers*>(arg);
154    while (This->m_continue_timer_loop)
155       {
156       TIMEVAL cur_time = This->get_timer();
157       if (cur_time >= This->m_last_alarm_set_time)
158          {
159          This->m_last_occured_alarm_time = cur_time;
160          This->m_last_alarm_set_time = TIMEVAL_MAX;         
161          EnterMutex();
162          TimeDispatch();
163          LeaveMutex();
164          }
165       else
166          {
167          ::Sleep(1);
168          }
169       }
170    return 0;
171    }
172
173 void class_timers::start_timer_thread()
174    {
175    if (m_timer_thread == 0)
176       {
177       unsigned long thread_id = 0;
178       m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, this, CREATE_SUSPENDED, &thread_id);
179       m_last_alarm_set_time = TIMEVAL_MAX;
180       m_last_occured_alarm_time = get_timer();
181       }
182    }
183
184 void class_timers::resume_timer_thread()
185    {
186    if (m_timer_thread)
187       {
188       m_continue_timer_loop = true;
189       ::ResumeThread(m_timer_thread);
190       }
191    }
192
193 void class_timers::stop_timer_thread()
194    {
195    if (m_timer_thread)
196       {
197       m_continue_timer_loop = false;
198       ::WaitForSingleObject(m_timer_thread, INFINITE);
199       ::CloseHandle(m_timer_thread);
200       m_timer_thread = 0;
201       }
202    }
203
204 void class_timers::set_timer(TIMEVAL value)
205    {
206    m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value;
207    }
208
209 // elapsed time since last occured alarm
210 TIMEVAL class_timers::get_elapsed_time()
211    {
212    return get_timer() - m_last_occured_alarm_time;
213    }
214
215 // ----------------------------------------------------------
216
217 static class_timers s_timers;
218
219 void StartTimerLoop(TimerCallback_t init_callback)
220    {
221    s_timers.start_timer_thread();
222    // At first, TimeDispatch will call init_callback.
223    if (init_callback != NULL)
224       SetAlarm(NULL, 0, init_callback, (TIMEVAL)0, (TIMEVAL)0);
225    s_timers.resume_timer_thread();
226    }
227
228 void StopTimerLoop(void)
229    {
230    s_timers.stop_timer_thread();
231    }
232
233 void setTimer(TIMEVAL value)
234    {
235    s_timers.set_timer(value);
236    }
237
238 TIMEVAL getElapsedTime(void)
239    {
240    return s_timers.get_elapsed_time();
241    }