#include "csl_vcp2.h"
#include "csl_vcp2Aux.h"
#include "csl_edma3.h"
#include "stdio.h"
#include "string.h"
#include "cslr_dev.h"
#include "VCP2EDMA3.h"
#include "Viterbi.h"

#define YAMAMOTO_THRESHOLD 80
#define INITIAL_STATE       31

/* EDMA frame size */
#define DMA_BURST_SIZE  128

/* VCP2 input configuration transfer size */
#define VCPIC_DMA_SIZE  24

/* VCP2 out register transfer size */
#define VCPOUT_DMA_SIZE  8

int maxdata;
float maxdataf;
int DecodeFlag;
int LDLDataNum;
int DataPackNum;

#pragma DATA_ALIGN(outputdata,8);
unsigned int outputdata[512];
#pragma DATA_ALIGN(decodebitdata,8);
unsigned char decodebitdata[240*8];
#pragma DATA_ALIGN(BMUserData,8);
char BMUserData[240*8*8*2];
int BMUserData1[240*8*8*2];
#pragma DATA_ALIGN(outbitdata,8);
unsigned char outbitdata[128*8];
#pragma DATA_ALIGN(decodedata,8);
unsigned char decodedata[240];

void Output2Bit(unsigned int *I_outputdata,unsigned char *O_decodedata,int inlen)
{
	int i,j,k;
	for(i=0;i<((inlen>>5)+1);i++)
	{
		for(k=0;k<4;k++)
		{
			for(j=0;j<8;j++)
			{
				O_decodedata[i*32+k*8+j]=(I_outputdata[i]>>k*8+j)&0x0001;
			}
		}
	}
}

