/*
 * ddr.c
 *
 *  Created on: 26-05-2014
 *      Author: KJ
 */


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

#include <ti/ipc/Notify.h>
#include <string.h>
#include "ddr.h"
#include "ddr_drv.h"
#include "rec_an.h"
#include "rec_bin.h"
#include "comm.h"
#include "misc.h"
#include "config.h"

#pragma LOCATION(ddr_bank0,0xc4000000) // @ non-cached memory above 128MB
volatile u8 ddr_bank0[DDR_REG_BANK_SIZE];
#pragma LOCATION(ddr_bank1,0xc4100000) // @ non-cached memory above 128MB
volatile u8 ddr_bank1[DDR_REG_BANK_SIZE];
#pragma LOCATION(ddr_bank2,0xc4200000) // @ non-cached memory above 128MB
volatile u8 ddr_bank2[DDR_REG_BANK_SIZE];
#pragma LOCATION(ddr_bank3,0xc4300000) // @ non-cached memory above 128MB
volatile u8 ddr_bank3[DDR_REG_BANK_SIZE];

volatile struct ddr_reg_inf ddr_regs = {	.cur_reg_bank = 0,
									.bank[0].data = (void*) ddr_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*) ddr_bank1,
									.bank[2].data = (void*) ddr_bank2,
									.bank[3].data = (void*) ddr_bank3,
								};

int ddr_initlog(void *arguments, void *logic)
{
	struct ddr_args *args = (struct ddr_args *)arguments;
	struct ddr_logic *log = (struct ddr_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;

	switch((enum ddr_fs)args->params.f_sampling)
	{
		case Fs_100Hz:
			log->decimation=10/LOOP_CYCLE_MS;
			break;
		case Fs_50Hz:
			log->decimation=20/LOOP_CYCLE_MS;
			break;
		case Fs_10Hz:
			log->decimation=100/LOOP_CYCLE_MS;
			break;
		case Fs_5Hz:
			log->decimation=200/LOOP_CYCLE_MS;
			break;
		case Fs_1Hz:
			log->decimation=1000/LOOP_CYCLE_MS;
			break;
		case Fs_0_5Hz:
			log->decimation=2000/LOOP_CYCLE_MS;
			break;
		case Fs_0_1Hz:
			log->decimation=10000/LOOP_CYCLE_MS;
			break;
		default:
			log->decimation=10/LOOP_CYCLE_MS;
			break;
	}

	log->pre_trigger_samples = args->params.pre_trigger_time / log->decimation;
	if(args->params.pre_trigger_time)
		log->pre_trigger_samples++;

	log->post_trigger_samples = args->params.post_trigger_time / log->decimation;
	if(args->params.post_trigger_time)
		log->post_trigger_samples++;

	log->max_reg_samples = args->params.max_reg_time / log->decimation;
	if(args->params.max_reg_time)
		log->max_reg_samples++;

	return 0;
}

void ddr(void *arguments, void *logic)
{
	struct ddr_logic *log = (struct ddr_logic *)logic;
	//struct ddr_args *args = (struct ddr_args *)arguments;
	struct rec_an_logic *an_log;
	struct rec_bin_logic *bin_log;
	u16 sample_buf[(MAX_SAMPLE_SIZE/sizeof(u16)) + 8];
	int i,bit_cnt=0,pos=0;
	u8 new_sample=0;

	if(ddr_drv_log_ptr == NULL) // ddr driver not initialized?
		return;

	if(!log->decimation_cnt--)
	{
		log->decimation_cnt=log->decimation;
		new_sample=1;
	}

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

		case BANK_TRIGGERED:
			if(new_sample)
			{
				if(ddr_regs.bank[ddr_regs.cur_reg_bank].total_cnt++>=log->max_reg_samples || ddr_regs.bank[ddr_regs.cur_reg_bank].post_trigger_cnt>=log->post_trigger_samples)
				{
					// send notify to ARM
					ddr_regs.bank[ddr_regs.cur_reg_bank].state=BANK_FILLED;
					ddr_regs.bank[ddr_regs.cur_reg_bank].decimation=log->decimation;
					ddr_regs.cur_reg_bank++;
					ddr_regs.cur_reg_bank%=DDR_MAX_REG_BANKS;
					ddr_regs.bank[ddr_regs.cur_reg_bank].state=BANK_BUFFERING;
					ddr_regs.bank[ddr_regs.cur_reg_bank].addr_offset=0;
					ddr_regs.bank[ddr_regs.cur_reg_bank].post_trigger_cnt=0;
					ddr_regs.bank[ddr_regs.cur_reg_bank].pre_trigger_cnt=0;
					ddr_regs.bank[ddr_regs.cur_reg_bank].trigger_offset=0;
					ddr_regs.bank[ddr_regs.cur_reg_bank].total_cnt=0;
					logman_notify|=LOGMAN_NOTIFY_NEW_DDR;
//					Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_NEW_DDR_REG, TRUE);
				}
				else
				{
					if(*log->trigger_ptr & (1<<log->trigger_bit_no))
						ddr_regs.bank[ddr_regs.cur_reg_bank].post_trigger_cnt=0;
					else
						ddr_regs.bank[ddr_regs.cur_reg_bank].post_trigger_cnt++;
				}
			}
			break;

		case BANK_EMPTY:
		case BANK_FILLED:
		default:
			ddr_regs.bank[ddr_regs.cur_reg_bank].state=BANK_BUFFERING;
			ddr_regs.bank[ddr_regs.cur_reg_bank].addr_offset=0;
			ddr_regs.bank[ddr_regs.cur_reg_bank].post_trigger_cnt=0;
			ddr_regs.bank[ddr_regs.cur_reg_bank].pre_trigger_cnt=0;
			ddr_regs.bank[ddr_regs.cur_reg_bank].trigger_offset=0;
			ddr_regs.bank[ddr_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
//
	if(new_sample)
	{

		pos = 4;

		for(i=0;i<ddr_drv_log_ptr->an_count;i++)
		{
			an_log = (struct rec_an_logic *)log_manager.log_element[ddr_drv_log_ptr->element_num[i] & 0x3FFF].fun_log_ptr;
			sample_buf[pos]=*an_log->in_ptr;
			pos++;
		}

		sample_buf[pos]=0;

		for(;i<(ddr_drv_log_ptr->an_count+ddr_drv_log_ptr->bin_count);i++)
		{
			bin_log = (struct rec_bin_logic *)log_manager.log_element[ddr_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(ddr_regs.bank[ddr_regs.cur_reg_bank].addr_offset + ddr_drv_log_ptr->sample_size > DDR_REG_BANK_SIZE)
			ddr_regs.bank[ddr_regs.cur_reg_bank].addr_offset=0;

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