timers_win32.cpp

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

Generated on Mon Jul 2 19:10:16 2007 for CanFestival by  doxygen 1.5.1