diff -r 3ebf16150b2e -r e747d2e26af0 drivers/win32/timers_win32.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/win32/timers_win32.cpp Wed Apr 04 13:04:31 2007 +0200 @@ -0,0 +1,241 @@ +/* +This file is part of CanFestival, a library implementing CanOpen Stack. + +Copyright (C): Edouard TISSERANT and Francis DUPIN +Copyright (C) Win32 Port Leonid Tochinski + +See COPYING file for copyrights details. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#include +#include + +extern "C" +{ +#include "applicfg.h" +#include "can_driver.h" +#include "timer.h" +#include "timers_driver.h" +}; + +// --------------- Synchronization Object Implementation --------------- +class ccritical_section + { + public: + ccritical_section() + { + ::InitializeCriticalSection(&m_cs); + } + ~ccritical_section() + { + ::DeleteCriticalSection(&m_cs); + } + void enter() + { + ::EnterCriticalSection(&m_cs); + } + void leave() + { + ::LeaveCriticalSection(&m_cs); + } + private: + CRITICAL_SECTION m_cs; + }; + +static ccritical_section g_cs; + + +void EnterMutex(void) + { + g_cs.enter(); + } + +void LeaveMutex(void) + { + g_cs.leave(); + } +// --------------- Synchronization Object Implementation --------------- + + +// --------------- CAN Receive Thread Implementation --------------- + +void CreateReceiveTask(CAN_HANDLE fd0, TASK_HANDLE* Thread, void* ReceiveLoopPtr) + { + unsigned long thread_id = 0; + *Thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveLoopPtr, fd0, 0, &thread_id); + } + +void WaitReceiveTaskEnd(TASK_HANDLE Thread) + { + ::WaitForSingleObject(Thread, INFINITE); + ::CloseHandle(Thread); + //*Thread = NULL; + } +// --------------- CAN Receive Thread Implementation --------------- + + +// --------------- Timer Thread Implementation --------------- +class class_timers + { + public: + class_timers(); + ~class_timers(); + void start_timer_thread(); + void resume_timer_thread(); + void stop_timer_thread(); + void set_timer(TIMEVAL value); + TIMEVAL get_elapsed_time(); + private: + TIMEVAL get_timer() const; + static DWORD WINAPI timer_loop_thread_proc(void* arg); + private: + TIMEVAL m_last_occured_alarm_time; + volatile TIMEVAL m_last_alarm_set_time; + HANDLE m_timer_thread; + volatile bool m_continue_timer_loop; + bool m_use_hi_res_timer; + double m_counts_per_usec; + }; + +class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX), + m_last_alarm_set_time(TIMEVAL_MAX), + m_timer_thread(0), + m_continue_timer_loop(false), + m_use_hi_res_timer(false), + m_counts_per_usec(0.) + { + // initialize hi resolution timer + LARGE_INTEGER counts_per_sec = {0, 0}; + if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0) + { + m_use_hi_res_timer = true; + m_counts_per_usec = counts_per_sec.QuadPart / 1000000.; + } + m_use_hi_res_timer = true; + } + +class_timers::~class_timers() + { + stop_timer_thread(); + } + +// time is in micro seconds +TIMEVAL class_timers::get_timer() const + { + if (m_use_hi_res_timer) + { + LARGE_INTEGER performance_count = {0, 0}; + ::QueryPerformanceCounter(&performance_count); + return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec); + } + // hi-res timer is unavailable + return 1000 * ::GetTickCount(); + } + +DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg) + { + class_timers* This = reinterpret_cast(arg); + while (This->m_continue_timer_loop) + { + TIMEVAL cur_time = This->get_timer(); + if (cur_time >= This->m_last_alarm_set_time) + { + This->m_last_occured_alarm_time = cur_time; + This->m_last_alarm_set_time = TIMEVAL_MAX; + EnterMutex(); + TimeDispatch(); + LeaveMutex(); + } + else + { + ::Sleep(1); + } + } + return 0; + } + +void class_timers::start_timer_thread() + { + if (m_timer_thread == 0) + { + unsigned long thread_id = 0; + m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, this, CREATE_SUSPENDED, &thread_id); + m_last_alarm_set_time = TIMEVAL_MAX; + m_last_occured_alarm_time = get_timer(); + } + } + +void class_timers::resume_timer_thread() + { + if (m_timer_thread) + { + m_continue_timer_loop = true; + ::ResumeThread(m_timer_thread); + } + } + +void class_timers::stop_timer_thread() + { + if (m_timer_thread) + { + m_continue_timer_loop = false; + ::WaitForSingleObject(m_timer_thread, INFINITE); + ::CloseHandle(m_timer_thread); + m_timer_thread = 0; + } + } + +void class_timers::set_timer(TIMEVAL value) + { + m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value; + } + +// elapsed time since last occured alarm +TIMEVAL class_timers::get_elapsed_time() + { + return get_timer() - m_last_occured_alarm_time; + } + +// ---------------------------------------------------------- + +static class_timers s_timers; + +void StartTimerLoop(TimerCallback_t init_callback) + { + s_timers.start_timer_thread(); + // At first, TimeDispatch will call init_callback. + if (init_callback != NULL) + SetAlarm(NULL, 0, init_callback, (TIMEVAL)0, (TIMEVAL)0); + s_timers.resume_timer_thread(); + } + +void StopTimerLoop(void) + { + s_timers.stop_timer_thread(); + } + +void setTimer(TIMEVAL value) + { + s_timers.set_timer(value); + } + +TIMEVAL getElapsedTime(void) + { + return s_timers.get_elapsed_time(); + }