/**************************************************************
***************************************************************
**
** Host Application, Copyright (C) 2003-2005
** Ikanos Communication, Fremont, CA 
** All rights reserved.
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of 
** Ikanos Communication
**
***************************************************************

$Revision: 1.1 $
$Date: 2006/10/16 04:34:49 $
**************************************************************/

/*******  Include Files         ***************************************/
#include <stdio.h>
#include "bmeconfig.h"
#include "oampdb.h"
#include "linecrc.h"

#define RPT_INTVL_SEC	2	/* Counter report in seconds */
#define MAX_CRC_CNT_PER_INTVL	((400 * RPT_INTVL_SEC) - 5)
#define TRUE  (1)
U8 eTrigger = 30;
U8 dbCnt = 5;
U8 lineCrcDBug = 0;

struct crcThStatus
{
	U32 dataRateF;
	U32 dataRateS;
	U16 prevCrcCntF;
	U16 prevCrcCntS;
	U16 crcThF;
	U16 crcThS;
	U16 crcCntF;
	U16 crcCntS;
	U16 loopF;
	U16 loopS;
	U16 loopCntF;
	U16 loopCntS;
	U8 dbCntF;
	U8 dbCntS;
};
static struct crcThStatus portCrcStatus[IPOS_MAX_BME][IPOS_MAX_PORTS];

static int sixPtLineHoldEnable = 0; //Global Enable, default is disabled 
/***********************************************************************
************************************************************************

          F U N C T I O N     I N T E R F A C E S 

************************************************************************
***********************************************************************/
void setSixPtLineHoldEnable(int en)
{
    if(en==0 || en == 1)
    {
        sixPtLineHoldEnable = en;
    }
}

int getSixPtLineHoldEnable()
{
    return (sixPtLineHoldEnable);
}


int evalSixPtLineHold(U8 lineHold6ptOk)
{
    if( lineHold6ptOk == TRUE  && getSixPtLineHoldEnable() == 1) 
    {
        return 1; 
    }
    else
    {
        return 0;
    }
}

void setLineCrcThreshold (ipos_port_id pid, U32 dataRateF, U32 dataRateS)
{
	struct crcThStatus *pCrcStatus;
    int port, bme;

    port = pid.portNum - 1;
    bme  = pid.bmeNum - 1;

	if ((port >= 0) && (port < IPOS_MAX_PORTS)
            && (bme >= 0) && (bme < IPOS_MAX_BME))
	{
		pCrcStatus = &portCrcStatus[bme][port];
		pCrcStatus->dataRateF = dataRateF * 64;
		pCrcStatus->prevCrcCntF = 0;
		pCrcStatus->dataRateS = dataRateS * 64;
		pCrcStatus->prevCrcCntS = 0;
		reCalLineCrcThreshold(pid);
	}
	else
	{
		if (lineCrcDBug)
			printf ("\nSet line crc threshold invalid port/bme number: %d %d\n", port+1, bme+1);
	}
}

void reCalLineCrcThreshold (ipos_port_id pid)
{
	struct crcThStatus *pCrcStatus;
	int portStop, bmeStop, port, bme;
	U32 errRate, dataRate;
	U16 numLoop;

    port = pid.portNum;
    bme  = pid.bmeNum;

	if ((bme >= 0) && (bme <= IPOS_MAX_BME) && (port >= 0) && (port <= IPOS_MAX_PORTS))
	{
		if (port == 0)
			portStop = IPOS_MAX_PORTS;
		else
		{
			portStop = port;
			port--;
		}
		if (bme == 0)
			bmeStop = IPOS_MAX_BME;
		else
		{
			bmeStop = bme;
			bme--;
		}
		if (((errRate = oampGetVdslCrcThreshold) > 0) && (errRate <= 10000))
			errRate = ((U32)eTrigger * 100000) / errRate;
		else
			errRate = 0;
        do
        {
            do
            {
                pCrcStatus = &portCrcStatus[bme][port];
                if ((pCrcStatus->dataRateF > 0) && (errRate > 0))
                {
                    dataRate = RPT_INTVL_SEC * pCrcStatus->dataRateF;
                    numLoop = (U16)((errRate + dataRate) / dataRate);
                    pCrcStatus->crcThF = (eTrigger * (((numLoop * dataRate * 100) +
                                                                                         errRate) / errRate)) / 100;
                    if (pCrcStatus->crcThF > MAX_CRC_CNT_PER_INTVL)
                        pCrcStatus->crcThF = MAX_CRC_CNT_PER_INTVL;
                    pCrcStatus->crcCntF = 0;
                    pCrcStatus->loopF = numLoop;
                    pCrcStatus->loopCntF = 0;
                    pCrcStatus->dbCntF = 0;
                }
                else
                    pCrcStatus->loopF = 0;
                if ((pCrcStatus->dataRateS > 0) && (errRate > 0))
                {
                    dataRate = RPT_INTVL_SEC * pCrcStatus->dataRateS;
                    numLoop = (U16)((errRate + dataRate) / dataRate);
                    pCrcStatus->crcThS = (eTrigger * (((numLoop * dataRate * 100) +
                                                                                         errRate) / errRate)) / 100;
                    if (pCrcStatus->crcThS > MAX_CRC_CNT_PER_INTVL)
                        pCrcStatus->crcThS = MAX_CRC_CNT_PER_INTVL;
                    pCrcStatus->crcCntS = 0;
                    pCrcStatus->loopS = numLoop;
                    pCrcStatus->loopCntS = 0;
                    pCrcStatus->dbCntS = 0;
                }
                else
                    pCrcStatus->loopS = 0;

            } while (++port < portStop );

        } while (++bme < bmeStop);
	}
	else
	{
		if (lineCrcDBug)
			printf ("\nInvalid port/bme number: %d %d\n", port, bme);
	}
}