Uint16 vcp2_configEdma(Uint32 inputBM, Uint32 outputHD)
{
    volatile Uint16               count;
    CSL_Status                  chStatus, chStatus1;

    CSL_edma3Init(&context);
    
    CSL_edma3Open(&edmaObj,CSL_EDMA3,NULL,&chStatus);

    /* Channel Configuration for VCP2XEVT event */
    /* Channel Open */
    chParam.regionNum = CSL_EDMA3_REGION_GLOBAL;
    chParam.chaNum = CSL_EDMA3_CHA_VCP2XEVT;
    hChannel = CSL_edma3ChannelOpen(&ChObj, CSL_EDMA3, &chParam, &chStatus);
    if ((chStatus != CSL_SOK) || (hChannel == NULL)) {
        printf("Error in EDMA channel open function\n");
        return 0;
    }

    /* Channel Setup */
    if (CSL_SOK != CSL_edma3HwChannelSetupParam(hChannel, 0 /* PaRAM entry */)){
        printf("Error in EDMA channel setup for channel #29\n");
        return 0;
    }

    if (CSL_SOK != CSL_edma3HwChannelSetupQue(hChannel, CSL_EDMA3_QUE_0)) {
        printf("Error in EDMA channel setup for channel #29\n");
        return 0;
    }

    /* Setup link to transmit Input configuration */
    hParam[0] = CSL_edma3GetParamHandle (hChannel, 0, &chStatus);
    myParamSetup.option = CSL_EDMA3_OPT_MAKE (FALSE,FALSE,FALSE,FALSE,0,
                                            CSL_EDMA3_TCC_NORMAL,
                                            CSL_EDMA3_FIFOWIDTH_NONE,
                                            FALSE,CSL_EDMA3_SYNC_A,
                                            CSL_EDMA3_ADDRMODE_INCR,
                                            CSL_EDMA3_ADDRMODE_INCR);           
    myParamSetup.srcAddr = (Uint32)&vcpConfig;
    myParamSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(VCPIC_DMA_SIZE, 1);       
    myParamSetup.dstAddr = (Uint32)hVcp2Vbus;        
    myParamSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(0, 0);     
    myParamSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(0x20, 0); 
                            /* offset to the next param entry */    
    myParamSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0, 0);     
    myParamSetup.cCnt = 1;
    if (CSL_SOK != CSL_edma3ParamSetup (hParam[0], &myParamSetup)) {
        printf("Error in EDMA paRam setup for entry #0\n");
        return 0;
    }

    /* Setup link to transmit branch metrics */
    hParam[1] = CSL_edma3GetParamHandle(hChannel,1,&chStatus);
    myParamSetup.option = CSL_EDMA3_OPT_MAKE(FALSE, FALSE, FALSE, FALSE, 0,
                                            CSL_EDMA3_TCC_NORMAL,
                                            CSL_EDMA3_FIFOWIDTH_64BIT,
                                            FALSE,CSL_EDMA3_SYNC_A,
                                            CSL_EDMA3_ADDRMODE_CONST,
                                            CSL_EDMA3_ADDRMODE_INCR);           
    myParamSetup.srcAddr = (Uint32)BMUserData;
    myParamSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(DMA_BURST_SIZE, 0);     
    myParamSetup.dstAddr = (Uint32)&(hVcp2Vbus->VCPWBM);
    myParamSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(
                                                CSL_EDMA3_LINK_NULL, 0);
    myParamSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(DMA_BURST_SIZE, inputBM);
    myParamSetup.cCnt = 1;
    if (CSL_SOK != CSL_edma3ParamSetup (hParam[1], &myParamSetup)) {
        printf("Error in EDMA paRam setup for entry #1\n");
        return 0;
    }

    /* Channel Configuration for VCP2REVT event */
    /* Channel Open */
    chParam1.regionNum = CSL_EDMA3_REGION_GLOBAL;
    chParam1.chaNum = CSL_EDMA3_CHA_VCP2REVT;
    hChannel1 = CSL_edma3ChannelOpen (&ChObj1, CSL_EDMA3, &chParam1, 
                                                            &chStatus1);
    if ((chStatus1 != CSL_SOK) | (hChannel1 == NULL)) {
        printf("Error in EDMA channel open function\n");
        return 0;
    }

    /* Channel Setup */
    if (CSL_SOK != CSL_edma3HwChannelSetupParam(hChannel1, 2 )) {
        printf("Error in EDMA channel setup for channel #29\n");
        return 0;
    }

    if (CSL_SOK != CSL_edma3HwChannelSetupQue(hChannel1, CSL_EDMA3_QUE_0)) {
        printf("Error in EDMA channel setup for channel #29\n");
        return 0;
    }

    hParam[2] = CSL_edma3GetParamHandle (hChannel1, 2, &chStatus);
    myParamSetup.option = CSL_EDMA3_OPT_MAKE (FALSE, FALSE, FALSE, FALSE, 0,
                                             CSL_EDMA3_TCC_NORMAL,
                                             CSL_EDMA3_FIFOWIDTH_64BIT,
                                             FALSE,CSL_EDMA3_SYNC_A,
                                             CSL_EDMA3_ADDRMODE_INCR,
                                             CSL_EDMA3_ADDRMODE_CONST);           
    myParamSetup.srcAddr = (Uint32)&(hVcp2Vbus->VCPRDECS);
    myParamSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE (outputHD, 1);       
    myParamSetup.dstAddr = (Uint32)outputdata;        
    myParamSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE (0, outputHD);     
    myParamSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE (0x60, 0);  
                                        /* offset to the next param entry */    
    myParamSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE (0, 0);     
    myParamSetup.cCnt = 1;
    if (CSL_SOK != CSL_edma3ParamSetup (hParam[2], &myParamSetup)) {
        printf("Error in EDMA paRam setup for entry #2\n");
        return 0;
    }

    hParam[3] = CSL_edma3GetParamHandle (hChannel1, 3, &chStatus);
    myParamSetup.option = CSL_EDMA3_OPT_MAKE (FALSE, FALSE, FALSE, FALSE, 0,
                                             CSL_EDMA3_TCC_NORMAL,
                                             CSL_EDMA3_FIFOWIDTH_NONE,
                                             FALSE,CSL_EDMA3_SYNC_A,
                                             CSL_EDMA3_ADDRMODE_INCR,
                                             CSL_EDMA3_ADDRMODE_INCR);
    myParamSetup.srcAddr = (Uint32)&(hVcp2Vbus->VCPOUT0);
    myParamSetup.dstAddr = (Uint32)&ouputParams[0];
    myParamSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE (VCPOUT_DMA_SIZE, 1);
    myParamSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE (
                                            CSL_EDMA3_LINK_NULL, 0);
    if (CSL_SOK != CSL_edma3ParamSetup (hParam[3], &myParamSetup)) {
        printf("Error in EDMA paRam setup for entry #3\n");
        return 0;
    }

    return 1;

}

