2 This file is part of CanFestival, a library implementing CanOpen Stack.
4 Copyright (C): Edouard TISSERANT and Francis DUPIN
5 Copyright (C) Win32 Port Leonid Tochinski
7 See COPYING file for copyrights details.
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.
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.
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
32 #include "can_driver.h"
34 #include "timers_driver.h"
37 // --------------- Synchronization Object Implementation ---------------
38 class ccritical_section
43 ::InitializeCriticalSection(&m_cs);
47 ::DeleteCriticalSection(&m_cs);
51 ::EnterCriticalSection(&m_cs);
55 ::LeaveCriticalSection(&m_cs);
58 CRITICAL_SECTION m_cs;
61 static ccritical_section g_cs;
73 // --------------- Synchronization Object Implementation ---------------
76 // --------------- CAN Receive Thread Implementation ---------------
78 void CreateReceiveTask(CAN_HANDLE fd0, TASK_HANDLE* Thread, void* ReceiveLoopPtr)
80 unsigned long thread_id = 0;
81 *Thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveLoopPtr, fd0, 0, &thread_id);
84 void WaitReceiveTaskEnd(TASK_HANDLE *Thread)
86 ::WaitForSingleObject(*Thread, INFINITE);
87 ::CloseHandle(*Thread);
90 // --------------- CAN Receive Thread Implementation ---------------
93 // --------------- Timer Thread Implementation ---------------
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();
105 TIMEVAL get_timer() const;
106 static DWORD WINAPI timer_loop_thread_proc(void* arg);
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;
116 class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX),
117 m_last_alarm_set_time(TIMEVAL_MAX),
119 m_continue_timer_loop(false),
120 m_use_hi_res_timer(false),
121 m_counts_per_usec(0.)
123 // initialize hi resolution timer
124 LARGE_INTEGER counts_per_sec = {0, 0};
125 if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0)
127 m_use_hi_res_timer = true;
128 m_counts_per_usec = counts_per_sec.QuadPart / 1000000.;
130 m_use_hi_res_timer = true;
133 class_timers::~class_timers()
138 // time is in micro seconds
139 TIMEVAL class_timers::get_timer() const
141 if (m_use_hi_res_timer)
143 LARGE_INTEGER performance_count = {0, 0};
144 ::QueryPerformanceCounter(&performance_count);
145 return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec);
147 // hi-res timer is unavailable
148 return 1000 * ::GetTickCount();
151 DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg)
153 class_timers* This = reinterpret_cast<class_timers*>(arg);
154 while (This->m_continue_timer_loop)
156 TIMEVAL cur_time = This->get_timer();
157 if (cur_time >= This->m_last_alarm_set_time)
159 This->m_last_occured_alarm_time = cur_time;
160 This->m_last_alarm_set_time = TIMEVAL_MAX;
173 void class_timers::start_timer_thread()
175 if (m_timer_thread == 0)
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();
184 void class_timers::resume_timer_thread()
188 m_continue_timer_loop = true;
189 ::ResumeThread(m_timer_thread);
193 void class_timers::stop_timer_thread()
197 m_continue_timer_loop = false;
198 ::WaitForSingleObject(m_timer_thread, INFINITE);
199 ::CloseHandle(m_timer_thread);
204 void class_timers::set_timer(TIMEVAL value)
206 m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value;
209 // elapsed time since last occured alarm
210 TIMEVAL class_timers::get_elapsed_time()
212 return get_timer() - m_last_occured_alarm_time;
215 // ----------------------------------------------------------
217 static class_timers s_timers;
219 void StartTimerLoop(TimerCallback_t init_callback)
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();
228 void StopTimerLoop(void)
230 s_timers.stop_timer_thread();
233 void setTimer(TIMEVAL value)
235 s_timers.set_timer(value);
238 TIMEVAL getElapsedTime(void)
240 return s_timers.get_elapsed_time();