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