drivers/timers_win32/timers_win32.cpp
changeset 556 8296acd119a9
parent 555 ee24dcbd3e64
child 557 922873e5b409
equal deleted inserted replaced
555:ee24dcbd3e64 556:8296acd119a9
     1 /*
       
     2 This file is part of CanFestival, a library implementing CanOpen Stack.
       
     3 
       
     4 Copyright (C): Edouard TISSERANT and Francis DUPIN
       
     5 Copyright (C) Win32 Port Leonid Tochinski
       
     6 
       
     7 See COPYING file for copyrights details.
       
     8 
       
     9 This library is free software; you can redistribute it and/or
       
    10 modify it under the terms of the GNU Lesser General Public
       
    11 License as published by the Free Software Foundation; either
       
    12 version 2.1 of the License, or (at your option) any later version.
       
    13 
       
    14 This library is distributed in the hope that it will be useful,
       
    15 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    17 Lesser General Public License for more details.
       
    18 
       
    19 You should have received a copy of the GNU Lesser General Public
       
    20 License along with this library; if not, write to the Free Software
       
    21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    22 */
       
    23 
       
    24 
       
    25 
       
    26 #include <windows.h>
       
    27 #include <stdlib.h>
       
    28 
       
    29 extern "C"
       
    30 {
       
    31 #include "applicfg.h"
       
    32 #include "can_driver.h"
       
    33 #include "timer.h"
       
    34 #include "timers_driver.h"
       
    35 };
       
    36 
       
    37 // --------------- Synchronization Object Implementation ---------------
       
    38 class ccritical_section
       
    39    {
       
    40    public:
       
    41       ccritical_section()
       
    42          {
       
    43          ::InitializeCriticalSection(&m_cs);
       
    44          }
       
    45       ~ccritical_section()
       
    46          {
       
    47          ::DeleteCriticalSection(&m_cs);
       
    48          }
       
    49       void enter()
       
    50          {
       
    51          ::EnterCriticalSection(&m_cs);
       
    52          }
       
    53       void leave()
       
    54          {
       
    55          ::LeaveCriticalSection(&m_cs);
       
    56          }
       
    57    private:
       
    58       CRITICAL_SECTION m_cs;
       
    59    };
       
    60 
       
    61 static ccritical_section g_cs;
       
    62 
       
    63 
       
    64 void EnterMutex(void)
       
    65    {
       
    66    g_cs.enter();
       
    67    }
       
    68 
       
    69 void LeaveMutex(void)
       
    70    {
       
    71    g_cs.leave();
       
    72    }
       
    73 // --------------- Synchronization Object Implementation ---------------
       
    74 
       
    75 
       
    76 // --------------- CAN Receive Thread Implementation ---------------
       
    77 
       
    78 void CreateReceiveTask(CAN_HANDLE fd0, TASK_HANDLE* Thread, void* ReceiveLoopPtr)
       
    79    {
       
    80    unsigned long thread_id = 0;
       
    81    *Thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveLoopPtr, fd0, 0, &thread_id);
       
    82    }
       
    83 
       
    84 void WaitReceiveTaskEnd(TASK_HANDLE *Thread)
       
    85    {
       
    86    ::WaitForSingleObject(*Thread, INFINITE);
       
    87    ::CloseHandle(*Thread);
       
    88    //*Thread = NULL;
       
    89    }
       
    90 // --------------- CAN Receive Thread Implementation ---------------
       
    91 
       
    92 
       
    93 // --------------- Timer Thread Implementation ---------------
       
    94 class class_timers
       
    95    {
       
    96    public:
       
    97       class_timers();
       
    98       ~class_timers();
       
    99       void start_timer_thread();
       
   100       void resume_timer_thread();
       
   101       void stop_timer_thread();
       
   102       void set_timer(TIMEVAL value);
       
   103       TIMEVAL get_elapsed_time();
       
   104    private:
       
   105       TIMEVAL get_timer() const;   
       
   106       static DWORD WINAPI timer_loop_thread_proc(void* arg);
       
   107    private:
       
   108       TIMEVAL m_last_occured_alarm_time;
       
   109       volatile TIMEVAL m_last_alarm_set_time;
       
   110       HANDLE m_timer_thread;
       
   111       volatile bool m_continue_timer_loop;
       
   112       bool m_use_hi_res_timer;
       
   113       double m_counts_per_usec;
       
   114    };
       
   115 
       
   116 class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX),
       
   117       m_last_alarm_set_time(TIMEVAL_MAX),
       
   118       m_timer_thread(0),
       
   119       m_continue_timer_loop(false),
       
   120       m_use_hi_res_timer(false),
       
   121       m_counts_per_usec(0.)
       
   122    {
       
   123    // initialize hi resolution timer
       
   124    LARGE_INTEGER counts_per_sec = {0, 0};
       
   125    if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0)
       
   126       {
       
   127       m_use_hi_res_timer = true;
       
   128       m_counts_per_usec = counts_per_sec.QuadPart / 1000000.;
       
   129       }
       
   130    m_use_hi_res_timer = true;
       
   131    }
       
   132 
       
   133 class_timers::~class_timers()
       
   134    {
       
   135    stop_timer_thread();
       
   136    }
       
   137 
       
   138 // time is in micro seconds
       
   139 TIMEVAL class_timers::get_timer() const
       
   140    {
       
   141    if (m_use_hi_res_timer)
       
   142       {
       
   143       LARGE_INTEGER performance_count = {0, 0};
       
   144       ::QueryPerformanceCounter(&performance_count);
       
   145       return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec);
       
   146       }
       
   147    // hi-res timer is unavailable
       
   148    return 1000 * ::GetTickCount();
       
   149    }
       
   150 
       
   151 DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg)
       
   152    {
       
   153    class_timers* This = reinterpret_cast<class_timers*>(arg);
       
   154    while (This->m_continue_timer_loop)
       
   155       {
       
   156       TIMEVAL cur_time = This->get_timer();
       
   157       if (cur_time >= This->m_last_alarm_set_time)
       
   158          {
       
   159          This->m_last_occured_alarm_time = cur_time;
       
   160          This->m_last_alarm_set_time = TIMEVAL_MAX;         
       
   161          EnterMutex();
       
   162          TimeDispatch();
       
   163          LeaveMutex();
       
   164          }
       
   165       else
       
   166          {
       
   167          ::Sleep(1);
       
   168          }
       
   169       }
       
   170    return 0;
       
   171    }
       
   172 
       
   173 void class_timers::start_timer_thread()
       
   174    {
       
   175    if (m_timer_thread == 0)
       
   176       {
       
   177       unsigned long thread_id = 0;
       
   178       m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, this, CREATE_SUSPENDED, &thread_id);
       
   179       m_last_alarm_set_time = TIMEVAL_MAX;
       
   180       m_last_occured_alarm_time = get_timer();
       
   181       }
       
   182    }
       
   183 
       
   184 void class_timers::resume_timer_thread()
       
   185    {
       
   186    if (m_timer_thread)
       
   187       {
       
   188       m_continue_timer_loop = true;
       
   189       ::ResumeThread(m_timer_thread);
       
   190       }
       
   191    }
       
   192 
       
   193 void class_timers::stop_timer_thread()
       
   194    {
       
   195    if (m_timer_thread)
       
   196       {
       
   197       m_continue_timer_loop = false;
       
   198       ::WaitForSingleObject(m_timer_thread, INFINITE);
       
   199       ::CloseHandle(m_timer_thread);
       
   200       m_timer_thread = 0;
       
   201       }
       
   202    }
       
   203 
       
   204 void class_timers::set_timer(TIMEVAL value)
       
   205    {
       
   206    m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value;
       
   207    }
       
   208 
       
   209 // elapsed time since last occured alarm
       
   210 TIMEVAL class_timers::get_elapsed_time()
       
   211    {
       
   212    return get_timer() - m_last_occured_alarm_time;
       
   213    }
       
   214 
       
   215 // ----------------------------------------------------------
       
   216 
       
   217 static class_timers s_timers;
       
   218 
       
   219 void TimerCleanup(void)
       
   220 {
       
   221 	/* only used in realtime apps */
       
   222 }
       
   223 
       
   224 void StartTimerLoop(TimerCallback_t init_callback)
       
   225    {
       
   226    s_timers.start_timer_thread();
       
   227    // At first, TimeDispatch will call init_callback.
       
   228    if (init_callback != NULL)
       
   229       SetAlarm(NULL, 0, init_callback, (TIMEVAL)0, (TIMEVAL)0);
       
   230    s_timers.resume_timer_thread();
       
   231    }
       
   232 
       
   233 void StopTimerLoop(TimerCallback_t init_callback)
       
   234    {
       
   235    s_timers.stop_timer_thread();
       
   236    }
       
   237 
       
   238 void setTimer(TIMEVAL value)
       
   239    {
       
   240    s_timers.set_timer(value);
       
   241    }
       
   242 
       
   243 TIMEVAL getElapsedTime(void)
       
   244    {
       
   245    return s_timers.get_elapsed_time();
       
   246    }