/*
 * logman.c
 *
 *  Created on: 08-04-2014
 *      Author: Krzysztof Jakubczyk
 */

#include <string.h>
#include <stdlib.h>
/*
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/hal/Timer.h>
*/
#include "mocks.h"

#include "tdefs.h"
#include "logman.h"
#include "misc.h"
// #include "comm.h"

#include "elements.h"
#include "eth.h"
#include "ports/am1808/include/netif/sitaraif.h"

struct logic_manager log_manager;
struct logman_profiler log_profile[MAX_LOG_ELEMENTS];
//u32 debug_size[8];

#pragma LOCATION(log_profile,0xc5400000) // @ non-cached memory above 128MB

void logman_reset()
{
	u32 i;
	memset((void *)&measurands,0,sizeof(measurands));
	memset(&log_manager,0,sizeof(log_manager));
	memset(&log_profile,0,sizeof(log_profile));

	dbg.logman_cycle_time_max=0;
	dbg.logman_cycle_time=0;
	ev_reg_log=NULL;
//	led_blink_states=0;
//	led_states=0;
//	virt_in_states=0;
	virt_in_mask=0;
	virt_in2_mask=0;
	dfr_drv_log_ptr=NULL;
	ddr_drv_log_ptr=NULL;
	dev_ctrl_state=0;
	memset((u8*)force_bus_bin_data,0,sizeof(force_bus_bin_data));
	memset((u8*)force_bus_out_data,0,sizeof(force_bus_out_data));
	memset((u8*)bus_an_samples_neg,0,sizeof(bus_an_samples_neg));
//	memset((u8*)ic->out_set,0,sizeof(ic->out_set));
	for(i=0;i<MAX_REG_BANKS;i++)
		regs.bank[i].state=BANK_EMPTY;

	log_manager.cur_buf_ptr = log_manager.buf;
	log_manager.nets_data[0]&=~0x01; // all unused inputs will be pulled down
	log_manager.nets_data[0]|=0x02;
	logman_notify=0;

	mwd32_mask=0;
	ic->mwd32_present=0;

	emac_hash_clear(EMAC_0_BASE);
}