void Vcp2ParmSet(int framelen,int rate,int constlen,VCP2_Poly polyarray)
{
    vcpBaseParams.rate      = rate;
    vcpBaseParams.constLen  = constlen;
    vcpBaseParams.frameLen  = framelen;
    vcpBaseParams.yamTh     = YAMAMOTO_THRESHOLD;
    vcpBaseParams.stateNum  = INITIAL_STATE;
    vcpBaseParams.tbConvrgMode = FALSE;
    vcpBaseParams.decision  = VCP2_DECISION_SOFT;
    vcpBaseParams.readFlag  = TRUE;
    vcpBaseParams.tailBitEnable = FALSE;
    vcpBaseParams.traceBackIndex = 0;
    vcpBaseParams.outOrder  = 1;
	
    VCP2_genParams (&vcpBaseParams, &vcpParams);
    inputBM = vcpParams.numBmFrames;
    outputHD_bytes = vcpBaseParams.frameLen + vcpBaseParams.constLen - 1;
    outputHD_words = VCP2_normalCeil (outputHD_bytes, sizeof (Uint32));
    outputHD = outputHD_words * sizeof (Uint32);

    VCP2_addPoly (&poly, &vcpParams);
		
    VCP2_genIc (&vcpParams, &vcpConfig);

}

void vcp2_core(int inbitlen,short * sourceI0,short * sourceQ0,short * sourceI1,short * sourceQ1,
												short * sourceI2,short * sourceQ2,short * sourceI3,short * sourceQ3,
												int rate,int conlen,unsigned char *decodebit)
{
	short framelen;
	int i;
	int bmlen;
	int BMlen=1;

       /* Enable the VCP2 in power saver */
       CSL_FINST (((CSL_DevRegs*)CSL_DEV_REGS)->PERLOCK, DEV_PERLOCK_LOCKVAL, 
                                                                       UNLOCK);
   
       CSL_FINST (((CSL_DevRegs*)CSL_DEV_REGS)->PERCFG0, DEV_PERCFG0_VCPCTL, 
                                                                       ENABLE);
   
       while (CSL_DEV_PERSTAT0_VCPSTAT_ENABLE != 
               CSL_FEXT (((CSL_DevRegs*)CSL_DEV_REGS)->PERSTAT0, 
                                                       DEV_PERSTAT0_VCPSTAT));

	BMlen=BMlen<<(rate-1);
	framelen=inbitlen;
	bmlen=framelen*rate;
	BMlen=BMlen*framelen;	
	
	Vcp2ParmSet(framelen-7,rate,conlen,poly);

	maxdata=BitMetricComputeBPSKtest(sourceI0,sourceQ0,sourceI1,sourceQ1,sourceI2,sourceQ2,sourceI3,sourceQ3,BMUserData1,framelen,rate);

	maxdataf=1.0/maxdata;
	for(i=0;i<BMlen;i++)
		BMUserData[i]=(char)(BMUserData1[i]*maxdataf*127);
	
       if (!(vcp2_configEdma (inputBM, outputHD)))
       {
           printf("\nError in configuring EDMA\n");
           return;
       }
       else
           printf("\nConfiguring EDMA......... Success\n");

       /* clear the error registers */
       chErrClear.missed = TRUE;
       chErrClear.secEvt = TRUE;
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL);
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_CLEARERR, 
                                  &chErrClear);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEARERR, 
                                  &chErrClear);
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL);
   
       /* Enable Channel */
       CSL_edma3HwChannelControl(hChannel1, CSL_EDMA3_CMD_CHANNEL_ENABLE , NULL);
       /* Enable Channel */ 
       CSL_edma3HwChannelControl(hChannel, CSL_EDMA3_CMD_CHANNEL_ENABLE , NULL);

       /* Start VCP2 */ 
       VCP2_reset ();
       VCP2_emuDisable ();   
       VCP2_start ();
       printf("VCP2 is started...\n");
       
       /* Wait till processing is over */
       while (VCP2_statRun());
       printf("VCP2 processing of data over\n");
       printf("\nRESULTS\n");
       printf("~~~~~~~\n");
       
       printf("FMINS = %d\n", ((ouputParams[0] & 0x0FFF0000)>>16));
       printf("FMAXS = %d\n", (ouputParams[0] & 0x00000FFF));
       printf("FMAXI = %d\n", (ouputParams[1] & 0x0000000F));
	   
       /* Get the number of symbols processed */
       numSymProc = VCP2_statSymProc();
       printf("Number of symbols processed = %d \n", numSymProc);

       Output2Bit(outputdata,decodebit,framelen);

       /* clear the error registers */
       chErrClear.missed = TRUE;
       chErrClear.secEvt = TRUE;
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL);
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_CLEARERR, 
                                  &chErrClear);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEARERR, 
                                  &chErrClear);
       CSL_edma3HwChannelControl (hChannel, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL);
       CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL);
       
       /* Close EDMA channels */
       CSL_edma3ChannelClose (hChannel);
       CSL_edma3ChannelClose (hChannel1);
	   
	
}

