/*
 * main.c
 *
 *  Created on: 01-06-2013
 *      Author: Krzysztof Jakubczyk
 */

#include <xdc/std.h>

#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/hal/Hwi.h>
#include <ti/sysbios/knl/Swi.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/hal/Timer.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/ipc/Notify.h>
#include <string.h>

#include "misc.h"
#include "comm.h"
#include "tdefs.h"
#include "logman.h"
#include "spi.h"
#include "logic_elements/dev_ctrl.h"
#include "logic_elements/an_gen.h"
#include "logic_elements/events_reg.h"
//pwm
#include "psc.h"
#include "soc_OMAPL138.h"
#include "hw_syscfg0_OMAPL138.h"
#include "hw_types.h"
//
/// ethernet
#include "ethernet/ports/am1808/include/lwiplib.h"
///
#include "config.h"

volatile unsigned short last_sample_no;
volatile unsigned short samples_dropped = 0;
volatile unsigned short last_sample_sync_no;
volatile unsigned short samples_sync_dropped = 0;
volatile int is_first_sample = 1;
volatile int irqs = 0;
u16 bus_an_cur_timestamp = 0;

#pragma LOCATION(shared_buf,0xc5500000) // @ non-cached memory above 128MB
volatile int shared_buf[1024];

#pragma DATA_ALIGN(analog_buf, 128) // place @ cache line boundary
volatile short analog_buf[127];

//volatile int analog_buf_ready = 0;
//volatile int analog_buf_cnt = 0;
unsigned int analog_buf_card = 0;
unsigned int analog_buf_channel = 0;

struct device_config dev_cfg;

u8 mwd_states_cur[MAX_BIN_CARDS];
u8 mwd_states_prev[MAX_BIN_CARDS];

Swi_Handle swi_notify;
Swi_Params swi_notify_params;

Swi_Handle swi_ms;
Swi_Params swi_ms_params;

Swi_Handle swi_10ms;
Swi_Params swi_10ms_params;

Swi_Handle swi_50ms;
Swi_Params swi_50ms_params;

extern Timer_Handle timer0;

u8 loops_synced=0;

u8 khz_trigger=LOOP_CYCLE_MS * SAMPLES_PER_MS;

volatile u32 cycle_pwm=0;
volatile struct timeval cur_time = { 1388563200, 0 }; // default 2014-01-01
volatile struct timeval cur_time_sw = { 1577836800, 0 }; // default 2020-01-01
u8 bus_an_cur_sample_num_prev=0;
u8 sample_watch_init=0;
u8 cur_sample_diff=0;

void pwm_init()
{
    PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_EHRPWM, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
	PWM1_SET(PWM1_TBCTL, 0x8D03); //FREE RUN, CLKDIV /8, HSPCLKDIV /4, STOP
	PWM1_SET(PWM1_TBPRD, 0xFFFF);
	PWM1_SET(PWM1_TBCNT, 0x0000);
	HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_CFGCHIP1) |= SYSCFG_CFGCHIP1_TBCLKSYNC;
}

void pwm_start_cnt()
{
	PWM1_SET(PWM1_TBCNT, 0x0000); //COUNTER = 0
	PWM1_SET(PWM1_TBCTL, 0x8D00); //START
}

u32 pwm_stop_cnt()
{
	PWM1_SET(PWM1_TBCTL, 0x8D03);//STOP
	return PWM1_GET(PWM1_TBCNT);
}

