{-
Copyright 2016 Markus Ongyerth
This file is part of pulseaudio-hs.
Monky is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Monky 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with pulseaudio-hs. If not, see .
-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-|
Module : Data.Time
Description : provides the time type used by this package and a few functions on it
Maintianer : ongy
Stability : experimental
-- Portability : Linux (Not quite sure if headers are specific, might be POSIX)
Pulseaudio uses struct timeval for time. Since the time package on hackage does not
export the internal functions, this module exports a type and functions for that
type.
-}
module Data.Time
( PATime
, getTime
, addSeconds
, addNSeconds
, addTimes
, getDiff
, timeToUS
, timeFromUS
, dummyTime
)
where
-- PATime is defined in here, for better hiding :)
import Data.Time.Internal
import Data.Word (Word)
import Foreign.Ptr
import Foreign.Storable
import Foreign.C.Types
import Foreign.Marshal.Alloc
#include
foreign import ccall unsafe "clock_gettime" clock_gettime :: CInt -> Ptr PATime -> IO CInt
-- We don't take an clockid argument for now, this is PA use, not general time
-- library
-- |Get the current system time in real time (wallclock)
getTime :: IO PATime
getTime = alloca $ \ptr -> do
ret <- clock_gettime #{const CLOCK_REALTIME} ptr
if ret /= 0
then error "This should not happen, PAs getTime failed"
else peek ptr
-- |Add seconds to a 'PATime'
addSeconds :: Integral a => a -> PATime -> PATime
addSeconds x (PATime s n) = (PATime (s + fromIntegral x) n)
-- |Add nanoseconds to a 'PATime'
addNSeconds :: Integral a => a -> PATime -> PATime
addNSeconds x (PATime s n) =
let new = n + fromIntegral x
cap = 1000 * 1000 * 1000
over = if new > cap
then 1
else 0
capped = new `mod` cap
in PATime (s + over) capped
-- |Add two 'PATime's together
addTimes :: PATime -> PATime -> PATime
addTimes (PATime s n) = addSeconds s . addNSeconds n
-- |Get the difference between to times.
getDiff :: PATime -> PATime -> PATime
getDiff l@(PATime ls ln) r@(PATime rs rn) = if l < r
then error "PAs getDiff only works if the first argument is greater"
else let new = ln -rn
cap = 1000 * 1000 * 1000
over = if new < 0
then (-1)
else 0
capped = new `mod` cap
in PATime (ls - rs + over) capped
-- |Convert from Microseconds to 'PATime'
timeFromUS :: Word -> PATime
timeFromUS x = let cap = 1000 * 1000 in
PATime (x `div` cap) $ fromIntegral (x `mod` cap * 1000)
-- |Convert a 'PATime' to Microseconds
timeToUS :: PATime -> Word
timeToUS (PATime s ns) =
s * 1000 * 1000 + fromIntegral ns `div` 1000
-- |A dummy time value, do not use to calculate, only if guaranteed to be
-- ignored
dummyTime :: PATime
dummyTime = PATime 0 0