/*
 * dfr.c
 *
 *  Created on: 24-06-2014
 *      Author: KJ
 */


#include "tdefs.h"
#include "misc.h"

#include <ti/ipc/Notify.h>
#include <string.h>
#include "dfr.h"
#include "dfr_drv.h"
#include "rec_an.h"
#include "rec_buf.h"
#include "rec_bin.h"
#include "comm.h"
#include "misc.h"
#include "config.h"

#pragma LOCATION(bank0,0xc4400000) // @ non-cached memory above 128MB
volatile u8 bank0[REG_BANK_SIZE];
#pragma LOCATION(bank1,0xc4800000) // @ non-cached memory above 128MB
volatile u8 bank1[REG_BANK_SIZE];
#pragma LOCATION(bank2,0xc4c00000) // @ non-cached memory above 128MB
volatile u8 bank2[REG_BANK_SIZE];
#pragma LOCATION(bank3,0xc5000000) // @ non-cached memory above 128MB
volatile u8 bank3[REG_BANK_SIZE];

volatile struct reg_inf regs = {	.cur_reg_bank = 0,
									.bank[0].data = (void*) bank0,
									.bank[0].state = BANK_BUFFERING,
									.bank[0].addr_offset = 0,
									.bank[0].pre_trigger_cnt = 0,
									.bank[0].post_trigger_cnt = 0,
									.bank[0].total_cnt = 0,
									.bank[1].data = (void*) bank1,
									.bank[2].data = (void*) bank2,
									.bank[3].data = (void*) bank3,
								};

int dfr_initlog(void *arguments, void *logic)
{
	struct dfr_args *args = (struct dfr_args *)arguments;
	struct dfr_logic *log = (struct dfr_logic *)logic;

	log->trigger_ptr = log_manager.nets_data + (args->io.trigger_in >> 3);
	log->trigger_bit_no = args->io.trigger_in & 0x07;
	if(log->trigger_ptr >= (log_manager.nets_data+sizeof(log_manager.nets_data)))
		return -1;

	return 0;
}