Void notify_swi(UArg a0, UArg a1)
{
	u32 requests = logman_notify;

	if(requests & LOGMAN_NOTIFY_NEW_EVENTS)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_NEW_EVENTS | ((u32)ev_db.pos<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_NEW_EVENTS;
	}

	if(requests & LOGMAN_NOTIFY_NEW_DFR)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_NEW_DFR_REG, TRUE);
		logman_notify&=~LOGMAN_NOTIFY_NEW_DFR;
	}

	if(requests & LOGMAN_NOTIFY_NEW_DDR)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_NEW_DDR_REG, TRUE);
		logman_notify&=~LOGMAN_NOTIFY_NEW_DDR;
	}

	if(requests & LOGMAN_NOTIFY_BANK0)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK0|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK0;
	}

	if(requests & LOGMAN_NOTIFY_BANK1)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK1|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK1;
	}

	if(requests & LOGMAN_NOTIFY_BANK2)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK2|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK2;
	}

	if(requests & LOGMAN_NOTIFY_BANK3)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK3|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK3;
	}

	if(requests & LOGMAN_NOTIFY_BANK4)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK4|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK4;
	}

	if(requests & LOGMAN_NOTIFY_BANK5)
	{
		Notify_sendEvent(notify.remoteProcId,notify.lineId,notify.eventId, NOTIFY_SEL_BANK5|(service_mode<<8), TRUE);
		logman_notify&=~LOGMAN_NOTIFY_BANK5;
	}

}

volatile u16 pps_low_cnt=0;
volatile u16 pps3_timeout_cnt=0xFFFF;

Void ms_hook(UArg a0, UArg a1)
{
	u32 t_pre,t_post,sync_reg;
	u8 pps=0;

	t_pre=PWM1_GET(PWM1_TBCNT);

	bus_an_cur_sample_num=bus_an_cur_sample_num_xkhz;//bus_an_cur_sample_num_3khz;

	// gdy IEC SV to cofamy czas/pozycje bufora o obiegi pętli w celu synchronizacji próbek
  	if(log_manager.status & LOGMAN_USING_IEC_SV)
	{
		if(bus_an_cur_sample_num<(SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES))
			bus_an_cur_sample_num=SAMPLES_PER_MS*MAIN_FREQ_PERIOD_MS*2-((SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES)-bus_an_cur_sample_num);
		else
			bus_an_cur_sample_num-=(SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES);
	}

	sync_reg = ic->sync_reg;
	if(sync_reg & (PPS_SYNCED|IRIGB_SYNCED))
		ext_sync=1;


	if(timesync_method==SYNC_METHOD_IEC103||timesync_method==SYNC_METHOD_ZP6||timesync_method==SYNC_METHOD_MLB || (timesync_method==SYNC_METHOD_CUSTOM & !(timesync_bits & CFG_TSYNC_USE_PPS)))
		ext_sync=0;

	bus_an_cur_timestamp=tstamp_khz;
  	if(log_manager.status & LOGMAN_USING_IEC_SV)
  	{
		if(bus_an_cur_timestamp<(SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES))
			bus_an_cur_timestamp=SAMPLES_PER_MS*1000-((SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES)-bus_an_cur_timestamp);
		else
			bus_an_cur_timestamp-=(SAMPLES_PER_MS*LOOP_CYCLE_MS*SV_WAIT_LOOP_CYCLES);
  	}

	if(!ext_sync)
	{
		cur_time.tv_usec+=LOOP_CYCLE_MS;

		if(cur_time.tv_usec>=1000)
		{
			cur_time.tv_usec=0;
			cur_time.tv_sec++;
		}
	}
	else
	{
		u32 usec_prev;
		usec_prev=cur_time.tv_usec;
		cur_time.tv_usec=bus_an_cur_timestamp/SAMPLES_PER_MS;
	  	if(!cur_time.tv_usec && usec_prev)
			cur_time.tv_sec++;

	}

	if(pps3_timeout_cnt!=0xFFFF)
		pps3_timeout_cnt++;

	if(!(IN_DATA01 & (1<<4)))
	{
		if(pps_low_cnt<(1000/LOOP_CYCLE_MS))
			pps_low_cnt++;
	}
	else
	{
		if(pps_low_cnt>(600/LOOP_CYCLE_MS) && pps_low_cnt<(900/LOOP_CYCLE_MS))
		{
			pps=1;
			pps3_timeout_cnt=0;
		}

		pps_low_cnt=0;
	}

	if(((sync_reg & 0x80) && (timesync_method==SYNC_METHOD_IRIG_B || timesync_method==SYNC_METHOD_IRIG_B_ZPRAE || (timesync_method==SYNC_METHOD_CUSTOM && (timesync_bits & CFG_TSYNC_FROM_DSP))))
		|| (pps && (timesync_method==SYNC_METHOD_CUSTOM && (timesync_bits & CFG_TSYNC_USE_SWPPS)))
	)
	{
		if(cur_time_sw.tv_usec>900)
			cur_time_sw.tv_sec++;

		//if(pps)
		//	zprae_event_add(1,97);
		cur_time_sw.tv_usec=0;
	}
	else
	{
		cur_time_sw.tv_usec+=LOOP_CYCLE_MS;

		if(cur_time_sw.tv_usec>=1000)
		{
			cur_time_sw.tv_usec=0;
			cur_time_sw.tv_sec++;
		}
	}


	if(bus_an_cur_sample_num_prev<=bus_an_cur_sample_num)
		cur_sample_diff=bus_an_cur_sample_num-bus_an_cur_sample_num_prev;
	else
		cur_sample_diff=(u16)bus_an_cur_sample_num+(SAMPLES_PER_MS*MAIN_FREQ_PERIOD_MS*2)-bus_an_cur_sample_num_prev;

	if(cur_sample_diff!=(SAMPLES_PER_MS*LOOP_CYCLE_MS) && sample_watch_init) // debug lost x kHz loops
	{
	//	if(cur_sample_diff>dbg.delta_period)
		//	dbg.delta_period=cur_sample_diff;
		dbg.temp_dbg++;
	}

	bus_an_cur_sample_num_prev = bus_an_cur_sample_num;
	sample_watch_init=1;

	logman_xkhz();

	t_post=PWM1_GET(PWM1_TBCNT);

	if(t_post>=t_pre)
		dbg.logman_cycle_time = t_post-t_pre;
	else
		dbg.logman_cycle_time = t_post+65536-t_pre;

	if(dbg.logman_cycle_time>dbg.logman_cycle_time_max)
		dbg.logman_cycle_time_max=dbg.logman_cycle_time;



}

