/*
 * GetRemainingTime_tl.c
 */

#include <string.h>
#include <tz_time.h>
#include <qsee_timer.h>

#include "GetRemainingTime_tl.h"
#include "tz_arcounter_errors.h"
#include "tz_arcounter_defs.h"

#include "tz_iccc_comdef.h"

uint32_t process_GetRemainingTime(
	tl_arcounter_ctx_t * ctx,
	tz_arcounter_getremainingtime_payload_t * sendmsg,
	tz_arcounter_getremainingtime_payload_t * respmsg
)
{
	uint32_t ret = RET_TL_TZ_ARCOUNTER_INTERNAL_ERR;
	uint32_t iccc_ret;
	int rpmb_ret;

	uint8_t rpmb_buffer[TZ_RPMB_ARCOUNTER_BLOCK_SIZE];
	uint32_t curr_time;
	uint32_t ref_time = 0x0;
	uint32_t old_ref_time = 0x0;
	int32_t delta = 0x0;
	uint32_t tz_time = 0x0;
	uint8_t flag = 0x0;

	uint8_t index = 0;
	uint32_t next_period = TZ_ARCOUNTER_MAX_TICK_PERIOD;
	uint8_t timer_index = sendmsg->payload.cmd.index;
	uint32_t temp_timer = 0;

	TTY_LOG("TL_TZ_ARCOUNTER: process_GetRemainingTime: entering");
	respmsg->payload.resp.alarm_state = 0;
	respmsg->payload.resp.next_tick = TZ_ARCOUNTER_MAX_TICK_PERIOD;
	respmsg->payload.resp.return_code = TZ_ARCOUNTER_INTERNAL_ERROR;

	rpmb_ret = arcounter_rpmb_read(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
		TTY_LOG("TL_TZ_ARCOUNTER: rpmb read failed 0x%x", rpmb_ret);
		goto exit;
	}

	memcpy(&flag, rpmb_buffer+ENABLE_FLAG_OFFSET, ENABLE_FLAG_SIZE);
	if (flag != 1) {
		TTY_LOG("TZ_ARCOUNTER: arcounter is not enabled");
		respmsg->payload.resp.return_code = TZ_ARCOUNTER_SUCCESS;
		goto exit;
	}

	memcpy(&old_ref_time, rpmb_buffer, 4);
	memcpy(&delta, &rpmb_buffer[4], 4);
	memcpy(&tz_time, &rpmb_buffer[8], 4);
#ifdef DEBUG
	TTY_LOG("TL_TZ_ARCOUNTER: old ref.time : 0x%x", old_ref_time);
	TTY_LOG("TL_TZ_ARCOUNTER: delta : 0x%x", delta);
	TTY_LOG("TL_TZ_ARCOUNTER: tz_time : 0x%x", tz_time);
#endif

	curr_time = (uint32_t)(tz_get_timestamp()/1000);
//	TTY_LOG("TL_TZ_ARCOUNTER: curr_time : sec 0x%x", curr_time);

	if (curr_time >= tz_time) {
		ref_time = old_ref_time + (curr_time - tz_time);
//		TTY_LOG("TL_TZ_ARCOUNTER: diff : 0x%x", curr_time - tz_time);
		tz_time = curr_time;
	}
	else {
		respmsg->payload.resp.return_code = 0x10;
		TTY_LOG("TL_TZ_ARCOUNTER: curr_time is wrong");
		goto exit;
	}

	if (ref_time < old_ref_time || ref_time > TZ_ARCOUNTER_MAX_REF_TIME) {
		TTY_LOG("TL_TZ_ARCOUNTER: ref_time is wrong");
		ref_time = TZ_ARCOUNTER_MAX_REF_TIME;
	}

	memset(respmsg->payload.resp.cached_time, 0x0, MAX_ARCOUNTER_WRAP_BUFFER);

	memcpy(rpmb_buffer+REF_TIME_OFFSET, &ref_time, REF_TIME_SIZE);
	memcpy(rpmb_buffer+TZ_TIME_OFFSET, &tz_time, TZ_TIME_SIZE);

	index = check_timer(&next_period, rpmb_buffer);

	uint32_t temp_size = MAX_ARCOUNTER_WRAP_BUFFER;
	uint8_t temp_buff[8] = {0x0, };
	uint32_t temp_ret = 0;

	memcpy(temp_buff, &ref_time, REF_TIME_SIZE);
	memcpy(temp_buff+REF_TIME_SIZE, &tz_time, TZ_TIME_SIZE);
	temp_ret = wrap_time(temp_buff, 8, respmsg->payload.resp.cached_time, &temp_size);
	if (TZ_API_OK != temp_ret) {
		TTY_LOG("TL_TZ_ARCOUNTER: failed to wrap cached time 0x%x", rpmb_ret);
		goto exit;
	}
	respmsg->payload.resp.cache_size = temp_size;

	temp_timer = get_timer(timer_index, rpmb_buffer);
	if (temp_timer > 0) {
		temp_timer -= ref_time;
	}
	respmsg->payload.resp.alarm_state = index;
	respmsg->payload.resp.next_tick = next_period;
	respmsg->payload.resp.remaining_time = temp_timer;
	respmsg->payload.resp.return_code = TZ_ARCOUNTER_SUCCESS;
	ret = RET_TL_TZ_ARCOUNTER_OK;

	if (set_attn(ATTN_SC_REF_TIME, ref_time) == ICCC_SUCCESS) {
		TTY_LOG("TL_TZ_ARCOUNTER: ref_time is updated to attn.", rpmb_ret);
	}
#ifdef DEBUG
	rpmb_ret = arcounter_rpmb_read(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
		TTY_LOG("TL_TZ_ARCOUNTER: rpmb read (old ref.time) failed 0x%x", rpmb_ret);
		goto exit;
	}

	memcpy(&ref_time, rpmb_buffer, 4);
	memcpy(&delta, rpmb_buffer+4, 4);
	memcpy(&tz_time, rpmb_buffer+8, 4);

	TTY_LOG("TL_TZ_ARCOUNTER: ref.time : 0x%x", ref_time);
	TTY_LOG("TL_TZ_ARCOUNTER: delta : 0x%x", delta);
	TTY_LOG("TL_TZ_ARCOUNTER: tz time : 0x%x", tz_time);
	TTY_LOG("TL_TZ_ARCOUNTER: diff : 0x%x", ref_time - tz_time);
#endif
exit:
	return ret;
}
