/*
 * timer.c
 *
 *  Created on: 2021/03/23
 *      Author: 0170886
 */
#include <kernel.h>
#include "kernel_cfg.h"
#include <t_syslog.h>
#include <t_stdlib.h>

#include "device.h"
#include "limits.h"
#include "cup_timer.h"
#include "common.h"
#include "timer.h"

/*
 *  Glboal Variable
 */
static unsigned char sw1;
static unsigned char sw8;
static TTM_CTL	gtm_ctl;


/* システム時刻による時間の測定(デバッグ用) */
static SYSUTM gStartTime;
static SYSUTM gCurrentTime;

/*
 *  Initialization Routine
 */
void
cup_timer_init(intptr_t exinf)
{
	sw8 = get_push1_state();
	sw1 = get_sw1_state();
}

void
timer_task_init(intptr_t exinf){
	GTM_CTLF = 0;
	GTM_REMTM = 0;
	GTM_NOWSTS = ST_TIMER_OFF;
	GTM_NEXTSTS = ST_TIMER_OFF;
}

/*
 *  Switch State Scan Cyclic Handler
 */
void
sw_scan_handler(intptr_t exinf){
	SVC_PERROR(iwup_tsk(SW_SCAN_TASK));
}

/*
 *  Switch State Scan Task
 */
void
sw_scan_task(intptr_t exinf){
	unsigned char sw;
	T_EVENT *psnd_data;

	for(;;){
		SVC_PERROR(slp_tsk());          /* ハンドラから起床されるまでスリープ */

		sw = get_sw1_state();
		if (sw1 != sw) {
			/* 固定長メモリブロックの獲得 */
			SVC_PERROR(get_mpf(EVENT_MPF, (void**)&psnd_data));
			if (sw == ON) {
				psnd_data -> event = EV_TIMER_SW1_ON;
			} else {
				psnd_data -> event = EV_TIMER_SW1_OFF;
			}
			DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", psnd_data);
        	SVC_PERROR(psnd_dtq(TIMER_DTQ, (intptr_t)psnd_data));
			sw1 = sw;
		}

		sw = get_push1_state();
		if (sw8 != sw) {
			if (sw == ON) {
				/* 固定長メモリブロックの獲得 */
				SVC_PERROR(get_mpf(EVENT_MPF, (void**)&psnd_data));
                psnd_data -> event = EV_TIMER_PUSH1_ON;
				DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", psnd_data);
	        	SVC_PERROR(psnd_dtq(TIMER_DTQ, (intptr_t)psnd_data));
				set_led2_state(ON);
			} else {
				set_led2_state(OFF);
			}
			sw8 = sw;
		}
	}
}

/*
 *  Base Time Generate Cyclic Handler
 */
void
base_time_handler(intptr_t exinf){
	SVC_PERROR(iwup_tsk(BASE_TIME_TASK));
}

/*
 *  Base Time Generate Task
 */
void
base_time_task(intptr_t exinf){
	T_EVENT *psnd_data;

	for(;;){
		SVC_PERROR(slp_tsk());          /* ハンドラから起床されるまでスリープ */
		/* 固定長メモリブロックの獲得 */
		SVC_PERROR(get_mpf(EVENT_MPF, (void**)&psnd_data));
		psnd_data -> event = EV_TIMER_BASE_TIME;
		DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", psnd_data);
	    SVC_PERROR(psnd_dtq(TIMER_DTQ, (intptr_t)psnd_data));
	}
}

/*
 *  Timer Task
 */
static void
StOffEvSw1Off(void){
	/* メモリプール解放禁止を設定 */
	GTM_CTLF |= DTM_NOTREL;

	/* 受信したメッセージのイベントを書き換えて転送 */
	GTM_RCVEV =  EV_BLINK_OFF;
    DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", GTM_RCVAD);
	SVC_PERROR(snd_dtq(BLINK_DTQ, (intptr_t)GTM_RCVAD));
	DEBUG_SYSLOG(LOG_NOTICE, " Timer stop!");
}

static void
StOnEvSw1Off(void){
	/* 状態遷移有り,メモリプール解放禁止を設定 */
	GTM_CTLF |= (DTM_STSCHG | DTM_NOTREL);

	GTM_NEXTSTS = ST_TIMER_OFF;	/* 次状態を「タイマOFF」状態に設定 	*/

	/* 受信したメッセージのイベントを書き換えて転送 */
	GTM_RCVEV = EV_BLINK_OFF;

    DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", GTM_RCVAD);
	SVC_PERROR(snd_dtq(BLINK_DTQ, (intptr_t)GTM_RCVAD));
	DEBUG_SYSLOG(LOG_NOTICE, " Timer stop!");
	GTM_REMTM = 0;
	stp_cyc(BASE_TIME_HANDLER);
}

static void
StOffEvSw1On(void){
	/* 状態遷移有り,メモリプール解放禁止を設定 */
	GTM_CTLF |= (DTM_STSCHG | DTM_NOTREL);

	GTM_NEXTSTS = ST_TIMER_ON;	/* 次状態を「タイマON」状態に設定 	*/

	GTM_REMTM = INIT_TIME;		/* タイムアウト時間を初期値に設定 	*/

	/* 受信したメッセージのイベントを書き換えて転送 */
	GTM_RCVEV = EV_BLINK_ACTIVE;

    DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", GTM_RCVAD);
	SVC_PERROR(snd_dtq(BLINK_DTQ, (intptr_t)GTM_RCVAD));
	DEBUG_SYSLOG(LOG_NOTICE, " Timer start!");
	SVC_PERROR(get_utm(&gStartTime)); /* スタート時刻を記憶 */
	sta_cyc(BASE_TIME_HANDLER);
}

static void
StOnEvPush1On(void){
	GTM_REMTM = GTM_REMTM + EXTRA_UNIT;
	DEBUG_SYSLOG(LOG_NOTICE, " Extend %d sec. Remaining  %d sec",
	EXTRA_UNIT, GTM_REMTM);
}

static void
StOnEvBaseTime(void){
	GTM_REMTM = GTM_REMTM - 1;
	if (GTM_REMTM == 0) {
		SVC_PERROR(get_utm(&gCurrentTime));
		DEBUG_SYSLOG(LOG_NOTICE, " System measurement time : %lu%s", gCurrentTime - gStartTime,"us");

		/* 状態遷移有り,メモリプール解放禁止を設定 */
		GTM_CTLF |= (DTM_STSCHG | DTM_NOTREL);
		GTM_NEXTSTS = ST_TIMER_OFF;	/* 次状態を「タイマOFF」状態に設定 	*/

		/* 受信したメッセージのイベントを書き換えて転送 */
		GTM_RCVEV = EV_BLINK_TIMEOUT;

        DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", GTM_RCVAD);
		SVC_PERROR(snd_dtq(BLINK_DTQ, (intptr_t)GTM_RCVAD));
		DEBUG_SYSLOG(LOG_NOTICE, " Timer timeout");
		stp_cyc(BASE_TIME_HANDLER);
	} else if ((GTM_REMTM % ACT_INTERVAL) == 0) {
		SVC_PERROR(get_utm(&gCurrentTime));
		DEBUG_SYSLOG(LOG_NOTICE, " System measurement time : %lu%s", gCurrentTime - gStartTime,"us");

		/* メモリプール解放禁止を設定 */
		GTM_CTLF |= DTM_NOTREL;

		/* 受信したメッセージのイベントを書き換えて転送 */
		GTM_RCVEV = EV_BLINK_ACTIVE;

        DEBUG_SYSLOG(LOG_NOTICE, " snd_dtq = 0x%p", GTM_RCVAD);
		SVC_PERROR(snd_dtq(BLINK_DTQ, (intptr_t)GTM_RCVAD));
    	DEBUG_SYSLOG(LOG_NOTICE, " Remaining  %d sec", GTM_REMTM);
    }
}

/* タイマタスクのジャンプテーブルの定義 */
static const CALLBACK_TM TMStateTable[ST_TIMER_NUM][EV_TIMER_NUM]={
/*   SW1_OFF,           SW1_ON,          PUSH1_ON,         1秒経過 */
	{&StOffEvSw1Off,	&StOffEvSw1On, 	 NULL,			   NULL				},/* タイマOFF状態	*/
    {&StOnEvSw1Off,		NULL,			 &StOnEvPush1On,   &StOnEvBaseTime	},/* タイマON状態	*/
};

void
timer_task(intptr_t exinf)
{
	const CALLBACK_TM *pFunc;

	DEBUG_SYSLOG(LOG_NOTICE, " Cup Timer 7 start!");

	for (;;) {
        SVC_PERROR(rcv_dtq(TIMER_DTQ, (intptr_t *)&GTM_RCVAD));
		pFunc = &TMStateTable[GTM_NOWSTS][GTM_RCVEV];
		if(NULL != *pFunc){
			(*pFunc)();		/* 現状態とイベントに対応する関数を実行 */
		} else {
			DEBUG_SYSLOG(LOG_NOTICE, " ignore event. event id = %d ",GTM_RCVEV);
        }
		if(GTM_CTLF & DTM_STSCHG) {		/* 状態遷移要求有り? */
			GTM_CTLF &= ~DTM_STSCHG;	/* 要求クリア		 */
			GTM_NOWSTS = GTM_NEXTSTS;   /* 状態更新 		 */
		}
		if(GTM_CTLF & DTM_NOTREL){		/* メモリプール解放禁止? */
			GTM_CTLF &= ~DTM_NOTREL;	/* 要求クリア		 */
			DEBUG_SYSLOG(LOG_NOTICE, " Not call rel_mpf");
		}
		else{
	        DEBUG_SYSLOG(LOG_NOTICE, " rel_mpf = 0x%p", GTM_RCVAD);
			SVC_PERROR(rel_mpf(EVENT_MPF, GTM_RCVAD));
		}
	}
}