Void ms10_hook(UArg a0, UArg a1)
{
	logman_100hz();
}

Void ms50_hook(UArg a0, UArg a1)
{
	logman_20hz();
}

Void spi_irq(UArg arg)
{
	 Hwi_clearInterrupt(14);
}

UInt IntGlobalDisable()
{
	return Hwi_disable();
}

UInt IntGlobalRestore(UInt hwi_key)
{
	Hwi_restore(hwi_key);
	return 0;
}

u8 spi_frame[32];
u8 spi_processed=1;

Void comm_irq(UArg arg)
{
	int i;
	u32 t_pre,t_post;

	t_pre=PWM1_GET(PWM1_TBCNT);

	bus_an_cur_sample_num_3khz++;
	bus_an_cur_sample_num_3khz%=(SAMPLES_PER_MS*MAIN_FREQ_PERIOD_MS*2);

/* Nie potrzebne przy PPS
	if(!ext_sync && timesync_method!=SYNC_METHOD_IRIG_B && timesync_method!=SYNC_METHOD_IRIG_B_ZPRAE && !(timesync_bits & CFG_TSYNC_FROM_DSP) && ic->spi_reg & 0x01)
	{
		if(ic->spi_frame[7]==0x01 && ic->spi_frame[0]==0x68 && ic->spi_frame[31]==0x16 && ic->spi_frame[1]==0x1a && spi_processed)
		{
			memcpy(spi_frame,(char *)&ic->spi_frame[0],32);
			if(mod256_cksum(spi_frame+4,26)==spi_frame[30] && spi_frame[1]==0x1a && spi_frame[7]==0x01 && spi_frame[9]!=0xD5) // time sync req
			{
				u16 ms;
				ms = (u16)spi_frame[9] | ((u16)spi_frame[10]<<8);
				ms%=1000;

				if(!ext_sync)
					cur_time.tv_usec = ms;

				cur_time_sw.tv_usec = ms;

				//dbg.temp_dbg++;
				spi_processed=0;
			}
		}
	}
	else
		spi_processed=1;
*/

	for(i=0;i<MAX_AN_CARDS/2;i++)
	{
		if((dev_ctrl_state & DEV_CTRL_STATE_TEST_AN) && an_gen_buf_ready && (i<MAX_AN_CARDS/2))
		{
			if(!(genpar.an_force_mask & (1<< ((i<<2)+(0)))))
				bus_an_samples_buf[i][0][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][0]?(65534-((u16)ic->an_in[i].l1 + 32767)):((u16)ic->an_in[i].l1 + 32767);

			if(!(genpar.an_force_mask & (1<< ((i<<2)+(1)))))
				bus_an_samples_buf[i][1][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][1]?(65534-((u16)ic->an_in[i].l2 + 32767)):((u16)ic->an_in[i].l2 + 32767);

			if(!(genpar.an_force_mask & (1<< ((i<<2)+(2)))))
				bus_an_samples_buf[i][2][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][2]?(65534-((u16)ic->an_in[i].l3 + 32767)):((u16)ic->an_in[i].l3 + 32767);

			if(!(genpar.an_force_mask & (1<< ((i<<2)+(3)))))
				bus_an_samples_buf[i][3][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][3]?(65534-((u16)ic->an_in[i].l4 + 32767)):((u16)ic->an_in[i].l4 + 32767);

		}
		else
		{
			bus_an_samples_buf[i][0][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][0]?(65534-((u16)ic->an_in[i].l1 + 32767)):((u16)ic->an_in[i].l1 + 32767);
			bus_an_samples_buf[i][1][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][1]?(65534-((u16)ic->an_in[i].l2 + 32767)):((u16)ic->an_in[i].l2 + 32767);
			bus_an_samples_buf[i][2][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][2]?(65534-((u16)ic->an_in[i].l3 + 32767)):((u16)ic->an_in[i].l3 + 32767);
			bus_an_samples_buf[i][3][bus_an_cur_sample_num_3khz]=bus_an_samples_neg[i][3]?(65534-((u16)ic->an_in[i].l4 + 32767)):((u16)ic->an_in[i].l4 + 32767);
		}
	}


	if(loops_synced)
	{
		if(!--khz_trigger)
		{
			bus_an_cur_sample_num_xkhz=bus_an_cur_sample_num_3khz;
			tstamp_khz=ic->sample_sync_no;
			Swi_post(swi_ms);
			khz_trigger=SAMPLES_PER_MS*LOOP_CYCLE_MS;
		}
		//Swi_dec(swi_1ms);
		Swi_dec(swi_10ms);
		Swi_dec(swi_50ms);
	}

	if(!loops_synced && (ic->sample_sync_no==0))
	{
		loops_synced=1;
		bus_an_cur_sample_num_3khz=0; //dodano przy okazji SV
	}

	//dodano na wszelki wypadek, bo czasem pętle się nie synchronizowały, dlaczego? FPGA?
	//trzeba to sprawdzic bo moze byc skutek uboczny || zakomentowano jednak po poprawie sync na 2ms w fpga
	//if(ic->sample_sync_no==0)
	//	khz_trigger=LOOP_CYCLE_MS * SAMPLES_PER_MS;
	//

	i=ic->sample_no;

	if(is_first_sample)
		is_first_sample=0;
	else
		samples_dropped+=(i - last_sample_no)-1;

	last_sample_no=i;

	t_post=PWM1_GET(PWM1_TBCNT);

	if(t_post>=t_pre)
		dbg.irq_time = t_post-t_pre;
	else
		dbg.irq_time = t_post+65536-t_pre;
}

