/*
 * ChangeTime_tl.c
 */
#include <string.h>
#include <tz_time.h>
#include <qsee_timer.h>

#include "ChangeTime_tl.h"
#include "tz_arcounter_errors.h"
#include "tz_arcounter_defs.h"

#include "tz_iccc_comdef.h"

uint32_t process_ChangeTime(
	tl_arcounter_ctx_t * ctx,
	tz_arcounter_changetime_payload_t * sendmsg,
	tz_arcounter_changetime_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 unwrapped_cache_buff[MAX_ARCOUNTER_WRAP_BUFFER] = {0x0};
	uint32_t cached_ref_time = 0;
	uint32_t cached_tz_time = 0;
	uint8_t flag = 0x0;

	uint8_t index = 0;
	uint32_t next_period = TZ_ARCOUNTER_MAX_TICK_PERIOD;

	TTY_LOG("TL_TZ_ARCOUNTER: process_ChangeTime: 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;
	}

	if (sendmsg->payload.cmd.cache_size > 0
	 && sendmsg->payload.cmd.cache_size <= MAX_ARCOUNTER_WRAP_BUFFER) {
		uint32_t temp_size = MAX_ARCOUNTER_WRAP_BUFFER;
		ret = unwrap_time(sendmsg->payload.cmd.cached_time, sendmsg->payload.cmd.cache_size, unwrapped_cache_buff, &temp_size);
		if (TZ_API_OK != ret) {
			TTY_LOG("TL_TZ_ARCOUNTER: failed to wrap cached time 0x%x", ret);
			cached_ref_time = 0;
			cached_tz_time = 0;
		}
		else {
			memcpy(&cached_ref_time, unwrapped_cache_buff, REF_TIME_SIZE);
			memcpy(&cached_tz_time, unwrapped_cache_buff+REF_TIME_SIZE, TZ_TIME_SIZE);
#ifdef DEBUG
			TTY_LOG("TL_TZ_ARCOUNTER: temp_size : 0x%x", temp_size);
			TTY_LOG("TL_TZ_ARCOUNTER: cached_ref_time : 0x%x", cached_ref_time);
			TTY_LOG("TL_TZ_ARCOUNTER: cached_tz_time : 0x%x", cached_tz_time);
#endif
		}
	}

	memcpy(&old_ref_time, rpmb_buffer+REF_TIME_OFFSET, REF_TIME_SIZE);
	memcpy(&delta, rpmb_buffer+DELTA_OFFSET, DELTA_SIZE);
	memcpy(&tz_time, rpmb_buffer+TZ_TIME_OFFSET, TZ_TIME_SIZE);
#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);
	TTY_LOG("TL_TZ_ARCOUNTER: cached_time : 0x%x", cached_ref_time);
#endif
	if (cached_ref_time > old_ref_time && cached_tz_time > tz_time) {
		old_ref_time = cached_ref_time;
		tz_time = cached_tz_time;
	}

	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);
		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;
	}

	  // gen delta
#if 0 // normal
	if (old_ref_time >= sendmsg->payload.cmd.input) {
		delta = old_ref_time - sendmsg->payload.cmd.input;
	}
	else {
		delta = 0;
		old_ref_time = sendmsg->payload.cmd.input;
	}
#else //test
	delta = ref_time - sendmsg->payload.cmd.input;
#endif

	memcpy(rpmb_buffer+REF_TIME_OFFSET, &ref_time, REF_TIME_SIZE);
	memcpy(rpmb_buffer+DELTA_OFFSET, &delta, DELTA_SIZE);
	memcpy(rpmb_buffer+TZ_TIME_OFFSET, &tz_time, TZ_TIME_SIZE);

	index = check_timer(&next_period, rpmb_buffer);

	rpmb_ret = arcounter_rpmb_write(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
 		TTY_LOG("TL_TZ_ARCOUNTER: rpmb write (update time) failed 0x%x", rpmb_ret);
		goto exit;
	}

	respmsg->payload.resp.alarm_state = index;
	respmsg->payload.resp.next_tick = next_period;
	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;
}
