#!/usr/bin/python

# Copyright 2010 Robert Siemer
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


# 0.1 first release


import ctypes, os, errno
from ctypes import c_int, c_long, c_void_p, POINTER, byref

_rt = ctypes.CDLL('librt.so.1')

def errcheck(result, func, args):
    if result:
        e = ctypes.get_errno()
        raise ValueError(errno.errorcode[e] + os.strerror(e))
    return args

CLOCK_REALTIME = 0
CLOCK_MONOTONIC = 1
CLOCK_PROCESS_CPUTIME_ID = 2
CLOCK_THREAD_CPUTIME_ID = 3

# int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
prototype = ctypes.CFUNCTYPE(c_int, c_int, c_void_p, POINTER(c_void_p), use_errno=True)
paramflags = (1, 'clockid', CLOCK_REALTIME), (1, 'evp', None), (2, 'timerid')
_timer_create = prototype(('timer_create',  _rt), paramflags)
_timer_create.errcheck = errcheck

#           struct timespec {
#               time_t tv_sec;                /* Seconds */
#               long   tv_nsec;               /* Nanoseconds */
#           };

#           struct itimerspec {
#               struct timespec it_interval;  /* Timer interval */
#               struct timespec it_value;     /* Initial expiration */
#           };

class Timespec(ctypes.Structure):
    _fields_ = [('sec', c_long),
                ('nsec', c_long)]

class ITimerspec(ctypes.Structure):
    _fields_ = [('interval', Timespec),
                ('value', Timespec)]

itp = POINTER(ITimerspec)

# int timer_settime(timer_t timerid, int flags,
#        const struct itimerspec *new_value, struct itimerspec * old_value);
prototype = ctypes.CFUNCTYPE(c_int, c_void_p, c_int, itp, itp, use_errno=True)
paramflags = (1, 'timerid'), (1, 'flags'), (1, 'new_value'), (2, 'old_value')
_timer_settime = prototype(('timer_settime',  _rt), paramflags)
_timer_settime.errcheck = errcheck
        
# int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
prototype = ctypes.CFUNCTYPE(c_int, c_void_p, itp, use_errno=True)
paramflags = (1, 'timerid'), (2, 'curr_value')
_timer_gettime = prototype(('timer_gettime',  _rt), paramflags)
_timer_gettime.errcheck = errcheck

class Timer(object):
    def __init__(self, clockid, signal=True):
        self.timerid = _timer_create(clockid=clockid)

    def settime(self, time, absolute=False):
        # absolute should be False or True, so that it gets into 0/1 as int
        old = _timer_settime(self.timerid, absolute, ITimerspec(*time))
        return (old.interval.sec, old.interval.nsec), (old.value.sec, old.value.nsec)

    def gettime(self):
        old = _timer_gettime(self.timerid)
        return (old.interval.sec, old.interval.nsec), (old.value.sec, old.value.nsec)

    def getoverrun(self):
        # timer_getoverrun()
        pass

    def __delete__(self):
        # timer_delte(self.timerid)
        pass