void configure_pwr_ok_gpio()
{
	KICK0R=KICK0R_VAL;
	KICK1R=KICK1R_VAL;

	PINMUX0=(PINMUX0 & ~(PINMUX3_15_12)) | (0x08 << 12); // pwr1_ok GP0[12] as GPIO
	PINMUX1=(PINMUX1 & ~(PINMUX3_11_8)) | (0x08 << 8); // pwr2_ok GP0[5] as GPIO
	PINMUX1=(PINMUX1 & ~(PINMUX3_15_12)) | (0x08 << 12); // pps3 GP0[4] as GPIO
	PINMUX2=(PINMUX2 & ~(PINMUX3_19_16)) | (0x04 << 16); // gp1[11] (PPS from GPS) as GPIO

	DIR01|=((1<<4)|(1<<5)|(1<<12)|(1<<27)); // gp0.4, gp0.5, gp0.12 and gp1 .11 as input
	PUPD_ENA|=((1<<0)|(1<<2)); // enable pull up/down control 1<<5 == GP1[11]
	PUPD_ENA&=~(1<<5); // disable pull up/down for gp1[11]
	PUPD_SEL|=((1<<0)|(1<<2)); // set pull up
}

/*
** Interrupt Handler for Core 0 Receive interrupt
*/
void EMACCore0RxIsr(void)
{
    lwIPRxIntHandler(0);
}

