/*
 * Copyright (c) 2001-2003 Shiman Associates Inc. All Rights Reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#include "mas/mas_common.h"
#include "mas/mas_nanosleep_reality.h"
#include "mas_time_pd.h"

#define NTP_UNIX_EPOCH_START 2208988800u
#define NTP_LSW_MULTIPLIER   2.32830643654E-10
#define NTP_LSW16_MULTIPLIER 1.52587890625E-5

/***************************************************************************
 * Initialization and exit cleanup -- must be called before calling
 * other timing functions.
 * 
 */
int32
masc_init_timing( void )
{
    int32 err;
    
    masc_entering_log_level("Initializing timers: masc_init_timing()");
    err = masc_init_timing_pd();
    masc_exiting_log_level();
    
    return err;
}


int32
masc_exit_timing( void )
{
    int32 err;
    
    masc_entering_log_level("Initializing timers: masc_init_timing()");
    err = masc_exit_timing_pd();
    masc_exiting_log_level();
    
    return err;
}

/***************************************************************************
 * masc_get_systime
 *
 * arguments:
 *    1. pointer to struct mas_ntpval
 *
 *  Fills out an NTP-style timestamp from the system clock's current time.
 *
 * returns: error
 *
 ***************************************************************************/
int32
masc_get_systime(struct mas_ntpval* systime)
{
    return masc_get_systime_pd( systime );
}

/***************************************************************************
 * masc_get_short_usec_ts
 *
 * arguments:
 *    1. pointer to 32-bit unsigned counter
 *
 *  Gets the current system time and stores it in a 32-bit wrapping
 *  counter.  This rolls over every 71.6 minutes.  You can't use it to
 *  time events longer than that. 
 *
 * returns: error
 *
 ***************************************************************************/
int32
masc_get_short_usec_ts(u_int32* usec)
{
    return masc_get_short_usec_ts_pd( usec );
}

/***************************************************************************
 * masc_nanosleep
 *
 * arguments:
 *    1. 32-bit unsigned nanoseconds
 *
 *  Puts the process or LWP to sleep for a specified number of
 *  nanoseconds.  This could have rather coarse resolution on some
 *  systems. Since it's a 32bit uint this function can't sleep for
 *  longer than 4.29 seconds (2^32 / 10^9).
 *
 * returns: error
 *
 ***************************************************************************/
int32
masc_nanosleep(u_int32 nsec)
{
    return masc_nanosleep_pd( nsec );
}

/***************************************************************************
 * masc_realsleep
 *
 * arguments:
 *    1. 32-bit unsigned nanoseconds
 *
 *  This is a front end for nanosleep() that takes advantage of
 *  compiled in tables for nanosleep values and actual average time
 *  slept.  This function tries to sleep for time less than or equal to
 *  the specified time.  Thus, if you ask it to sleep for 27ms, and it
 *  knows how to sleep for either 20ms or 30ms, it will sleep for
 *  20ms.
 *
 * returns: error
 *
 ***************************************************************************/
int32
masc_realsleep(u_int32 nsec)
{
    int i = 0;

    while ( (mas_nanosleep_real_wall_clock[i] != 0) &&
	    (mas_nanosleep_real_wall_clock[i] <= nsec) )
	i++;

    if (i == 0) return -1;
    else return masc_nanosleep(mas_nanosleep_real_value[i-1]);
}

int32
masc_ntp_to_double(struct mas_ntpval* ntptime, double* doubletime)
{
    *doubletime = (double)ntptime->secs + (double)ntptime->frac * NTP_LSW_MULTIPLIER;
    return 0;

}

int32
masc_ntp32_to_double(uint32 ntptime, double* doubletime)
{
    *doubletime = (double)ntptime * NTP_LSW16_MULTIPLIER;
    return 0;
}

#if _POSIX_C_SOURCE
int32
masc_timeval_to_double(struct timeval* tv, double* doubletime)
{
    *doubletime = tv->tv_sec + (double)tv->tv_usec/1000000.0 + NTP_UNIX_EPOCH_START;
    return 0;
}
#endif
