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