int logman_pushfunc(u16 fun_id,void *args, u32 args_size)
{
	u32 i=0;
	u32 fun_index=0;
//	u32 dbgg;

	void *argsptr,*logptr;

	if(log_manager.cur_element_num>=MAX_LOG_ELEMENTS)
		return -5;

	while(log_elements[i].id!=EOF_ELEMENT)
	{
		if(log_elements[i].id == fun_id)
			break;
		i++;
	}

	if(log_elements[i].id==EOF_ELEMENT)
		return -1;

	fun_index=i;

	if(log_elements[fun_index].args_size != args_size && ((fun_id != GOOSE_FUN_ID && fun_id != SV_FUN_ID && fun_id != GOOSE_OUT_FUN_ID) || args_size<log_elements[fun_index].args_size) )
		return -2;

	if((log_manager.cur_buf_ptr + args_size) > (log_manager.buf + LOGMAN_BUFSIZE))
		return -3;

	log_manager.log_element[log_manager.cur_element_num].el_num = fun_index;
//	log_manager.log_element[log_manager.cur_element_num].fun_main_ptr = log_elements[fun_index].fun_ptr;
//	log_manager.log_element[log_manager.cur_element_num].fun_100hz_ptr = log_elements[fun_index].fun_100hz_ptr;
//	log_manager.log_element[log_manager.cur_element_num].fun_20hz_ptr = log_elements[fun_index].fun_20hz_ptr;

//	dbgg=(u32)(log_manager.cur_buf_ptr);

	memcpy(log_manager.cur_buf_ptr,args,args_size);
	log_manager.log_element[log_manager.cur_element_num].fun_args_ptr = log_manager.cur_buf_ptr;
	argsptr=log_manager.cur_buf_ptr;
	log_manager.cur_buf_ptr+=args_size;

	if((log_manager.cur_buf_ptr + log_elements[fun_index].log_size) > (log_manager.buf + LOGMAN_BUFSIZE))
		return -4;

	log_manager.log_element[log_manager.cur_element_num].fun_log_ptr = log_manager.cur_buf_ptr;
	logptr=log_manager.cur_buf_ptr;

	log_manager.cur_buf_ptr+=log_elements[fun_index].log_size;

	if(log_elements[fun_index].initlog_ptr)
		if(log_elements[fun_index].initlog_ptr(argsptr,logptr))
			return -6;

	if(fun_id == EVENTS_REG_FUN_ID)
	{
		struct events_reg_logic *evreg_l = (struct events_reg_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&evreg_l->element_num[evreg_l->events_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[0]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == OUT_DRV_FUN_ID)
	{
		struct out_drv_logic *out_drv_l = (struct out_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&out_drv_l->element_num[out_drv_l->out_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[1]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == DFR_DRV_FUN_ID)
	{
		struct dfr_drv_logic *dfr_l = (struct dfr_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&dfr_l->element_num[dfr_l->an_count+dfr_l->bin_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[2]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == DDR_DRV_FUN_ID)
	{
		struct ddr_drv_logic *ddr_l = (struct ddr_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&ddr_l->element_num[ddr_l->an_count+ddr_l->bin_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[3]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == LEDS_DRV_FUN_ID)
	{
		struct leds_drv_logic *leds_l = (struct leds_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&leds_l->element_num[leds_l->leds_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[4]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == VIRT_IN_DRV_FUN_ID)
	{
		struct virt_in_drv_logic *virt_l = (struct virt_in_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&virt_l->element_num[virt_l->virt_in_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[5]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == GOOSE_DRV_FUN_ID)
	{
		struct goose_drv_logic *g = (struct goose_drv_logic *)logptr;
		log_manager.cur_buf_ptr=(u8*)&g->element_num[g->gooses_count+1];
		log_manager.cur_buf_ptr+=(u32)(log_manager.cur_buf_ptr)%4;
	//	debug_size[6]=(u32)(log_manager.cur_buf_ptr)-dbgg;
	}
	else if(fun_id == AN_GEN_FUN_ID)
	{
	//	struct an_gen_logic *an_gen_l = (struct an_gen_logic *)logptr;
	//	log_manager.cur_buf_ptr=(u8*)&an_gen_l->element_num[an_gen_l->an_count+1];
	}

	log_manager.log_element[log_manager.cur_element_num].flags = FUNCTION_ENABLED;

	if(fun_id == EVENT_FUN_ID)
	{
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_EVENT;
		log_manager.status|=LOGMAN_USING_EVENTS;
	}
	else if(fun_id == REC_AN_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_REC_AN;
	else if(fun_id == REC_BUF_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_REC_BUF;
	else if(fun_id == REC_FLOAT_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_REC_FLOAT;
	else if(fun_id == REC_BIN_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_REC_BIN;
	else if(fun_id == REL_OUT_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_REL_OUT;
	else if(fun_id == SV_FUN_ID)
		log_manager.status|= LOGMAN_USING_IEC_SV;
	else if(fun_id == GOOSE_FUN_ID)
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_GOOSE;
	else if(fun_id == DFR_FUN_ID)
	{
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_DFR;
		log_manager.status|=LOGMAN_USING_DFR;
	}
	else if(fun_id == DDR_FUN_ID)
	{
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_DDR;
		log_manager.status|=LOGMAN_USING_DDR;
	}
	else if(fun_id == LED_FUN_ID || fun_id == BUZZER_FUN_ID)
	{
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_LED;
		log_manager.status|=LOGMAN_USING_LEDS;
	}
	else if(fun_id == VIRT_IN_FUN_ID)
	{
		log_manager.log_element[log_manager.cur_element_num].flags |= FUNCTION_IS_VIRT_IN;
		log_manager.status|=LOGMAN_USING_VIRT_IN;
	}

	log_manager.cur_element_num++;

	dbg.logman_buf_size_cur = log_manager.cur_buf_ptr - log_manager.buf;

	log_manager.status|=LOGMAN_USING_AN_GEN;

	return 0;
}

void logman_stop()
{
	log_manager.requests|=LOGMAN_REQUEST_STOP;
	while(log_manager.status & LOGMAN_STATUS_STARTED)
    	Task_sleep(1);
}

int logman_start()
{
	int ret;

	log_manager.soft_start_cnt=0;

	ret=logman_pushfunc(OUT_DRV_FUN_ID,NULL,0);
	if(ret)
		return -7;

	if(log_manager.status & LOGMAN_USING_EVENTS)
	{
		ret=logman_pushfunc(EVENTS_REG_FUN_ID,NULL,0);
		if(ret)
			return -1;
		log_manager.status&=~LOGMAN_USING_EVENTS;
	}
	if(log_manager.status & LOGMAN_USING_LEDS)
	{
		ret=logman_pushfunc(LEDS_DRV_FUN_ID,NULL,0);
		if(ret)
			return -2;
		log_manager.status&=~LOGMAN_USING_LEDS;
	}
	if(log_manager.status & LOGMAN_USING_VIRT_IN)
	{
		ret=logman_pushfunc(VIRT_IN_DRV_FUN_ID,NULL,0);
		if(ret)
			return -3;
		log_manager.status&=~LOGMAN_USING_VIRT_IN;
	}
	if(log_manager.status & LOGMAN_USING_DFR)
	{
		ret=logman_pushfunc(DFR_DRV_FUN_ID,NULL,0);
		if(ret)
			return -4;
		log_manager.status&=~LOGMAN_USING_DFR;
	}
	if(log_manager.status & LOGMAN_USING_DDR)
	{
		ret=logman_pushfunc(DDR_DRV_FUN_ID,NULL,0);
		if(ret)
			return -5;
		log_manager.status&=~LOGMAN_USING_DDR;
	}

	if(log_manager.status & LOGMAN_USING_AN_GEN)
	{
		ret=logman_pushfunc(AN_GEN_FUN_ID,NULL,0);
		if(ret)
			return -6;
		log_manager.status&=~LOGMAN_USING_AN_GEN;
	}

	log_manager.requests|=LOGMAN_REQUEST_START;
	while(!(log_manager.status & LOGMAN_STATUS_STARTED))
    	Task_sleep(1);

	return 0;
}

void logman_init()
{
	logman_reset();
}

void logman_xkhz()
{
	u32 i;
	u32 t_pre,t_post,t;

	if(log_manager.status & LOGMAN_STATUS_SOFT_STARTED && !(dev_ctrl_state & DEV_CTRL_STATE_TEST_OUT))
		memcpy((void*)bus_out_data,(void*)ic->out_set,MAX_OUT_CARDS);

	memcpy((void*)bus_bin_data,(void*)ic->bin_in,MAX_BIN_CARDS);
	memcpy((void*)bus_bin_data_ench,(void*)ic->bin_in_ench,MAX_BIN_CARDS);
	if(dev_ctrl_state & DEV_CTRL_STATE_TEST_IN)
	{
		for(i=0;i<MAX_BIN_CARDS;i++)
		{
			bus_bin_data[i]^=force_bus_bin_data[i];
			bus_bin_data_ench[i]^=force_bus_bin_data_ench[i];
		}
	}

	if(log_manager.requests & LOGMAN_REQUEST_STOP)
	{
		log_manager.status&=~LOGMAN_STATUS_STARTED;
		log_manager.requests&=~LOGMAN_REQUEST_STOP;
	}

	if(log_manager.requests & LOGMAN_REQUEST_START)
	{
		log_manager.status|=LOGMAN_STATUS_STARTED;
		log_manager.requests&=~LOGMAN_REQUEST_START;
	}

	if(log_manager.status & LOGMAN_STATUS_STARTED)
	{
		//logman_notify=0;

		if(log_manager.soft_start_cnt<LOGMAN_SOFT_START_TIME)
			log_manager.soft_start_cnt++;
		else
		{
			if(!(log_manager.status & LOGMAN_STATUS_SOFT_STARTED))
				log_manager.status|=LOGMAN_STATUS_SOFT_STARTED;
		}
		if(!(log_manager.status & LOGMAN_STATUS_PROFILING))
		{
			for(i=0;i<MAX_LOG_ELEMENTS;i++)
			{
				if((log_manager.log_element[i].flags & FUNCTION_ENABLED) && log_elements[log_manager.log_element[i].el_num].fun_main_ptr)
					log_elements[log_manager.log_element[i].el_num].fun_main_ptr(log_manager.log_element[i].fun_args_ptr,log_manager.log_element[i].fun_log_ptr);
				else if(log_manager.log_element[i].flags == FUNCTION_NOT_INITIALIZED)
				{
					dbg.used_elements=i;
					break;
				}
			}
		}
		else // profiling
		{
			for(i=0;i<MAX_LOG_ELEMENTS;i++)
			{
				if((log_manager.log_element[i].flags & FUNCTION_ENABLED) && log_elements[log_manager.log_element[i].el_num].fun_main_ptr)
				{
					t_pre=PWM1_GET(PWM1_TBCNT);
					log_elements[log_manager.log_element[i].el_num].fun_main_ptr(log_manager.log_element[i].fun_args_ptr,log_manager.log_element[i].fun_log_ptr);
					t_post=PWM1_GET(PWM1_TBCNT);
					if(t_post>=t_pre)
						t = t_post-t_pre;
					else
						t = t_post+65536-t_pre;

					log_profile[i].t_cur=t;

					if(t>log_profile[i].t_max)
						log_profile[i].t_max=t;
				}
				else if(log_manager.log_element[i].flags == FUNCTION_NOT_INITIALIZED)
					break;
			}
		}

		if(logman_notify)
			Swi_post(swi_notify);
	}

	if(log_manager.status & LOGMAN_STATUS_SOFT_STARTED)
	{
		if(dev_ctrl_state & DEV_CTRL_STATE_TEST_OUT)
		{
			for(i=0;i<MAX_OUT_CARDS;i++)
				bus_out_data_test[i]=force_bus_out_data[i]^bus_out_data[i];

			if(!(dev_ctrl_state & DEV_CTRL_STATE_BLOCK_OUT))
				memcpy((void*)ic->out_set,(void*)bus_out_data_test,MAX_OUT_CARDS*2);
		}
		else
		{
			if(!(dev_ctrl_state & DEV_CTRL_STATE_BLOCK_OUT))
				memcpy((void*)ic->out_set,(void*)bus_out_data,MAX_OUT_CARDS*2);
		}
	}

}

void logman_100hz()
{
	u32 i;

	if(log_manager.status & LOGMAN_STATUS_STARTED)
	{
		for(i=0;i<MAX_LOG_ELEMENTS;i++)
		{
			if((log_manager.log_element[i].flags & FUNCTION_ENABLED) && log_elements[log_manager.log_element[i].el_num].fun_100hz_ptr)
				log_elements[log_manager.log_element[i].el_num].fun_100hz_ptr(log_manager.log_element[i].fun_args_ptr,log_manager.log_element[i].fun_log_ptr);
			else if(log_manager.log_element[i].flags == FUNCTION_NOT_INITIALIZED)
				break;
		}

	}
}

void logman_20hz()
{
	u32 i;

	if(log_manager.status & LOGMAN_STATUS_STARTED)
	{
		for(i=0;i<MAX_LOG_ELEMENTS;i++)
		{
			if((log_manager.log_element[i].flags & FUNCTION_ENABLED) && log_elements[log_manager.log_element[i].el_num].fun_20hz_ptr)
				log_elements[log_manager.log_element[i].el_num].fun_20hz_ptr(log_manager.log_element[i].fun_args_ptr,log_manager.log_element[i].fun_log_ptr);
			else if(log_manager.log_element[i].flags == FUNCTION_NOT_INITIALIZED)
				break;
		}
	}
}
