nico@215: nico@215: nico@215: CanFestival: drivers/win32/timers_win32.cpp Source File nico@215: nico@215: nico@215: nico@215: nico@215:
nico@215:
nico@215:
nico@215:
nico@215: nico@215:

timers_win32.cpp

Go to the documentation of this file.
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: 

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