/*
** Interrupt Handler for Core 0 Transmit interrupt
*/
void EMACCore0TxIsr(void)
{
    lwIPTxIntHandler(0);
}

Void main()
{ 
    Task_Handle task,task2;

    memset((u8*)&dbg,0,sizeof(dbg));
    ic->sync_reg|=NEG_PPS_IN;

    task = Task_create(commFxn, NULL, NULL);
    Task_setPri(task,3);

    if (task == NULL) {
        BIOS_exit(0);
    }

    task2 = Task_create(spiFxn, NULL, NULL);
    Task_setPri(task2,2);

    if (task2 == NULL) {
        BIOS_exit(0);
    }

    analog_inputs_init();

    logman_init();

    Swi_Params_init(&swi_ms_params);
    swi_ms_params.priority = 15;

    swi_ms_params.trigger = SAMPLES_PER_MS * LOOP_CYCLE_MS; // every x samples
    swi_ms = Swi_create(&ms_hook,&swi_ms_params,NULL);

    Swi_Params_init(&swi_10ms_params);
    swi_10ms_params.priority = 10;
    swi_10ms_params.trigger = SAMPLES_PER_MS * 10; // (10 ms)
    swi_10ms = Swi_create(&ms10_hook,&swi_10ms_params,NULL);

    Swi_Params_init(&swi_50ms_params);
    swi_50ms_params.priority = 8;
    swi_50ms_params.trigger = SAMPLES_PER_MS * 50; // (50 ms)
    swi_50ms = Swi_create(&ms50_hook,&swi_50ms_params,NULL);

    Swi_Params_init(&swi_notify_params);
    swi_notify_params.priority = 1;
    swi_notify_params.trigger = 1;
    swi_notify = Swi_create(&notify_swi,&swi_notify_params,NULL);

    SET_RIS_TRIG8 = (1<<15); // rising edge trig from GP8.15

    configure_pwr_ok_gpio();
    pwm_init();
    pwm_start_cnt();

//	eth.hwaddr[0]=0xC4;
  //  eth.hwaddr[1]=0xff;
//	eth.hwaddr[2]=0xBC;
//	eth.hwaddr[3]=0x70;
//	eth.hwaddr[4]=0x14;
//	eth.hwaddr[5]=0x3f;
	//lwIPInit(0, eth.hwaddr, eth.ip, eth.netmask, eth.gateway, IPADDR_USE_STATIC);
	//Hwi_enableInterrupt(10);
	//Hwi_enableInterrupt(11);

    BIOS_start();     /* enable interrupts and start SYS/BIOS */
}