void VCP2Test()
{
	short framelen;
	int bmlen;
	int rate;
	int i;
	int BMlen=1;;

    rate=4;
	BMlen=BMlen<<(rate-1);

	framelen=LDLDataNum*8;
	bmlen=LDLDataNum*8*rate;
	BMlen=BMlen*framelen;	

	memset(outputdata,0,sizeof(outputdata));
	memset(decodebitdata,0,sizeof(decodebitdata));
	memset(decodedata,0,sizeof(decodedata));
	memset(outbitdata,0,sizeof(outbitdata));
	memset(BMUserData,0,sizeof(BMUserData));
	memset(BMUserData1,0,sizeof(BMUserData1));


	Data28PSK(NodeData.SourceDataTest,NodeData.XIData,NodeData.XQData,bmlen);//3840
	BitMetricCompute8PSKFix(NodeData.XIData,NodeData.XQData,NodeData.tempdata1,NodeData.tempdata2,bmlen/3);//3840/4

 	for(i=0;i<framelen;i++)
		{
		NodeData.sourcedataI0[i]=NodeData.tempdata1[i*rate];
		NodeData.sourcedataQ0[i]=NodeData.tempdata2[i*rate];
		NodeData.sourcedataI1[i]=NodeData.tempdata1[i*rate+1];
		NodeData.sourcedataQ1[i]=NodeData.tempdata2[i*rate+1];
		NodeData.sourcedataI2[i]=NodeData.tempdata1[i*rate+2];
		NodeData.sourcedataQ2[i]=NodeData.tempdata2[i*rate+2];
		NodeData.sourcedataI3[i]=NodeData.tempdata1[i*rate+3];
		NodeData.sourcedataQ3[i]=NodeData.tempdata2[i*rate+3];
		
		}
	
	vcp2_core((framelen),	NodeData.sourcedataI0,NodeData.sourcedataQ0,
										NodeData.sourcedataI1, NodeData.sourcedataQ1, 
										NodeData.sourcedataI2, NodeData.sourcedataQ2, 
										NodeData.sourcedataI3, NodeData.sourcedataQ3,rate,CONSTRAINT_LEN,outbitdata);
	Bit2Byte(decodedata,outbitdata,framelen);
	

}