int evalLineCrc (ipos_port_id pid, U16 currentCntF, U16 currentCntS)
{
	int thresholdCrossed = 0, port, bme;
	struct crcThStatus *pCrcStatus;

    port = pid.portNum - 1;
    bme  = pid.bmeNum - 1;

	if ((port >= 0) && (port < IPOS_MAX_PORTS)
            && (bme >= 0) && (bme < IPOS_MAX_BME))
	{
		pCrcStatus = &portCrcStatus[bme][port];
		if (pCrcStatus->loopF)
		{
			if (pCrcStatus->prevCrcCntF > currentCntF)
				pCrcStatus->crcCntF += (0x10000 - pCrcStatus->prevCrcCntF) +
																currentCntF;
			else
				pCrcStatus->crcCntF += currentCntF - pCrcStatus->prevCrcCntF;
			pCrcStatus->prevCrcCntF = currentCntF;
			if (pCrcStatus->crcCntF >= pCrcStatus->crcThF)
			{
				if (++(pCrcStatus->dbCntF) >= dbCnt)
					thresholdCrossed = 1;
				pCrcStatus->crcCntF = 0;
				pCrcStatus->loopCntF = 0;
			}
			else
			{
				if (++(pCrcStatus->loopCntF) >= pCrcStatus->loopF)
				{
					pCrcStatus->crcCntF = 0;
					pCrcStatus->loopCntF = 0;
					pCrcStatus->dbCntF = 0;
				}
			}
		}
		if (pCrcStatus->loopS)
		{
			if (pCrcStatus->prevCrcCntS > currentCntS)
				pCrcStatus->crcCntS += (0x10000 - pCrcStatus->prevCrcCntS) +
																currentCntS;
			else
				pCrcStatus->crcCntS += currentCntS - pCrcStatus->prevCrcCntS;
			pCrcStatus->prevCrcCntS = currentCntS;
			if (pCrcStatus->crcCntS >= pCrcStatus->crcThS)
			{
				if (++(pCrcStatus->dbCntS) >= dbCnt)
					thresholdCrossed = 1;
				pCrcStatus->crcCntS = 0;
				pCrcStatus->loopCntS = 0;
			}
			else
			{
				if (++(pCrcStatus->loopCntS) >= pCrcStatus->loopS)
				{
					pCrcStatus->crcCntS = 0;
					pCrcStatus->loopCntS = 0;
					pCrcStatus->dbCntS = 0;
				}
			}
		}
	}
	else
	{
		if (lineCrcDBug)
			printf ("\nEval line crc invalid port/bme number: %d %d\n", port+1, bme+1);
	}
	if (lineCrcDBug)
	{
		if (thresholdCrossed)
			printf ("\nThreshold crossed!!\n");
		dumpLineCrcStatus(pid);
	}
	return (thresholdCrossed);
}

void dumpLineCrcStatus (ipos_port_id pid)
{
	int stop, port, bme;

    port = pid.portNum;
    bme  = pid.bmeNum - 1;

	if ((bme >= 0) && (bme < IPOS_MAX_BME) && (port >= 0) && (port <= IPOS_MAX_PORTS))
	{
		if (port == 0)
			stop = IPOS_MAX_PORTS;
		else
		{
			stop = port;
			port--;
		}
		printf ("\nBER: %ld, Error Trigger: %d, Debounce Threshold: %d\n",
						(unsigned long)oampGetVdslCrcThreshold, eTrigger, dbCnt);
		do
		{
			printf ("Fast Path: %ld Kbps\n", portCrcStatus[bme][port].dataRateF);
			printf ("  previous count: %d, Threshold: %d, CRC count: %d\n",
							portCrcStatus[bme][port].prevCrcCntF, portCrcStatus[bme][port].crcThF,
							portCrcStatus[bme][port].crcCntF);
			printf ("  Interval: %d, Current Interval: %d, Debounce Count: %d\n",
							portCrcStatus[bme][port].loopF, portCrcStatus[bme][port].loopCntF,
							portCrcStatus[bme][port].dbCntF);
			printf ("Slow Path: %ld Kbps\n", portCrcStatus[bme][port].dataRateS);
			printf ("  previous count: %d, Threshold: %d, CRC count: %d\n",
							portCrcStatus[bme][port].prevCrcCntS, portCrcStatus[bme][port].crcThS,
							portCrcStatus[bme][port].crcCntS);
			printf ("  Interval: %d, Current Interval: %d, Debounce Count: %d\n",
							portCrcStatus[bme][port].loopS, portCrcStatus[bme][port].loopCntS,
							portCrcStatus[bme][port].dbCntS);
		} while (++port < stop );
	}
	else
		printf ("\nInvalid port/bme number: %d %d\n", port, bme+1);
}
