/******************************************************************************
 *
 * Copyright 2017, Lattice Semiconductor, Inc. All rights reserved.
 * No part of this work may be reproduced, modified, distributed, transmitted,
 * transcribed, or translated into any language or computer format, in any form
 * or by any means without written permission of Lattice Semiconductor Inc.,
 * 111 SW 5th Ave, Suite 700, Portland, OR 97204.
 *
 *****************************************************************************/
/**
 * @file sii_sys_time.c
 *
 * @brief Time library
 *
 *****************************************************************************/
/* #define SII_DEBUG 3 */

/***** #include statements ***************************************************/

#include "sii_system_api.h"
#include "sii_sys_time_api.h"
#include "sii_platform_api.h"
#include "sii_sys_assert_api.h"

/***** Register Module name **************************************************/

SII_MODULE_NAME_SET(lib_time);

/***** local macro definitions ***********************************************/

/* Maximum milli out must be set to less than half the range of
 * SII_SYS_TIME_MILLI_T */
#define MILLI_TO_MAX	(((SII_SYS_TIME_MILLI_T) ~0) >> 1)

/***** local type definitions ************************************************/

/***** local prototypes ******************************************************/

static void s_time_out_milli_set(SII_SYS_TIME_MILLI_T *p_milli_to,
		SII_SYS_TIME_MILLI_T time_out);
static bool_t s_time_out_milli_is(const SII_SYS_TIME_MILLI_T *p_milli_to);

/***** local data objects ****************************************************/

/***** public functions ******************************************************/

SII_SYS_TIME_MILLI_T sii_sys_time_milli_diff_get(SII_SYS_TIME_MILLI_T t1,
		SII_SYS_TIME_MILLI_T t2)
{
	if (t2 < t1)
		return ((SII_SYS_TIME_MILLI_T) ~0) - t1 + t2 + 1;
	else
		return t2 - t1;
}

void sii_sys_time_out_milli_set(SII_SYS_TIME_MILLI_T *p_milli_to,
		SII_SYS_TIME_MILLI_T time_out)
{
	s_time_out_milli_set(p_milli_to, time_out);
}

bool_t sii_sys_time_out_milli_is(const SII_SYS_TIME_MILLI_T *p_milli_to)
{
	return s_time_out_milli_is(p_milli_to);
}

void sii_sys_time_milli_delay(SII_SYS_TIME_MILLI_T milli_delay)
{
	SII_SYS_TIME_MILLI_T milli_to;

	s_time_out_milli_set(&milli_to, milli_delay);

	while (!s_time_out_milli_is(&milli_to))
		;
}

/***** local functions *******************************************************/

static void s_time_out_milli_set(SII_SYS_TIME_MILLI_T *p_milli_to,
		SII_SYS_TIME_MILLI_T time_out)
{
	SII_ASSERT(MILLI_TO_MAX > time_out);
	*p_milli_to = (SII_SYS_TIME_MILLI_T) sii_platform_time_msec_query()
		+ time_out;
}

static bool_t s_time_out_milli_is(const SII_SYS_TIME_MILLI_T *p_milli_to)
{
	SII_SYS_TIME_MILLI_T milli_new =
			(SII_SYS_TIME_MILLI_T) sii_platform_time_msec_query();
	SII_SYS_TIME_MILLI_T milli_diff =
			(*p_milli_to > milli_new) ?
					(*p_milli_to - milli_new) :
					(milli_new - *p_milli_to);

	if (MILLI_TO_MAX < milli_diff)
		return (*p_milli_to > milli_new) ? (TRUE) : (FALSE);
	else
		return (*p_milli_to <= milli_new) ? (TRUE) : (FALSE);
}

/***** end of file ***********************************************************/
