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