
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include "EventLog.h"

volatile EVENT_LOG_INFO event_log_buff[CORE_NUM][EVENT_LOG_NUM];
static unsigned long event_log_idx[CORE_NUM];
unsigned long event_log_enable_flag[CORE_NUM];
unsigned long event_log_lap_flag[CORE_NUM];

pthread_mutex_t event_log_mutex;

/**/
unsigned long get_ms()
{
    struct timespec res;
    clock_gettime(CLOCK_MONOTONIC, &res);
    return(1000.0 * res.tv_sec + res.tv_nsec / 1000000);
}

/**/
unsigned long get_us()
{
    struct timespec res;
    clock_gettime(CLOCK_MONOTONIC, &res);
    return(1000000.0 * res.tv_sec + res.tv_nsec / 1000);
}

double get_us_double()
{
    struct timespec res;
    clock_gettime(CLOCK_MONOTONIC, &res);
    return(1000000.0 * res.tv_sec + (double)res.tv_nsec / 1000);
}

/***********************************************************************************/
/* 機能概要       : イベントログ初期化                                             */
/* 引数           : なし                                                           */
/* 戻り値         : なし                                                           */
/* 備考           :                                                                */
/***********************************************************************************/
void event_log_init(void)
{
    unsigned int  i;

    /* ログバッファ ALL 0xFFFFFFF書込み */
    memset((void *)event_log_buff, 0xFF, sizeof(event_log_buff));

    for(i=0; i<CORE_NUM; i++) {
        event_log_idx[i]         = 0;
        event_log_enable_flag[i] = 0;
        event_log_lap_flag[i]    = 0;
    }

	pthread_mutex_init(&event_log_mutex, NULL);
}

/***********************************************************************************/
/* 機能概要       : イベントログ有効化                                             */
/* 引数           : なし                                                           */
/* 戻り値         : なし                                                           */
/* 備考           :                                                                */
/***********************************************************************************/
void event_log_enable(void)
{
    unsigned int  i;

    for(i=0; i<CORE_NUM; i++) {
        event_log_enable_flag[i] = 1;
    }
}

/***********************************************************************************/
/* 機能概要       : イベントログ無効化                                             */
/* 引数           : なし                                                           */
/* 戻り値         : なし                                                           */
/* 備考           :                                                                */
/***********************************************************************************/
void event_log_disable(void)
{
    unsigned int  i;

    for(i=0; i<CORE_NUM; i++) {
        event_log_enable_flag[i] = 0;
    }
}

/***********************************************************************************/
/* 機能概要       : イベントラップ動作ON                                           */
/* 引数           : なし                                                           */
/* 戻り値         : なし                                                           */
/* 備考           :                                                                */
/***********************************************************************************/
void event_log_lap_on(void)
{
    unsigned int  i;

    for(i=0; i<CORE_NUM; i++) {
        event_log_lap_flag[i] = 1;
    }
}

/***********************************************************************************/
/* 機能概要       : イベントラップ動作OFF                                          */
/* 引数           : なし                                                           */
/* 戻り値         : なし                                                           */
/* 備考           :                                                                */
/***********************************************************************************/
void event_log_lap_off(void)
{
    unsigned int  i;

    for(i=0; i<CORE_NUM; i++) {
        event_log_lap_flag[i] = 0;
    }
}

/***********************************************************************************/
/* 機能概要       : イベントログ格納                                               */
/* 引数(入力)     : イベントコード                                                 */
/* 引数(入力)     : 付加情報 (任意の値)                                            */
/* 戻り値         : なし                                                           */
/* 備考           : イベント情報をイベントログバッファに格納する。                 */
/***********************************************************************************/
void event_log_put(unsigned short event_code, unsigned short option_val)
{
    unsigned int  core;
    register unsigned int idx;
    EVENT_LOG_INFO  wk;

	pthread_mutex_lock(&event_log_mutex);

	wk.info.timestamp  = get_us();
    wk.info.event_code = event_code | (option_val << 16);

    core = 0;
    if (event_log_enable_flag[core] == 1)
    {   
        idx = event_log_idx[core];
        event_log_buff[core][(idx+0)&(EVENT_LOG_NUM-1)].u8_dat = wk.u8_dat;
        event_log_buff[core][(idx+1)&(EVENT_LOG_NUM-1)].u8_dat = 0xFFFFFFFFFFFFULL;
        event_log_idx[core] = idx + 1;
        if (event_log_idx[core] >= EVENT_LOG_NUM){
            //event_log_enable_flag[core]  = 0;
            event_log_enable_flag[core]  = event_log_lap_flag[core];
        }
    }

	pthread_mutex_unlock(&event_log_mutex);
}   

void event_log_fout(const char *filename)
{
	FILE *fp;

	event_log_disable();

	fp = fopen(filename, "wb");
	fwrite(event_log_buff, sizeof(event_log_buff), 1, fp);
	fclose(fp);

	event_log_enable();
}

/* 処理時間計測 */

PROC_TIME proc_time[PROC_PHASE_MAX];
char *proc_name[PROC_PHASE_MAX] = { "RAW", "FFT", "SBICA", "LM", "GHDSS", "OUTE" };

void proc_time_init(void)
{
	int i;

	for(i=0; i<PROC_PHASE_MAX; i++){
		proc_time[i].cnt = 0;
		proc_time[i].min = DBL_MAX;
		proc_time[i].max = DBL_MIN;
		proc_time[i].avg = 0;
		proc_time[i].sta = 0;
	}
}

void proc_time_sta(PROC_PHASE phase)
{
	proc_time[phase].sta = get_us_double();
}

void proc_time_end(PROC_PHASE phase)
{
	double elapse;

	elapse = get_us_double() - proc_time[phase].sta;

	if (elapse < proc_time[phase].min) {
		proc_time[phase].min = elapse;
	}
	if (elapse > proc_time[phase].max) {
		proc_time[phase].max = elapse;
	}
	proc_time[phase].avg = ((proc_time[phase].avg * proc_time[phase].cnt) + elapse) / (proc_time[phase].cnt + 1);
	proc_time[phase].cnt++;
}

void proc_time_show(void)
{
	int i;

	for(i=0; i<PROC_PHASE_MAX; i++){
		printf("proc[%d] %-5s min %11.6lf max %13.6lf avg %11.6lf [us] %u [times]\n", i, proc_name[i], proc_time[i].min, proc_time[i].max, proc_time[i].avg, proc_time[i].cnt);
	}
}