void dfr(void *arguments, void *logic)
{
	struct dfr_logic *log = (struct dfr_logic *)logic;
	struct dfr_args *args = (struct dfr_args *)arguments;
	struct rec_an_logic *an_log;
	struct rec_buf_logic *an_buf_log;
	struct rec_bin_logic *bin_log;
	u16 sample_buf[(MAX_SAMPLE_SIZE/sizeof(u16)) + 8];
	int i,bit_cnt=0,pos=0;
	int sdiff;
	u32 prev_offset;
	short *sample_buf_prev;

	if(dfr_drv_log_ptr == NULL) // dfr driver not initialized?
		return;

	sdiff=cur_sample_diff;

	while(sdiff)
	{
		switch(regs.bank[regs.cur_reg_bank].state)
		{
			case BANK_BUFFERING:
				if(*log->trigger_ptr & (1<<log->trigger_bit_no))
				{
					regs.bank[regs.cur_reg_bank].state=BANK_TRIGGERED;
					regs.bank[regs.cur_reg_bank].tr_time=(timesync_bits & CFG_TSYNC_USE_SWCLK)?cur_time_sw.tv_sec:cur_time.tv_sec;
					regs.bank[regs.cur_reg_bank].tr_time_ms=(timesync_bits & CFG_TSYNC_USE_SWCLK)?cur_time_sw.tv_usec:cur_time.tv_usec;
					regs.bank[regs.cur_reg_bank].sample_size=dfr_drv_log_ptr->sample_size;
					regs.bank[regs.cur_reg_bank].an_count=dfr_drv_log_ptr->an_count;
					regs.bank[regs.cur_reg_bank].bin_count=dfr_drv_log_ptr->bin_count;
					regs.bank[regs.cur_reg_bank].post_trigger_cnt=0;
					regs.bank[regs.cur_reg_bank].trigger_offset=regs.bank[regs.cur_reg_bank].addr_offset;
					regs.bank[regs.cur_reg_bank].total_cnt=regs.bank[regs.cur_reg_bank].pre_trigger_cnt;
				}
				else
				{
					if(regs.bank[regs.cur_reg_bank].pre_trigger_cnt<args->params.pre_trigger_time)
						regs.bank[regs.cur_reg_bank].pre_trigger_cnt++;
				}
				break;

			case BANK_TRIGGERED:
				if(regs.bank[regs.cur_reg_bank].total_cnt++>=args->params.max_reg_time || regs.bank[regs.cur_reg_bank].post_trigger_cnt>=args->params.post_trigger_time)
				{
					// send notify to ARM
					regs.bank[regs.cur_reg_bank].state=BANK_FILLED;
					regs.cur_reg_bank++;
					regs.cur_reg_bank%=MAX_REG_BANKS;
					regs.bank[regs.cur_reg_bank].state=BANK_BUFFERING;
					regs.bank[regs.cur_reg_bank].addr_offset=0;
					regs.bank[regs.cur_reg_bank].post_trigger_cnt=0;
					regs.bank[regs.cur_reg_bank].pre_trigger_cnt=0;
					regs.bank[regs.cur_reg_bank].trigger_offset=0;
					regs.bank[regs.cur_reg_bank].total_cnt=0;
					logman_notify|=LOGMAN_NOTIFY_NEW_DFR;
	//				Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_NEW_DFR_REG, TRUE);
				}
				else
				{
					if(*log->trigger_ptr & (1<<log->trigger_bit_no))
						regs.bank[regs.cur_reg_bank].post_trigger_cnt=0;
					else
						regs.bank[regs.cur_reg_bank].post_trigger_cnt++;
				}
				break;

			case BANK_EMPTY:
			case BANK_FILLED:
			default:
				regs.bank[regs.cur_reg_bank].state=BANK_BUFFERING;
				regs.bank[regs.cur_reg_bank].addr_offset=0;
				regs.bank[regs.cur_reg_bank].post_trigger_cnt=0;
				regs.bank[regs.cur_reg_bank].pre_trigger_cnt=0;
				regs.bank[regs.cur_reg_bank].trigger_offset=0;
				regs.bank[regs.cur_reg_bank].total_cnt=0;
				break;
		}



	//
	//  will be overwritten by ARM
	//	*((u32 *)&sample_buf[0]) = 0; // sample number 1..n
	//	*((u32 *)&sample_buf[2]) = 0; // time stamp 0..n*1ms @ 1 kHz
	//

		pos = 4;


		for(i=0;i<dfr_drv_log_ptr->an_count;i++)
		{
			if(regs.bank[regs.cur_reg_bank].addr_offset >= (dfr_drv_log_ptr->sample_size))
				prev_offset = regs.bank[regs.cur_reg_bank].addr_offset - (dfr_drv_log_ptr->sample_size);
			else
				prev_offset = dfr_drv_log_ptr->max_offset - (dfr_drv_log_ptr->sample_size);

			sample_buf_prev = (short*)((u8*)regs.bank[regs.cur_reg_bank].data+prev_offset+(pos<<1));

			if(dfr_drv_log_ptr->element_num[i] & ELEMENT_IS_REC_BUF)
			{
				an_buf_log = (struct rec_buf_logic *)log_manager.log_element[dfr_drv_log_ptr->element_num[i] & 0x3FFF].fun_log_ptr;

				sample_buf[pos]=(short)an_buf_log->buf_ptr[bus_an_cur_sample_num]-0x7FFF;

				if(sdiff>SAMPLES_PER_MS)
				{
					int snum;
					snum = bus_an_cur_sample_num;
					snum-= (sdiff-SAMPLES_PER_MS);
					if(snum<0)
						snum+=(SAMPLES_PER_MS*2*MAIN_FREQ_PERIOD_MS);
					*sample_buf_prev=(short)an_buf_log->buf_ptr[snum]-0x7FFF;
				}
			}
			else
			{
				an_log = (struct rec_an_logic *)log_manager.log_element[dfr_drv_log_ptr->element_num[i] & 0x3FFF].fun_log_ptr;
				sample_buf[pos]=*an_log->in_ptr;

				if(sdiff>SAMPLES_PER_MS)//first sample interpolation
				{
#if SAMPLES_INTERPOLATION==1
					*sample_buf_prev=((short)*an_log->in_ptr+*sample_buf_prev)>>1;
#elif SAMPLES_INTERPOLATION==2
					*sample_buf_prev=32768;
#else
					*sample_buf_prev=sample_buf[pos]; // only phase shift
#endif
				}

			}
			pos++;
		}

		sample_buf[pos]=0;
		bit_cnt=0;

		for(;i<(dfr_drv_log_ptr->an_count+dfr_drv_log_ptr->bin_count);i++)
		{
			bin_log = (struct rec_bin_logic *)log_manager.log_element[dfr_drv_log_ptr->element_num[i] & 0x3FFF].fun_log_ptr;

			if(*bin_log->in_ptr & bin_log->in_bit_mask)
				sample_buf[pos]|=(1<<(bit_cnt%16));

			if(!(++bit_cnt%16) && bit_cnt)
			{
				pos++;
				sample_buf[pos]=0;
			}
		}

		if(regs.bank[regs.cur_reg_bank].addr_offset + dfr_drv_log_ptr->sample_size > REG_BANK_SIZE)
			regs.bank[regs.cur_reg_bank].addr_offset=0;

		memcpy((u8*)regs.bank[regs.cur_reg_bank].data+regs.bank[regs.cur_reg_bank].addr_offset,(void *)sample_buf,dfr_drv_log_ptr->sample_size);
		regs.bank[regs.cur_reg_bank].addr_offset+=dfr_drv_log_ptr->sample_size;

		sdiff-=SAMPLES_PER_MS;
		if(sdiff<0)
			sdiff=0;
	}
}
