nico@207: nico@207:
nico@207:00001 /* nico@207: 00002 This file is part of CanFestival, a library implementing CanOpen Stack. nico@207: 00003 nico@207: 00004 Copyright (C): Edouard TISSERANT and Francis DUPIN nico@207: 00005 Copyright (C) Win32 Port Leonid Tochinski nico@207: 00006 nico@207: 00007 See COPYING file for copyrights details. nico@207: 00008 nico@207: 00009 This library is free software; you can redistribute it and/or nico@207: 00010 modify it under the terms of the GNU Lesser General Public nico@207: 00011 License as published by the Free Software Foundation; either nico@207: 00012 version 2.1 of the License, or (at your option) any later version. nico@207: 00013 nico@207: 00014 This library is distributed in the hope that it will be useful, nico@207: 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of nico@207: 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nico@207: 00017 Lesser General Public License for more details. nico@207: 00018 nico@207: 00019 You should have received a copy of the GNU Lesser General Public nico@207: 00020 License along with this library; if not, write to the Free Software nico@207: 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA nico@207: 00022 */ nico@207: 00023 nico@207: 00024 nico@207: 00025 nico@207: 00026 #include <windows.h> nico@207: 00027 #include <stdlib.h> nico@207: 00028 nico@207: 00029 extern "C" nico@207: 00030 { nico@207: 00031 #include "applicfg.h" nico@207: 00032 #include "can_driver.h" nico@207: 00033 #include "timer.h" nico@207: 00034 #include "timers_driver.h" nico@207: 00035 }; nico@207: 00036 nico@207: 00037 // --------------- Synchronization Object Implementation --------------- nico@207: 00038 class ccritical_section nico@207: 00039 { nico@207: 00040 public: nico@207: 00041 ccritical_section() nico@207: 00042 { nico@207: 00043 ::InitializeCriticalSection(&m_cs); nico@207: 00044 } nico@207: 00045 ~ccritical_section() nico@207: 00046 { nico@207: 00047 ::DeleteCriticalSection(&m_cs); nico@207: 00048 } nico@207: 00049 void enter() nico@207: 00050 { nico@207: 00051 ::EnterCriticalSection(&m_cs); nico@207: 00052 } nico@207: 00053 void leave() nico@207: 00054 { nico@207: 00055 ::LeaveCriticalSection(&m_cs); nico@207: 00056 } nico@207: 00057 private: nico@207: 00058 CRITICAL_SECTION m_cs; nico@207: 00059 }; nico@207: 00060 nico@207: 00061 static ccritical_section g_cs; nico@207: 00062 nico@207: 00063 nico@207: 00064 void EnterMutex(void) nico@207: 00065 { nico@207: 00066 g_cs.enter(); nico@207: 00067 } nico@207: 00068 nico@207: 00069 void LeaveMutex(void) nico@207: 00070 { nico@207: 00071 g_cs.leave(); nico@207: 00072 } nico@207: 00073 // --------------- Synchronization Object Implementation --------------- nico@207: 00074 nico@207: 00075 nico@207: 00076 // --------------- CAN Receive Thread Implementation --------------- nico@207: 00077 nico@207: 00078 void CreateReceiveTask(CAN_HANDLE fd0, TASK_HANDLE* Thread, void* ReceiveLoopPtr) nico@207: 00079 { nico@207: 00080 unsigned long thread_id = 0; nico@207: 00081 *Thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveLoopPtr, fd0, 0, &thread_id); nico@207: 00082 } nico@207: 00083 nico@207: 00084 void WaitReceiveTaskEnd(TASK_HANDLE Thread) nico@207: 00085 { nico@207: 00086 ::WaitForSingleObject(Thread, INFINITE); nico@207: 00087 ::CloseHandle(Thread); nico@207: 00088 //*Thread = NULL; nico@207: 00089 } nico@207: 00090 // --------------- CAN Receive Thread Implementation --------------- nico@207: 00091 nico@207: 00092 nico@207: 00093 // --------------- Timer Thread Implementation --------------- nico@207: 00094 class class_timers nico@207: 00095 { nico@207: 00096 public: nico@207: 00097 class_timers(); nico@207: 00098 ~class_timers(); nico@207: 00099 void start_timer_thread(); nico@207: 00100 void resume_timer_thread(); nico@207: 00101 void stop_timer_thread(); nico@207: 00102 void set_timer(TIMEVAL value); nico@207: 00103 TIMEVAL get_elapsed_time(); nico@207: 00104 private: nico@207: 00105 TIMEVAL get_timer() const; nico@207: 00106 static DWORD WINAPI timer_loop_thread_proc(void* arg); nico@207: 00107 private: nico@207: 00108 TIMEVAL m_last_occured_alarm_time; nico@207: 00109 volatile TIMEVAL m_last_alarm_set_time; nico@207: 00110 HANDLE m_timer_thread; nico@207: 00111 volatile bool m_continue_timer_loop; nico@207: 00112 bool m_use_hi_res_timer; nico@207: 00113 double m_counts_per_usec; nico@207: 00114 }; nico@207: 00115 nico@207: 00116 class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX), nico@207: 00117 m_last_alarm_set_time(TIMEVAL_MAX), nico@207: 00118 m_timer_thread(0), nico@207: 00119 m_continue_timer_loop(false), nico@207: 00120 m_use_hi_res_timer(false), nico@207: 00121 m_counts_per_usec(0.) nico@207: 00122 { nico@207: 00123 // initialize hi resolution timer nico@207: 00124 LARGE_INTEGER counts_per_sec = {0, 0}; nico@207: 00125 if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0) nico@207: 00126 { nico@207: 00127 m_use_hi_res_timer = true; nico@207: 00128 m_counts_per_usec = counts_per_sec.QuadPart / 1000000.; nico@207: 00129 } nico@207: 00130 m_use_hi_res_timer = true; nico@207: 00131 } nico@207: 00132 nico@207: 00133 class_timers::~class_timers() nico@207: 00134 { nico@207: 00135 stop_timer_thread(); nico@207: 00136 } nico@207: 00137 nico@207: 00138 // time is in micro seconds nico@207: 00139 TIMEVAL class_timers::get_timer() const nico@207: 00140 { nico@207: 00141 if (m_use_hi_res_timer) nico@207: 00142 { nico@207: 00143 LARGE_INTEGER performance_count = {0, 0}; nico@207: 00144 ::QueryPerformanceCounter(&performance_count); nico@207: 00145 return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec); nico@207: 00146 } nico@207: 00147 // hi-res timer is unavailable nico@207: 00148 return 1000 * ::GetTickCount(); nico@207: 00149 } nico@207: 00150 nico@207: 00151 DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg) nico@207: 00152 { nico@207: 00153 class_timers* This = reinterpret_cast<class_timers*>(arg); nico@207: 00154 while (This->m_continue_timer_loop) nico@207: 00155 { nico@207: 00156 TIMEVAL cur_time = This->get_timer(); nico@207: 00157 if (cur_time >= This->m_last_alarm_set_time) nico@207: 00158 { nico@207: 00159 This->m_last_occured_alarm_time = cur_time; nico@207: 00160 This->m_last_alarm_set_time = TIMEVAL_MAX; nico@207: 00161 EnterMutex(); nico@207: 00162 TimeDispatch(); nico@207: 00163 LeaveMutex(); nico@207: 00164 } nico@207: 00165 else nico@207: 00166 { nico@207: 00167 ::Sleep(1); nico@207: 00168 } nico@207: 00169 } nico@207: 00170 return 0; nico@207: 00171 } nico@207: 00172 nico@207: 00173 void class_timers::start_timer_thread() nico@207: 00174 { nico@207: 00175 if (m_timer_thread == 0) nico@207: 00176 { nico@207: 00177 unsigned long thread_id = 0; nico@207: 00178 m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, this, CREATE_SUSPENDED, &thread_id); nico@207: 00179 m_last_alarm_set_time = TIMEVAL_MAX; nico@207: 00180 m_last_occured_alarm_time = get_timer(); nico@207: 00181 } nico@207: 00182 } nico@207: 00183 nico@207: 00184 void class_timers::resume_timer_thread() nico@207: 00185 { nico@207: 00186 if (m_timer_thread) nico@207: 00187 { nico@207: 00188 m_continue_timer_loop = true; nico@207: 00189 ::ResumeThread(m_timer_thread); nico@207: 00190 } nico@207: 00191 } nico@207: 00192 nico@207: 00193 void class_timers::stop_timer_thread() nico@207: 00194 { nico@207: 00195 if (m_timer_thread) nico@207: 00196 { nico@207: 00197 m_continue_timer_loop = false; nico@207: 00198 ::WaitForSingleObject(m_timer_thread, INFINITE); nico@207: 00199 ::CloseHandle(m_timer_thread); nico@207: 00200 m_timer_thread = 0; nico@207: 00201 } nico@207: 00202 } nico@207: 00203 nico@207: 00204 void class_timers::set_timer(TIMEVAL value) nico@207: 00205 { nico@207: 00206 m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value; nico@207: 00207 } nico@207: 00208 nico@207: 00209 // elapsed time since last occured alarm nico@207: 00210 TIMEVAL class_timers::get_elapsed_time() nico@207: 00211 { nico@207: 00212 return get_timer() - m_last_occured_alarm_time; nico@207: 00213 } nico@207: 00214 nico@207: 00215 // ---------------------------------------------------------- nico@207: 00216 nico@207: 00217 static class_timers s_timers; nico@207: 00218 nico@207: 00219 void StartTimerLoop(TimerCallback_t init_callback) nico@207: 00220 { nico@207: 00221 s_timers.start_timer_thread(); nico@207: 00222 // At first, TimeDispatch will call init_callback. nico@207: 00223 if (init_callback != NULL) nico@207: 00224 SetAlarm(NULL, 0, init_callback, (TIMEVAL)0, (TIMEVAL)0); nico@207: 00225 s_timers.resume_timer_thread(); nico@207: 00226 } nico@207: 00227 nico@207: 00228 void StopTimerLoop(void) nico@207: 00229 { nico@207: 00230 s_timers.stop_timer_thread(); nico@207: 00231 } nico@207: 00232 nico@207: 00233 void setTimer(TIMEVAL value) nico@207: 00234 { nico@207: 00235 s_timers.set_timer(value); nico@207: 00236 } nico@207: 00237 nico@207: 00238 TIMEVAL getElapsedTime(void) nico@207: 00239 { nico@207: 00240 return s_timers.get_elapsed_time(); nico@207: 00241 } nico@207: