/*
 *  Copyright (C) 2006 by Nagoya University Extension Course for
 *                       Embedded Software Specialists(NEXCESS), JAPAN
 *                2014 by Nagoya University
 *                        Graduate School of Information Science
 *                        Center for Embedded Computing Systems(NCES), JAPAN
 *                2014 by Mitsuhiro Matsuura
 */

/*
 * カップラーメンタイマ
 */
#include <kernel.h>
#include "kernel_cfg.h"
#include <t_syslog.h>
#include <t_stdlib.h>

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

/*
 *  API Error Log Output Function
 */
Inline void
svc_perror(const char *file, int_t line, const char *expr, ER ercd)
{
	if (ercd < 0) {
		t_perror(LOG_ERROR, file, line, expr, ercd);
	}
}

#define SVC_PERROR(expr)	svc_perror(__FILE__, __LINE__, #expr, (expr))

#define DEBUG_UART  /* シリアルポートにデバッグログを出力 */
#ifdef DEBUG_UART
#define DEBUG_SYSLOG(prio,arg2,arg3,arg4)                  \
	do{                                                    \
		syslog(prio,"%s() on line %d of the %s",           \
			__func__,__LINE__,__FILE__);                   \
        syslog(prio,arg2,arg3,arg4);                       \
	}while(0)
#else
#define DEBUG_SYSLOG(prio,arg2,arg3,arg4)
#endif /* DEBUG_UART */

/*
 *  Glboal Variable
 */
unsigned char sw1;
unsigned char sw8;

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

/*
 *  Timer Task
 */
void
timer_task(intptr_t exinf)
{
	ST_TIMER st_timer = ST_TIMER_OFF;
	int timer = 0;
    intptr_t event;

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

	for (;;) {
        SVC_PERROR(rcv_dtq(TIMER_DTQ, &event));
        switch(event){
        	case EV_TIMER_SW1_OFF:
        		switch(st_timer){
        			case ST_TIMER_OFF:
        		        SVC_PERROR(snd_dtq(BLINK_DTQ, EV_BLINK_OFF));
        				DEBUG_SYSLOG(LOG_NOTICE, " Timer stop!"," "," ");
        				break;
        			case ST_TIMER_ON:
        				st_timer = ST_TIMER_OFF;
        				SVC_PERROR(snd_dtq(BLINK_DTQ, EV_BLINK_OFF));
        				syslog(LOG_NOTICE, "Timer stop!"," "," ");
        				timer = 0;
        				stp_cyc(BASE_TIME_HANDLER);
        				break;
        			default:
        				break;
        		}
        		break;
        	case EV_TIMER_SW1_ON:
        		switch(st_timer){
        			case ST_TIMER_OFF:
        				st_timer = ST_TIMER_ON;
        				timer = INIT_TIME;
        				SVC_PERROR(snd_dtq(BLINK_DTQ, EV_BLINK_ACTIVE));
        				DEBUG_SYSLOG(LOG_NOTICE, " Timer start!"," "," ");
						SVC_PERROR(get_utm(&gStartTime)); /* スタート時刻を記憶 */
        				sta_cyc(BASE_TIME_HANDLER);
        				break;
        			default:
        				break;
        		}
        		break;
        	case EV_TIMER_PUSH1_ON:
        		switch(st_timer){
        			case ST_TIMER_ON:
    					timer = timer + EXTRA_UNIT;
    					DEBUG_SYSLOG(LOG_NOTICE, " Extend %d sec. Remaining  %d sec",
    							EXTRA_UNIT, timer);
        				break;
        			default:
        				break;
        		}
        		break;
        	case EV_TIMER_BASE_TIME:
        		switch(st_timer){
        			case ST_TIMER_ON:
    					timer = timer - 1;
    					if (timer == 0) {
							SVC_PERROR(get_utm(&gCurrentTime));
							DEBUG_SYSLOG(LOG_NOTICE, " System measurement time : %lu%s", gCurrentTime - gStartTime,"us");
            				st_timer = ST_TIMER_OFF;
            		        SVC_PERROR(snd_dtq(BLINK_DTQ, EV_BLINK_TIMEOUT));
    						DEBUG_SYSLOG(LOG_NOTICE, " Timer timeout"," "," ");
    						stp_cyc(BASE_TIME_HANDLER);
    					}
    					else if ((timer % ACT_INTERVAL) == 0) {
							SVC_PERROR(get_utm(&gCurrentTime));
							DEBUG_SYSLOG(LOG_NOTICE, " System measurement time : %lu%s", gCurrentTime - gStartTime,"us");
            		        SVC_PERROR(snd_dtq(BLINK_DTQ, EV_BLINK_ACTIVE));
    						DEBUG_SYSLOG(LOG_NOTICE, " Remaining  %d sec", timer," ");
    					}
        				break;
        			default:
        				break;
        		}
        		break;
        	default:
        		DEBUG_SYSLOG(LOG_NOTICE, " ERROR Timer Illegal event = %d ",event," ");
        		break;
        }
	}
}

/*
 *  LED4 Blink Task
 */
void
blink_task(intptr_t exinf)
{
	int bcount = 0;
	ST_BLINK st_blink = ST_BLINK_IDLE;
    intptr_t event;

	for (;;) {
        SVC_PERROR(rcv_dtq(BLINK_DTQ, &event));
        switch(event){
    		case EV_BLINK_TIMEOUT:
    			switch(st_blink){
    				case ST_BLINK_IDLE:
    					st_blink = ST_BLINK_LED_OFF;
    					bcount = TIMEOUT_BLINK;
    					sta_cyc(LED4_BLINK_TIME_HANDLER);
    					break;
    				default:
    					break;
    			}
				break;
        	case EV_BLINK_ACTIVE:
        		switch(st_blink){
        			case ST_BLINK_IDLE:
        				st_blink = ST_BLINK_LED_OFF;
        				bcount = ACT_BLINK_TIME;
        				sta_cyc(LED4_BLINK_TIME_HANDLER);
        				break;
        			default:
        				break;
        		}
				break;
            case EV_BLINK_OFF:
           		switch(st_blink){
           			case ST_BLINK_LED_OFF: /* Break through  */
           			case ST_BLINK_LED_ON:
           				st_blink = ST_BLINK_IDLE;
           				bcount = 0;
           				stp_cyc(LED4_BLINK_TIME_HANDLER);
           				break;
           			default:
           				break;
           		}
				break;
            case EV_BLINK_BLINK:
            	switch(st_blink){
            		case ST_BLINK_LED_OFF:
            			set_led4_state(ON);
            			bcount--;
            			if(bcount == 0){
            				st_blink = ST_BLINK_IDLE;
            				stp_cyc(LED4_BLINK_TIME_HANDLER);
            			} else {
            				st_blink = ST_BLINK_LED_ON;
            			}
            			break;
            		case ST_BLINK_LED_ON:
            			set_led4_state(OFF);
            			bcount--;
            			if(bcount == 0){
            				st_blink = ST_BLINK_IDLE;
            				stp_cyc(LED4_BLINK_TIME_HANDLER);
            			} else {
            				st_blink = ST_BLINK_LED_OFF;
            			}
            			break;
            		default:
            			break;
            	}
				break;
       		default:
         		DEBUG_SYSLOG(LOG_NOTICE, " ERROR Blink Illegal event = %d ",event," ");
				break;
        }
	}
}

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


/*
 *  LED1 Blink Cyclic Handler
 */
void
led1_blink_handler(intptr_t exinf){
	static unsigned char sta_led = OFF;

	if (sta_led == ON) {
		sta_led = OFF;
	} else {
		sta_led = ON;
	}

	set_led1_state(sta_led);
}


/*
 *  LED4 Blink Time Generate Cyclic Handler
 */
void
led4_blink_time_handler(intptr_t exinf){
    SVC_PERROR(ipsnd_dtq(BLINK_DTQ, EV_BLINK_BLINK));
}

/*
 *  Switch State Scan Cyclic Handler
 */
void
sw_scan_handler(intptr_t exinf){
	unsigned char sw;
	intptr_t snd_event;

	sw = get_sw1_state();
	if (sw1 != sw) {
		if (sw == ON) {
			snd_event = EV_TIMER_SW1_ON;
		} else {
			snd_event = EV_TIMER_SW1_OFF;
		}
        SVC_PERROR(ipsnd_dtq(TIMER_DTQ, snd_event));
		sw1 = sw;
	}

	sw = get_push1_state();
	if (sw8 != sw) {
		if (sw == ON) {
	        SVC_PERROR(ipsnd_dtq(TIMER_DTQ, EV_TIMER_PUSH1_ON));
			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(ipsnd_dtq(TIMER_DTQ, EV_TIMER_BASE_TIME));
}
