/**************************************************************
$Workfile:   eocapp.c  $
***************************************************************
**
** FIRMWARE, Copyright (C) 2000-2002
** Ikanos Communications, 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.2 $
$Date: 2006/12/12 10:53:06 $
***************************************************************/


/**************************************************************

	This file contains functions for 
		EOC related Apps:
		
		1. EOC stream loopback
		
		
**************************************************************/


#include <stdio.h>
 
#include "ipos.h"
#include "eocapi.h"
#include "eocapp.h"
#include "appconfig.h"
#include "oampdef.h"
#include "oamp.h"
#include "oampstruct.h"
#include "report.h"
#include "portmap.h"
#include "oampdb.h"
#ifdef INI_SUPPORT
#include "HostPtmfApi.h"
#endif //INI_SUPPORT
/*#define TRACE_EOC*/

#define MAX_EOC_PROTOCOL_STRUCT_SIZE	64	/* 5 byte std EOC header + 2 byte protocol version + */
						/* 56 bytes of Vendor ID */

#ifdef	USE_RFM
#ifdef	VTU_O
extern void	iposRFMCOEntry(ipos_port_id pid, U8	*pEocMsg);
#endif
#ifdef	VTU_R
extern void	iposRFMCPEEntry(ipos_port_id pid, U8	*pEocMsg);
#endif
#endif

#ifdef	VTU_O
extern void	iposELMCOEntry(ipos_port_id pid, U8	*pEocMsg);
#endif
#ifdef	VTU_R
extern void	iposELMCPEEntry(ipos_port_id pid, U8	*pEocMsg);
#endif

extern oamp_bme oampBme [IPOS_MAX_BME+1];/* BME objects for OAMP   */
extern void displayPerfCntrs(ipos_port_id Pid) ;
extern void displayPmCounters (ipos_port_id Pid) ;
extern void eocGetDataComplete(ipos_port_id portId, U8 UID,U32 cntRpt, int status,  void *par);
extern void appRMMInit( void );
void uiOhmCmdMenu (ipos_port_id pid) ;

/* This struct MUST match the oamp_cb_msg struct in oampfuncs.c !! */

typedef	struct
{
	ipos_port_id	portId;
	U8				uid;
	int				status;
	int				cntRpt;			/* repeat counter	*/
	int				parLen;
    char			par[128];		/* parameters	*/
}oamp_cb_msg_snr;

/* For EOC loopback testing */

extern void	appEocLbStressResp( ipos_port_id pid, int len, U8 *data );
extern void	appEocLbStressResult( ipos_port_id pid, int len, U8 *data );
extern void	appEocLbResetStress( int portNum );


static struct
{
	U32	FeFEC_S;
	U32	FeFEC_F;
	U32	FeFECUnCrr_S;
	U32	FeFECUnCrr_F;
	
	U16	FeCRC_S;
	U16	FeCRC_F;	
    U16 FeSEF;
	U8	FeFLOS;

	U32 TxFrameCnt;
	U32 RxFrameCnt;
    U32 TxCrcCnt;
    U32	RxCrcCnt;
	U32	DropFrameCnt;
} feCounters[MAX_NUM_OF_PORTS + 1];

static struct
{
	S32	FeSnrMargin;
	U32 FeAttn;
} feSnrAttn[MAX_NUM_OF_PORTS + 1];

static char dataValid[MAX_NUM_OF_PORTS + 1];

static ieParserEntry	appIeParserTable[ MAX_IE_PARSER_ENTRIES ];

#ifdef BME_CPE_20
static const char	ikanos_vendor_id[] = "Ikanos BME CPE 2.0";
static U32 prevVal = 0;
#else
static const char	ikanos_vendor_id[] = "Ikanos BME CPE 1.0";
#endif

extern oamp_bme oampBme [IPOS_MAX_BME+1];  				/* BME objects for OAMP   */
extern ipos_port_profile sPortProfiles[];
/*---------------------------------------------------------------------------*/
/* Ethernet Address Filter EOC Semaphore                                     */
extern int AddrFilterEocSema4;
#ifdef INI_SUPPORT 
extern tsIposPtmfEnetAddrFilterCfg		tsEnetAddrFilterConfig;
#endif //INI_SUPPORT
/*---------------------------------------------------------------------------*/

extern int		getLineNum(ipos_port_id pid, int *lineNum);
extern int autoStart;
extern BYTE pTlStr[512];
extern int MacMenu;

typedef	void  (*completionJob) (int arg1, int arg2, ipos_msg_buf	*pBuf);
extern void	addCompletionJob(ipos_port_id portId, U8 UID, U32 uPar, int status,
														 U8 *par, int len,  completionJob  pFunJob);
/* for far-end SNR	*/
void portNeSnrCompleteRemote(ipos_port_id portId, U8 UID,U32 cntRpt, int status,  
							  ipos_port_nesnrattn *par);
static	void	portNeSnrJobRemote(int arg1, int arg2, ipos_msg_buf	*pBuf);
static void	appVirtualMessage1Init( void );
static int	virtualMessage1Filter( U8 *data, int len );

void	portFeSnrJob(U32 arg1, U32 arg2, ipos_msg_buf *pBuf);

void display_Eoc_LogMenu (ipos_port_id pid);
void construct_eoc_command (ipos_port_id pid, int internalEocCmd, int val, int flag);
void uiInternalEocMenu ( ipos_port_id pid );
extern int oampEocProtocolGet(ipos_port_id *pPid, U8 opCode, U8 cmdTag, U32 cntRpt);
extern int oampEocProtocolSet(ipos_port_id *pPid, U8 opCode, U8 *regdata, U8 cmdTag, U32 cntRpt);
extern int ReceiveTLCommand( U8 *bTlStr);
void add_EocEventLog(ipos_port_id pid,void *par);
void get_EocEventLog (ipos_port_id pid); 
void clear_EocEventLog (ipos_port_id pid);
void check_value(char *str, int *port_options);
void construct_ohm_command (ipos_port_id pid, int Cmd, int val, int flag) ;

#ifdef ALASKA
void ohmCmdProcess(ipos_port_id pid, char *ohmData);
#endif
#define MAX_DEBUG_MESSAGES 50
#define MAX_EOC_TRACE_MSG_SIZE (50)
typedef struct {
	 char trace_options;
	 char val_changed;
} trace_options_eoc;
trace_options_eoc trace_options[MAX_NUM_OF_PORTS +1];
trace_options_eoc ohm_trace_options[MAX_NUM_OF_PORTS +1];
int add_events;
int total_events;
typedef struct {
	  int portNum;
		char message[MAX_EOC_TRACE_MSG_SIZE];
    struct tm  	TimeStamp;
} trace_eoc;
trace_eoc trace_events[MAX_DEBUG_MESSAGES];

void add_EocEventLog(ipos_port_id pid,void *par) {

	 char *event = par;
	 time_t present_time;

   time(&present_time);

	 if (add_events < MAX_DEBUG_MESSAGES) {
       trace_events[add_events].portNum = pid.portNum;
                         memset(trace_events[add_events].message, ' ', MAX_EOC_TRACE_MSG_SIZE);
			 memcpy(trace_events[add_events].message, (event + 1), *event);
	     localtime_r(&present_time, &trace_events[add_events].TimeStamp);
			 total_events++;
			 add_events++;
	 } else {
			add_events = 0;
	 }
}

void get_EocEventLog (ipos_port_id pid) 
{
   int i = 0, count_of_trace = 0, j = 0;

   printf("EOC Trace for Port %x\n",pid.portNum);

	 if (total_events > MAX_DEBUG_MESSAGES)
			 count_of_trace = 50;
	 else
			 count_of_trace = total_events;

	 for ( i = 0; i < count_of_trace; i++) {
			 if ( total_events >  MAX_DEBUG_MESSAGES )
			     j = ( i + add_events ) % MAX_DEBUG_MESSAGES; 
			 else 
					 j = i;
       if (trace_events[j].portNum == pid.portNum) {
			     printf("\n%.2i:%.2i:%.2i:day %i:",(int)trace_events[j].TimeStamp.tm_hour,(int)trace_events[j].TimeStamp.tm_min,(int)trace_events[j].TimeStamp.tm_sec,(int)trace_events[j].TimeStamp.tm_mday);
					 printf("%s",trace_events[j].message);
			 }
	 }
}

void clear_EocEventLog (ipos_port_id pid)
{
	 /* Just clear the add_event_trace value of the Port. */
	 int i = 0;
	 add_events = 0;
	 total_events = 0;

	 for (i = 0; i < MAX_DEBUG_MESSAGES; i++) {
			 memset(&trace_events[i], 0, sizeof(trace_eoc));

	 }
}

#define GET_EN_DI_EOC_VAL     (0x01)
#define SET_EN_DI_EOC_VAL     (0x02)
#define GET_EN_DI_TRACE_VAL   (0x03)
#define SET_EN_DI_TRACE_VAL   (0x04)
#define GET_EOC_TRACE_OPTIONS (0x05)
#define SET_EOC_TRACE_OPTIONS (0x06)
#define GET_EOC_STATE         (0x11)

#define EOC_BIT  (0x07)
#define TRACE_BIT (0x05)
#define TRACE_OPTIONS (0x04)

/* OHM Commands Set */
#define OHM_HPI_STEST      0xA1    /* Perform "self test" */
#define OHM_HPI_UTP        0xA2    /* Update Test Parameters */
#define OHM_HPI_TXCRC_START  0xA3    /* Start Tx Corrupted CRCs */
#define OHM_HPI_TXCRC_END    0xA4    /* End Tx Corrupted CRCs */
#define OHM_HPI_RXCRC_START  0xA5    /* Start Rx Corrupted CRCs */
#define OHM_HPI_RXCRC_END    0xA6    /* End Rx Corrupted CRCs */

#define OHM_HPI_READTIME    0xA7    /* Read Time */
#define OHM_HPI_INVID      0xA8    /* Inventory ID */
#define OHM_HPI_AUXID      0xA9    /* Auxiliary ID */
#define OHM_HPI_STEST_RSLT    0xAA    /* Self Test Result Read */
#define OHM_HPI_PMDCAP      0xAB    /* PMD capability  */
#define OHM_HPI_PMSCAP      0xAC    /* PMSTC capability  */
#define OHM_HPI_TPSCAP      0xAD    /* TPSTC capability */

#define OHM_HPI_PMDCTRL    0xAE    /* PMD control param */
#define OHM_HPI_PMSCTRL    0xAF    /* PMSTC control param */
#define OHM_HPI_TPSCTRL    0xB0    /* TPSTC control param */

#define OHM_HPI_MGMTREAD    0xB1    /* Mgmt Counter Read */

#define OHM_HPI_SETTIME    0xB2    /* Set Time */
#define OHM_HPI_CLEAREOC    0xB3    /* ClearEOC */


#define OHM_HPI_TP_HLOG    0xB4    /* Channel Transfer Function per subcarrier */
#define OHM_HPI_TP_QLN      0xB5    /* Quiet Line Noise PSD per subcarrier */
#define OHM_HPI_TP_SNR      0xB6    /* Signal to noise ratio per subcarrier */
#define OHM_HPI_TP_LATN    0xB7    /* Line Attenuation */
#define OHM_HPI_TP_SATN    0xB8    /* Signal Attenuation */
#define OHM_HPI_TP_SNRM    0xB9    /* Signal-to-Noise Margin */
#define OHM_HPI_TP_ATTNDR    0xBA    /* Attainable Net Data Rate */
#define OHM_HPI_TP_ACTATP_NE  0xBB    /* Near-end Actual Aggregate Transmit Power */
#define OHM_HPI_TP_ACTATP_FE  0xBC    /* Far-end Actual Aggregate Transmit Power */
#define OHM_HPI_TP_MULTI_READ  0xBD    /* Multi Read */
#define OHM_HPI_TP_NEXTMULTI_READ  0xBE    /* Next Multi Read */
#define OHM_HPI_TP_BLOCK_READ  0xBF    /* Block Read */

#define OHM_SETTIME_LEN 8 /* Time format (HH:MM:SS) length*/

/* EOC Commands Set */
#define HOLD			        0x01					/* Hold State */
#define RTN				        0xf0					/* Return-To- Normal */
#define SLFTST		        0x02					/* Perform "self test" */
#define UTC				        0x04					/* Unable to comply */	
#define REQCOR		        0x07					/* Request for corrupted CRC/FEC */
#define REQEND		        0x08					/* Request end of corrupted CRC/FEC */
#define	NOTCOR		        0x0b					/* Notify Corrupted CRC/FEC */
#define NOTEND		        0x0d					/* Notify end of corrupted CRC/FEC */
#define EOD				        0x0e					/* End of data */
#define NEXT			        0x10					/* Next Octet */
#define REQTPU		        0x13					/* Request Test Parameters update */
#define ERR				        0x14					/* Error */

/* Read/ Write Registers */
#define WRITE_REG1        0x2A          /* Vendor Discretionary Register */
#define WRITE_REG2        0x2C          /* Line Attenuation Register */

/* Read only Commands */
#define VENDOR_ID		      0x40		      /* VTU-R vendor ID */
#define VENDOR_REVNO	    0x43		      /* VTU-R Revision Number */
#define VTUR_SRNO		      0x45		      /* VTU-R Serial number */
#define SLFTST_RESULTS	  0x46		      /* Self Test Results */
#define VENDOR_REG1       0x49          /* Vendor Discretionary. */
#define VENDOR_REG2       0x4A          /* Vendor Discretionary. */
#define LINE_ATTEN		    0x4c		      /* Line Attenuation */
#define SNR_MARGIN		    0x4f		      /* SNR Margin */
#define VTUR_CONFIG		    0x51		      /* VTU-R Configuration */

/* Reserved Read only registers */
#define RESV_READ_REG1		0x52
#define RESV_READ_REG2		0x54
#define RESV_READ_REG3		0x57
#define RESV_READ_REG4		0x58
#define RESV_READ_REG5		0x5b
#define RESV_READ_REG6		0x5d
#define RESV_READ_REG7		0x5e

/* Reserved Write registers (Some of these registers are Read Only and
 * cannot be written to currently.) */
#define RESV_WRITE_REG1		0x20
#define RESV_WRITE_REG2		0x23
#define RESV_WRITE_REG3		0x25
#define RESV_WRITE_REG4		0x26
#define RESV_WRITE_REG5		0x29
#define RESV_WRITE_REG6		0x2F
#define RESV_WRITE_REG7		0x31
#define RESV_WRITE_REG8		0x32
#define RESV_WRITE_REG9		0x34
#define RESV_WRITE_REG10	0x37
#define RESV_WRITE_REG11	0x38
#define RESV_WRITE_REG12	0x3B
#define RESV_WRITE_REG13	0x3D
#define RESV_WRITE_REG14	0x3E

/*	Undefined codes. Should not be used. Reserved for future use. The VTU-R
	sends UTC command for these commands and enters into UTC state. 
*/
#define RESV_CODE1		    0x15
#define RESV_CODE2		    0x16
#define RESV_CODE3		    0x80
#define RESV_CODE4		    0x83
#define RESV_CODE5		    0x85
#define RESV_CODE6		    0x86
#define RESV_CODE7		    0x89
#define RESV_CODE8		    0x8a
#define RESV_CODE9		    0x8c
#define RESV_CODE10		    0x8f

#define DATA 0xF9

#define RESERVED          0x00
#define MAX_EOC_COMMANDS  46
#define MAX_OHM_COMMANDS  16

int EocCommands[MAX_EOC_COMMANDS] = {
	 RESERVED, HOLD, RTN, SLFTST, REQCOR, REQEND,
	 NOTCOR, NOTEND, EOD, REQTPU, NEXT,
	 RESERVED, DATA, RESERVED, RESV_WRITE_REG1,
	 RESV_WRITE_REG2, RESV_WRITE_REG3, RESV_WRITE_REG4,
	 RESV_WRITE_REG5, WRITE_REG1, WRITE_REG2, 
	 RESV_WRITE_REG6, RESV_WRITE_REG7,
	 RESV_WRITE_REG8, RESV_WRITE_REG9,
	 RESV_WRITE_REG10, RESV_WRITE_REG11,
	 RESV_WRITE_REG12, RESV_WRITE_REG13,
	 RESV_WRITE_REG14, VENDOR_ID,
	 VENDOR_REVNO, VTUR_SRNO, SLFTST_RESULTS,
	 VENDOR_REG1, VENDOR_REG2, LINE_ATTEN,
	 SNR_MARGIN, VTUR_CONFIG, RESV_READ_REG1, RESV_READ_REG2,
   RESV_READ_REG3, RESV_READ_REG4, RESV_READ_REG5, RESV_READ_REG6, RESV_READ_REG7

};

char *get_eoc_state[5] = { 
     "IDLE",   
     "MESSAGE_ECHO",
		 "UTC STATE",
		 "DATAREAD",
		 "DATAWRITE"
};

char *get_latch_state[3] = {

	 "NORMAL",
	 "REQCOR",
	 "NOTCOR"
};



/* The EOC Loopback response	*/
/* Used as the callback fucntion for EOC Stream Receive: iposCbEocDataRelay	*/
const U8   eocLbPkt[]=
{		  
	0,1,2,3,4,5,6,7,8,9,
	10,11,12,13,14,15,16,17,18,19,
	20,21,22,23,24,25,26,27,28,29,
	30,31,32,33,34,35,36,37,38,39,
	40,41,42,43,44,45,46,47,48,49,
	50,51,52,53,54,55,56,57,58,59,
	60,61,62,63,64,65,66,67,68,69,
	70,71,72,73,74,75,76,77,78,79,
	80,81,82,83,84,85,86,87,88,89,
	90,91,92,93,94,95,96,97,98,99,
	100,
};

void appEocValidateData(int port, int valid)
{
  int start, stop;

  if ((port > 0) && (port <= MAX_NUM_OF_PORTS))
  {
    start = port;
    stop = port;
  }
  else
  {
    start = 1;
    stop = MAX_NUM_OF_PORTS;
  }
  do
  {
    dataValid[start] = valid;
  } while (++start <= stop);
}

static void
appEocStdEntry( ipos_port_id pid, U16 eocProtocol, U8 *data, int len )
{
	pIposEocPerProtocol	perProtocolAddr = iposEocGetPerProtocol( eocProtocol );

	if (perProtocolAddr != NULL)
	  (perProtocolAddr->pRemoteCb)( pid, IPOS_SUCCESS, data, len );
}

void	appEocMsgParser(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{
	U16	eocProtocol;

	if (virtualMessage1Filter( data, len ) != 0)
	  eocProtocol = EOC_VIRTUAL_MESSAGE_1;
	else
	  eocProtocol = data[ EOC_CTL_B ];

	//printf ("data[EOC_CTL_B] %x\n",data[EOC_CTL_B]);
#ifdef TRACE_EOC
	printf( "%d %d %d %d %d, length = %d\n", data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], len );
#endif

	switch (eocProtocol)
	{

	case	EOC_LOOPBACK_RESP:
		appEocLbResult(pid, uid, upar, len, data);
		break;
	case 	EOC_LOOPBACK_REQ:
		appEocLbResp(pid, uid, upar, len, data);
		break;
	case EOC_FAR_END_COUNTERS_REQ:
		appEocFeCntrResp (pid, uid, upar, len, data);
		break;
	case EOC_FAR_END_COUNTERS_RESP:
		appEocFeCntrResult (pid, uid, upar, len, data);
		break;
	case EOC_REQ_FAR_END_SNR_ATTN:
		appEocFeSnrAttnResp (pid, uid, upar, len, data);
		break;
	case EOC_RESP_FAR_END_SNR_ATTN:
		appEocFeSnrAttnResult (pid, uid, upar, len, data);
		break;
#ifdef INI_SUPPORT 
	case EOC_ENET_STATUS_RESP:
		appEocFeEnetStatus (pid, uid, upar, len, data);
		break;
	case EOC_PTMF_ADD_MAC_REQ:
		appEocCpeAddMacResp (pid, uid, upar, len, data);
		break;
	case EOC_PTMF_REMOVE_MAC_REQ:
		appEocCpeRemoveMacResp (pid, uid, upar, len, data);
		break;
	case EOC_PTMF_SHOW_MAC_REQ:
		appEocCpeShowMacResp (pid, uid, upar, len, data);
		break;
	case EOC_PTMF_SHOW_MAC_RESP:
		appEocCpeShowMacComplete (pid, uid, upar, len, data);
		break;

	case EOC_PTMF_CONFIG_MAC_REQ:
		appEocCpeConfigMacResp (pid, uid, upar, len, data);
		break;

  case EOC_PTMF_WRITE_CONFIG_REQ:
    appEocCpeConfigExtendMacResp (pid, uid, upar, len, data);
    break;

  case EOC_PTMF_READ_CONFIG_REQ:
    appEocCpeReadConfigMacResp (pid, uid, upar, len, data);
    break;

  case EOC_PTMF_READ_CONFIG_RESP:
    appEocReadConfigMacComplete (pid, uid, upar, len, data);
    break;

  case EOC_PTMF_FLUSH_LEARN_ADDR_REQ:
    appEocCpeFlushLearnedAddrResp (pid, uid, upar, len, data);
    break;
#endif //INI_SUPPORT 
#ifdef	USE_RFM
	case  EOC_RFM_PROTOCOL:
#ifdef	VTU_O
		iposRFMCOEntry(pid, data);
#endif

#ifdef	VTU_R
		iposRFMCPEEntry(pid, data);
#endif		  
	
  		break;
#endif

	case  EOC_ELM_PROTOCOL:
#ifdef	VTU_O
		iposELMCOEntry(pid, data);
#endif
#ifdef	VTU_R
		iposELMCPEEntry(pid, data);
#endif		  
  		break;

	default:
		appEocStdEntry( pid, eocProtocol, data, len );
		break;
	}

	return;
}
																	 

/* handling the EOC loopback msg	*/
																	 
void	appEocLbResp(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{


	/* if receive a eoc_loopback_req msg: 	*/

	if(data[EOC_CTL_B]==EOC_LOOPBACK_REQ)
	{

	/* change the ctrl byte to eoc_loopback_resp	*/
		data[EOC_CTL_B]=EOC_LOOPBACK_RESP;

/* For EOC loopback testing */

#ifdef VTU_R
		if (data[ EOC_LB_MAGIC_B ] == EOC_LB_MAGIC) {
			appEocLbStressResp( pid, len, data );
			return;
		}
#endif

	/* send iposEocDataStream	*/
		iposEocSendDataStream(pid, len, data, 0,0, NULL);

	}

}

void	appEocLbResult(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{

	int i;
	if(data[EOC_CTL_B]==EOC_LOOPBACK_RESP)
	{

#ifdef	NOTUSED
		/* compare the result	*/
		for(i=1;i<101;i++)
		{
			if(data[i+EOC_CTL_B]!=eocLbPkt[i])	break;

		}

		if(i==100) 
		{
			printf(" EOC LB Failed	\n");
			return;
		}
		
		printf("EOC LB SUCCESS\n");
#endif

/* For EOC loopback testing */

#ifdef VTU_O
		if (data[ EOC_CTL_B + 1 ] == EOC_LB_MAGIC) {
			appEocLbStressResult( pid, len, data );
			return;
		}
#endif
		printf ("\nb%ip%i Receive EOC Loopback Response",pid.bmeNum,pid.portNum);
		printf ("\neoc: ");
		for (i=0;i<100;i++)
		{
			if (data[i+EOC_CTL_B+1]!=eocLbPkt[i])
			{
				printf ("\nEOC loopback fail at index %i real_val: %x expect_val: %x",i,
								data[i+EOC_CTL_B+1],eocLbPkt[i]);

					break;
			}
			printf (" %i",data[i+EOC_CTL_B+1]);
		}

		if (i==100) printf ("\nEOC loopback successful\n");

		printf ("%s ",PROMPT);

	}

}


/* Initiating EOC loopback request	*/
void	appEocLbReq(ipos_port_id	pid)
{
    U8	msg[102];


if (oampGetPortState(pid)==uSHOWTIME)
	{

    /* construct the data stream msg 	*/
	memcpy(msg+1,eocLbPkt,sizeof(eocLbPkt));
	msg[EOC_CTL_B]=EOC_LOOPBACK_REQ;
    
	iposEocSendDataStream(pid, sizeof(eocLbPkt)+1, msg, 0,0,NULL);

	}
else
	{
	printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);

	}	



}

/* Initiating FE cntr request	*/
void	appEocFeCntrReq(ipos_port_id	pid)
{
    U8	msg[1];

	if (oampGetPortState(pid)==uSHOWTIME)
	{
//    printf("\n b%dp%d get FE counters.",pid.bmeNum, pid.portNum);
		msg[EOC_CTL_B]=EOC_FAR_END_COUNTERS_REQ;
    	iposEocSendDataStream(pid, 1, msg, 0,0,NULL);
	}
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}	
}


void	appEocFeCntrResp(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{

#ifdef INI_SUPPORT

  U32   uiPtmfRxFrames;
  U32   uiPtmfTxFrames;
  U32   uiPtmfTxCrcErrors;
  U32   uiPtmfRxCrcErrors;
  U32   uiPtmfRxDroppedFrames;
  int   lineNum, ptmfPort;

#endif
  
	if (data[EOC_CTL_B]==EOC_FAR_END_COUNTERS_REQ)
	{
    /* construct the data stream msg 	*/
	data[EOC_CTL_B]=EOC_FAR_END_COUNTERS_RESP;

	memcpy (&data[EOC_CTL_B+1],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeCRC_S,2);

	memcpy (&data[EOC_CTL_B+3],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeCRC_F,2);
	//printf ("\nNeCRC_F %i",oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeCRC_F);

	memcpy (&data[EOC_CTL_B+5],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeLOS,1);
	//printf ("\nNeLOS %i",oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeLOS);
	
	memcpy (&data[EOC_CTL_B+6],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFEC_S,4);

	memcpy (&data[EOC_CTL_B+10],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFEC_F,4);

#ifdef INI_SUPPORT
//  #ifndef P2CO
    getLineNum (pid, &lineNum);
    getIniPhy (lineNum, &ptmfPort);

    uiPtmfRxFrames = iposPtmfEnetTxFrames (ptmfPort);
    uiPtmfTxFrames = iposPtmfEnetRxFrames (ptmfPort);
    uiPtmfTxCrcErrors = iposPtmfEnetRxCrcErrors (ptmfPort);
    uiPtmfRxCrcErrors = iposPtmfHdlcCrcErrors (ptmfPort);
    uiPtmfRxDroppedFrames = iposPtmfHdlcDroppedFrames(ptmfPort);

	  memcpy (&data[EOC_CTL_B+14],&uiPtmfTxFrames,4);
	  memcpy (&data[EOC_CTL_B+18],&uiPtmfRxFrames,4);
	  memcpy (&data[EOC_CTL_B+22],&uiPtmfTxCrcErrors,4);
	  memcpy (&data[EOC_CTL_B+26],&uiPtmfRxCrcErrors,4);
	  memcpy (&data[EOC_CTL_B+30],&uiPtmfRxDroppedFrames,4);
//  #endif //P2CO
#endif //INI_SUPPORT
    
    memcpy (&data[EOC_CTL_B+34],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeSEF,2);
	memcpy (&data[EOC_CTL_B+36],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFECUnCrr_F,4);
	memcpy (&data[EOC_CTL_B+40],&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFECUnCrr_S,4);

	iposEocSendDataStream(pid, 44, data, 0,0,NULL);

	}

}

void	appEocFeCntrResult(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{
	int portn;

	/* Copy msg to far end counters */

	if (data[EOC_CTL_B]==EOC_FAR_END_COUNTERS_RESP)
	{
    getLineNum(pid,&portn);

	  memcpy (&feCounters[portn].FeCRC_S,&data[EOC_CTL_B+1],2);

	  memcpy (&feCounters[portn].FeCRC_F,&data[EOC_CTL_B+3],2);

	  memcpy (&feCounters[portn].FeFLOS,&data[EOC_CTL_B+5],1);

	  memcpy (&feCounters[portn].FeFEC_S,&data[EOC_CTL_B+6],4);

	  memcpy (&feCounters[portn].FeFEC_F,&data[EOC_CTL_B+10],4);

	  memcpy (&feCounters[portn].TxFrameCnt,&data[EOC_CTL_B+14],4);
	  memcpy (&feCounters[portn].RxFrameCnt,&data[EOC_CTL_B+18],4);
	  memcpy (&feCounters[portn].TxCrcCnt,&data[EOC_CTL_B+22],4);
	  memcpy (&feCounters[portn].RxCrcCnt,&data[EOC_CTL_B+26],4);
	  memcpy (&feCounters[portn].DropFrameCnt,&data[EOC_CTL_B+30],4);
	  memcpy (&feCounters[portn].FeSEF,&data[EOC_CTL_B+34],2);
	  memcpy (&feCounters[portn].FeFECUnCrr_F,&data[EOC_CTL_B+36],4);
      memcpy (&feCounters[portn].FeFECUnCrr_S,&data[EOC_CTL_B+40],4);

    dataValid[portn] |= 1;
  }
}

void	appEocFeCntr(ipos_port_id	pid)
{
	int portn;

  getLineNum(pid,&portn);
	if (oampGetPortState(pid)==uSHOWTIME)
	{
    if (dataValid[portn] & 0x1)
    {
      printf("\nFar end Counters for Port %d:", portn);
      printf ("\nFeFEC_F: %lu, FeCRC_F: %u, FeFEC_S: %lu, FeCRC_S: %u, FeFLOS: %u, FeSEF: %u\n",
              feCounters[portn].FeFEC_F,feCounters[portn].FeCRC_F,
              feCounters[portn].FeFEC_S,feCounters[portn].FeCRC_S,
              feCounters[portn].FeFLOS,feCounters[portn].FeSEF);
	  printf ("FeFECUnCrr_F: %lu, FeFECUnCrr_S: %lu\n",
		      feCounters[portn].FeFECUnCrr_F,feCounters[portn].FeFECUnCrr_S);

      printf ("\nINI Far end Counters for Port %d:",portn);
      printf ("\nTX_FRAME_CNT: %lu", feCounters[portn].TxFrameCnt);
      printf ("            RX_FRAME_CNT: %lu", feCounters[portn].RxFrameCnt);
      printf ("\nTX_CRC_FRAME_CNT: %lu", feCounters[portn].TxCrcCnt);
      printf ("      RX_CRC_FRAME_CNT: %lu", feCounters[portn].RxCrcCnt);
      printf ("\nDROP_FRAME_CNT: %lu", feCounters[portn].DropFrameCnt);
    }
    else
      printf("\n b%dp%d Far End counter data not valid.",pid.bmeNum, pid.portNum);
	}
	else
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	printf(PROMPT);
}
#ifdef INI_SUPPORT
void appEocFeEnetStatus(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{
   if (data[EOC_CTL_B]==EOC_ENET_STATUS_RESP)
   {
	   if(data[EOC_CTL_B+1] == 2)
	   {
		   printf("\n Remote Ethernet Link on bme%d port%d is UP\n",pid.bmeNum,pid.portNum);
		   if(data[EOC_CTL_B+2] == 2 )
			   printf(" Auto Negotiation ON\n");
		   if (data[EOC_CTL_B+2] == 1)
               printf(" Fixed Mode\n");
           if(data[EOC_CTL_B+3] == ENET_LINK_HALF_DUPLEX)
			   printf(" Link is HALF Duplex\n");
		   if (data[EOC_CTL_B+3] == ENET_LINK_FULL_DUPLEX)
               printf(" Link is FULL Duplex\n");
		   if(data[EOC_CTL_B+4] == ENET_LINK_10_MBPS)
			   printf(" Speed = 10 Mbps\n");
		   if (data[EOC_CTL_B+4] == ENET_LINK_100_MBPS)
               printf(" Speed = 100 Mbps\n");
	   }
	   if(data[EOC_CTL_B+1] == 1)
           printf("\n Remote Ethernet Link on bme%d port%d is DOWN\n",pid.bmeNum,pid.portNum);
   }
   printf(PROMPT);
}
#endif
#if defined (BME_CPE_20) && defined (INI_SUPPORT)
void appEocRemoteEnetStatus( ipos_port_id pid)
{
	U32 value32;
	U8	msg[5];
	int ptmfStatus, ptmfIndex, errCode, lineNum;
	getLineNum( pid, &lineNum );
	errCode = getIniPhy( lineNum, &ptmfIndex );
	if (errCode != IPOS_SUCCESS)
	{
		printf( "\nProblem getting the PTMF index for port b%dp%d\n",
				   pid.bmeNum, pid.portNum);
	}
	else
	{
	    ptmfStatus = iposPtmfGetConfigParam( ptmfIndex, ENET_LINK_EN, &value32 );
	    if (value32 != prevVal)
		{
		   prevVal = value32;
           msg[EOC_CTL_B]   = EOC_ENET_STATUS_RESP;
		   msg[EOC_CTL_B+1] = value32;
           ptmfStatus = iposPtmfGetConfigParam( ptmfIndex, ENET_AUTO_NEG, &value32 );
		   msg[EOC_CTL_B+2] = value32;
		   ptmfStatus = iposPtmfGetConfigParam( ptmfIndex, ENET_LINK_DUPLEX, &value32 );
		   msg[EOC_CTL_B+3] = value32;
		   ptmfStatus = iposPtmfGetConfigParam( ptmfIndex, ENET_LINK_SPEED, &value32 );
		   msg[EOC_CTL_B+4] = value32;
		   ptmfStatus = iposPtmfGetConfigParam( ptmfIndex, ENET_LINK_FLOW_CONTROL, &value32 );
		   msg[EOC_CTL_B+5] = value32;
           iposEocSendDataStream(pid, 6, msg, 0,0,NULL);
		}
	}	
}
#endif
/* Initiating FE cntr request	*/
void	appEocFeSnrAttnReq(ipos_port_id	pid)
{
    U8	msg[1];

	if (oampGetPortState(pid)==uSHOWTIME)
	{
		/* construct the data stream msg 	*/
		msg[EOC_CTL_B]=EOC_REQ_FAR_END_SNR_ATTN;
    
		iposEocSendDataStream(pid, 1, msg, 0,0,NULL);
	}
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);

	}	

}

/******************************************************************************/
void	appEocFeSnrAttnResp(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{

  if (data[EOC_CTL_B]==EOC_REQ_FAR_END_SNR_ATTN)
	{
    /* Retrieve Near end SNR Attenuation */
	  if(oampGetPortState(pid)==uSHOWTIME)
		{			
	    ipos_msg_buf	    *pBuf;
	    oamp_cb_msg_snr		*pMsg;

     	pBuf=iposMsgGet();

      if(pBuf==NULL)
	    {
		    printf("Failed to allocate the msg buffer in FE SNR Attn\n");
		    return;
	    }
     	pBuf->len=sizeof(oamp_cb_msg_snr);

      pMsg=(oamp_cb_msg_snr *) pBuf->pDataBuf;
	    pMsg->portId  = pid;
	    pMsg->uid     = uid;
	    pMsg->parLen  = len;
	    pMsg->cntRpt  = 1;

	    if(len !=0 && data !=NULL)
	    {
//        printf("Mem copy in FE SNR Attn\n");
		    memcpy(pMsg->par, data, len);
	    }

	    if(appOampJobAdd(TID_BLKFUNC, portFeSnrJob, 0, 0, pBuf)!=IPOS_SUCCESS)
	    {
			iposMsgFree(pBuf);
			printf("Failed to add job to the oamp task1\n");
	    }
    } 
    else
    {
      printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
    }
  }
}

/******************************************************************************/
void	portFeSnrJob(U32 arg1, U32 arg2, ipos_msg_buf *pBuf)
{
	ipos_port_id	    pid;
	oamp_cb_msg_snr		*pMsg;
  U32               cntRpt;

	if(pBuf==NULL || pBuf->len==0)
	{
		printf("No Msgbuf in FeSnrJob \n");
		return;
	}

	pMsg=(oamp_cb_msg_snr *) pBuf->pDataBuf;
	
	pid=pMsg->portId;

	cntRpt=1;
	iposGetNeSNRAttn(pid, 0, cntRpt, portNeSnrCompleteRemote);

	// release the message	
	iposMsgFree(pBuf);
}

/******************************************************************************/

void	appEocFeSnrAttnResult(ipos_port_id	pid, U8 uid, U32 upar, int len, U8 *data)
{
#ifndef POLL_FE_SNR
	S32	FeSnrMargin;
#endif
	int portn;

	if (data[EOC_CTL_B]==EOC_RESP_FAR_END_SNR_ATTN)
	{
    getLineNum(pid,&portn);
		memcpy (&feSnrAttn[portn].FeSnrMargin,&data[EOC_CTL_B+1],4);
		memcpy (&feSnrAttn[portn].FeAttn,&data[EOC_CTL_B+5],4);
    dataValid[portn] |= 0x2;
#ifndef POLL_FE_SNR
    printf ("\nGet FE SNR Margin for Bme: %d Port %d",pid.bmeNum,pid.portNum);
    printf ("\n=================");
    printf ("\nSNR Margin: ");

    FeSnrMargin = feSnrAttn[portn].FeSnrMargin;
    if (FeSnrMargin < 0)
    {
    	FeSnrMargin *= -1;
    	printf("-");
    }
    printf ("%ld.%ld dB",(FeSnrMargin / 10),(FeSnrMargin % 10));
		
		printf ("\nAttenuation: ");
    printf ("%ld.%ld dB",(feSnrAttn[portn].FeAttn / 10),
            (feSnrAttn[portn].FeAttn % 10));
    printf(PROMPT);
#endif
	}
}

#ifdef POLL_FE_SNR
void	appEocFeSnrAttn(ipos_port_id	pid)
{
	S32	FeSnrMargin;
	int portn;

  getLineNum(pid,&portn);
	if (oampGetPortState(pid)==uSHOWTIME)
	{
    if (dataValid[portn] & 0x2)
    {
      printf ("\nGet FE SNR Margin for Bme: %d Port %d",pid.bmeNum,pid.portNum);
      printf ("\n=================");
      printf ("\nSNR Margin: ");

      FeSnrMargin = feSnrAttn[portn].FeSnrMargin;
      if (FeSnrMargin < 0)
      {
    	  FeSnrMargin *= -1;
    	  printf("-");
      }
      printf ("%ld.%ld dB",(FeSnrMargin / 10),(FeSnrMargin % 10));
		
		  printf ("\nAttenuation: ");
      printf ("%ld.%ld dB",(feSnrAttn[portn].FeAttn / 10),
              (feSnrAttn[portn].FeAttn % 10));
    }
    else
      printf("\n b%dp%d Far End SNR data not valid.",pid.bmeNum, pid.portNum);
	}
	else
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
		printf(PROMPT);
}
#endif

void copyCountersToOamp (ipos_port_counters *pReport,ipos_port_id pid)
{

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFEC_S,&pReport->NeFEC_S
		,sizeof(pReport->NeFEC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFEC_F,&pReport->NeFEC_F
		,sizeof(pReport->NeFEC_F));

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeCRC_S,&pReport->NeCRC_S
		,sizeof(pReport->NeCRC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeCRC_F,&pReport->NeCRC_F
		,sizeof(pReport->NeCRC_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeLOS,&pReport->NeLOS
		,sizeof(pReport->NeLOS));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeSEF,&pReport->NeSEF
		,sizeof(pReport->NeSEF));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeLOM,&pReport->NeLOM
		,sizeof(pReport->NeLOM));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeNCD_S,&pReport->NeNCD_S
		,sizeof(pReport->NeNCD_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeOCD_S,&pReport->NeOCD_S
		,sizeof(pReport->NeOCD_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeOCD_F,&pReport->NeOCD_F
		,sizeof(pReport->NeOCD_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeHEC_S,&pReport->NeHEC_S
		,sizeof(pReport->NeHEC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeHEC_F,&pReport->NeHEC_F
		,sizeof(pReport->NeHEC_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeBER_S,&pReport->NeBER_S
		,sizeof(pReport->NeBER_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeBER_F,&pReport->NeBER_F
		,sizeof(pReport->NeBER_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFECUnCrr_S,&pReport->NeFECUnCrr_S
		,sizeof(pReport->NeFECUnCrr_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.NeFECUnCrr_F,&pReport->NeFECUnCrr_F
		,sizeof(pReport->NeFECUnCrr_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numUsrCell_S,&pReport->numUsrCell_S
		,sizeof(pReport->numUsrCell_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numUsrCell_F,&pReport->numUsrCell_F
		,sizeof(pReport->numUsrCell_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numIdlCell_S,&pReport->numIdlCell_S
		,sizeof(pReport->numIdlCell_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numIdlCell_F,&pReport->numIdlCell_F
		,sizeof(pReport->numIdlCell_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numTxBlk_S,&pReport->numTxBlk_S
		,sizeof(pReport->numTxBlk_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numUsrCell_S,&pReport->numUsrCell_S
		,sizeof(pReport->numUsrCell_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numTxBlk_F,&pReport->numTxBlk_F
		,sizeof(pReport->numTxBlk_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numRxBlk_S,&pReport->numRxBlk_S
		,sizeof(pReport->numRxBlk_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.numRxBlk_F,&pReport->numRxBlk_F
		,sizeof(pReport->numRxBlk_F));

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeFEC_S,&pReport->FeFEC_S
		,sizeof(pReport->FeFEC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeFEC_F,&pReport->FeFEC_F
		,sizeof(pReport->FeFEC_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeCRC_S,&pReport->FeCRC_S
		,sizeof(pReport->FeCRC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeCRC_F,&pReport->FeCRC_F
		,sizeof(pReport->FeCRC_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeLOS,&pReport->FeLOS
		,sizeof(pReport->FeLOS));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeRDI,&pReport->FeRDI
		,sizeof(pReport->FeRDI));

         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeFecEs_S,&pReport->FeFecEs_S
           ,sizeof(pReport->FeFecEs_S));
         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeEs_S,&pReport->FeEs_S
           ,sizeof(pReport->FeEs_S));
         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeSEs_S,&pReport->FeSEs_S
           ,sizeof(pReport->FeSEs_S));
         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeLosEs_S,&pReport->FeLosEs_S
           ,sizeof(pReport->FeLosEs_S));
         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeUnAvlEs_S,&pReport->FeUnAvlEs_S
           ,sizeof(pReport->FeUnAvlEs_S));
         memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeBER_S,&pReport->FeBER_S
           ,sizeof(pReport->FeBER_S));

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeOCD_S,&pReport->FeOCD_S
		,sizeof(pReport->FeOCD_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeOCD_F,&pReport->FeOCD_F
		,sizeof(pReport->FeOCD_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeHEC_S,&pReport->FeHEC_S
		,sizeof(pReport->FeHEC_S));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeHEC_F,&pReport->FeHEC_F
		,sizeof(pReport->FeHEC_F));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeLPR,&pReport->FeLPR
		,sizeof(pReport->FeLPR));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FeLOM,&pReport->FeLOM
		,sizeof(pReport->FeLOM));
	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].Counters.FePO,&pReport->FePO
		,sizeof(pReport->FePO));
}

void copySnrAttnToOamp  (ipos_port_nesnrattn *pReport,ipos_port_id pid)
{

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].SnrAttn.SnrMargin,&pReport->SnrMargin
		,sizeof(pReport->SnrMargin));

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].SnrAttn.SnrAvgMargin,&pReport->SnrAvgMargin
		,sizeof(pReport->SnrAvgMargin));

	memcpy (&oampBme[pid.bmeNum].oampPort[pid.portNum].SnrAttn.Attn,&pReport->Attn
		,sizeof(pReport->Attn));
}

void eocInit( void )
{
	ipos_port_id	pid;

	iposTmrInit();

for (pid.bmeNum=1;pid.bmeNum<=MAX_NUM_OF_BMES;pid.bmeNum++)
for (pid.portNum=1;pid.portNum<=MAX_PORTS_PER_BME;pid.portNum++) {
	iposSetCbEocDataStream(pid, 0, appEocMsgParser);
    iposSetCbEocEventLog(pid, 0, (void *)add_EocEventLog);
}

/* For EOC loopback testing */

	appEocLbResetStress( 0 );

	appEocProtocolVersionInit();
	appRMMInit();
	appVirtualMessage1Init();
	clear_EocEventLog(pid);
}



void portNeSnrCompleteRemote(ipos_port_id portId, U8 UID,U32 cntRpt, int status,  
							  ipos_port_nesnrattn *par)
{
	int	len;
	len=sizeof(ipos_port_nesnrattn);
	addCompletionJob(portId, UID, cntRpt, status, (U8 *) par, len,portNeSnrJobRemote);
}


/* the complete function running in the oamp task	*/
static	void	portNeSnrJobRemote(int arg1, int arg2, ipos_msg_buf	*pBuf)
{
	
	oamp_cb_msg_snr		*pMsg;
	ipos_port_id	pid;
	ipos_port_nesnrattn	*pNeSnr;

	U32		cntRpt;
	U8		cmdTag;
	int		errCode;
	char	funcName[]="iposPortNeSnr";
	U8 		data[20];


	if(pBuf==NULL)
	{
		printf("Invalid msg buffer in iposPortNeSnr Callback \n");
		return;
	}

	/* parse the message	*/
	pMsg=(oamp_cb_msg_snr *) pBuf->pDataBuf;

	pid		=pMsg->portId;
	cntRpt	=pMsg->cntRpt;
	cmdTag	=pMsg->uid;
	errCode =pMsg->status;
	
	pNeSnr=(ipos_port_nesnrattn *) pMsg->par;

	/* update the state		*/
	if(pMsg->status==IPOS_SUCCESS)
	{

		uiLog(pid,funcName,cmdTag,OAMP_COMPLETE, errCode);
		oampStateUpdate(pid,ePORT_STATUS_BRIEF);
		copySnrAttnToOamp(pNeSnr,pid);
		/* construct the data stream msg 	*/
		data[EOC_CTL_B]=EOC_RESP_FAR_END_SNR_ATTN;

		memcpy (&data[EOC_CTL_B+1],
						&oampBme[pid.bmeNum].oampPort[pid.portNum].SnrAttn.SnrAvgMargin,4);
		memcpy (&data[EOC_CTL_B+5],
						&oampBme[pid.bmeNum].oampPort[pid.portNum].SnrAttn.Attn,4);

		iposEocSendDataStream(pid, 9, data, 0,0,NULL);

	}
	else
	{
		uiLog(pid,funcName,cmdTag,OAMP_FAILED, errCode);
		oampStateUpdate(pid,CMD_FAILED);
	}


	/* release the message	*/
	iposMsgFree(pBuf);

}
#ifdef INI_SUPPORT 
/******************************************************************************/
/* ETHERNET ADDRESS FILTERING EOC COMMAND (REQUESTS TO REMOTE CPE FROM CO)    */
/******************************************************************************/
/* Try to send EOC message to configure the remote CPE's Ethernet Address     */
/* filtering settings (Just the base settings/ Backward Compatible with       */
/* 3.0.15x)                                                                   */
/******************************************************************************/
void appEocConfigMacReq (
        ipos_port_id          pid,
        tsIposPtmfEnetAddrFilterCfg  *ptsPtmfAddrFilTab )
{
  U8  msg[6];

  printf("\n EOC CPE CONFIG MAC REQUEST \n");

	if (oampGetPortState(pid)==uSHOWTIME)
	{
    /* construct the data stream msg 	*/
	  msg[EOC_CTL_B]    = EOC_PTMF_CONFIG_MAC_REQ;

    // Ethernet Address filter config structure copied to message buffer
    msg[EOC_CTL_B+1]  = ptsPtmfAddrFilTab->bAddrFilterEn;
    msg[EOC_CTL_B+2]  = ptsPtmfAddrFilTab->bLearningEn;
    msg[EOC_CTL_B+3]  = ptsPtmfAddrFilTab->bBroadCastFilterEn;
    msg[EOC_CTL_B+4]  = ptsPtmfAddrFilTab->bMultiCastFilterEn;
    msg[EOC_CTL_B+5]  = ptsPtmfAddrFilTab->bStaticAddrCount;

#if 0
    msg[EOC_CTL_B+6]  = ptsPtmfAddrFilTab->bAgingEn;
    msg[EOC_CTL_B+7]  = (ptsPtmfAddrFilTab->uiAgingCount & 0xff);
    msg[EOC_CTL_B+8]  = (ptsPtmfAddrFilTab->uiAgingCount >> 8) & 0xff;
    msg[EOC_CTL_B+9]  = ptsPtmfAddrFilTab->uiAddrEntryEn & 0xff;
    msg[EOC_CTL_B+10] = (ptsPtmfAddrFilTab->uiAddrEntryEn >> 8) & 0xff;
    msg[EOC_CTL_B+11] = ptsPtmfAddrFilTab->bMaxReadCount;
#endif

	  iposEocSendDataStream(pid, 6, msg, 0,0,NULL);
	}
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}
}

/******************************************************************************/
/* Try to send EOC message to configure the remote CPE's Ethernet Address     */
/* filtering settings (All settings including the Static Addresses in table)  */
/******************************************************************************/
void appEocConfigExtendMacReq (
        ipos_port_id          pid,
        tsIposPtmfEnetAddrFilterCfg  *ptsPtmfAddrFilTab )
{

  U8  msg[sizeof(tsIposPtmfEnetAddrFilterCfg) + 1];

  printf("\n EOC CPE CONFIG EXTENDED MAC REQUEST \n");

	if (oampGetPortState(pid) == uSHOWTIME)
	{
    /* construct the data stream msg 	*/
	  msg[EOC_CTL_B]    = EOC_PTMF_WRITE_CONFIG_REQ;

    // Ethernet Address filter config structure copied to message buffer
    memcpy (&msg[EOC_CTL_B+1], 
            ptsPtmfAddrFilTab,
            sizeof(tsIposPtmfEnetAddrFilterCfg));

	  iposEocSendDataStream(pid, 
                          sizeof(tsIposPtmfEnetAddrFilterCfg), 
                          msg, 0,0,NULL);
	}
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}
}


/******************************************************************************/
/* Try to send EOC message to read the ehernet address filtering address from */
/* the remote CPE                                                             */
/******************************************************************************/
void appEocCpeShowMacReq (ipos_port_id pid)
{
  U8	msg[1];

	if (oampGetPortState(pid)==uSHOWTIME)
	{
    printf("\n EOC CPE READ MAC ADDR REQUEST \n");
    /* construct the data stream msg 	*/
    msg[EOC_CTL_B]    = EOC_PTMF_SHOW_MAC_REQ;
    
    iposEocSendDataStream(pid, 1, msg, 0,0,NULL);
  }
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}
}

/******************************************************************************/
/* Try to send EOC message to add an entry in the static address table of the */
/* remote CPE                                                                 */
/******************************************************************************/
void appEocCpeAddMacReq (ipos_port_id pid, U8 bTableIndex, U8 *pbEnetAddr)
{
  U8	msg[10];

  if (oampGetPortState(pid)==uSHOWTIME)
	{
    printf("\n EOC CPE ADD ADDRESS REQUEST \n");

		/* construct the data stream msg 	*/
	  msg[EOC_CTL_B]    = EOC_PTMF_ADD_MAC_REQ;

    // Copy the 6 bytes of Ethernet Address to the EOC Message Buffer
    memcpy (&msg[EOC_CTL_B+3], pbEnetAddr, 6);

    // Next location after the Ethernet Address is the offet of this entry
    // in the remote CPE's static address table.
	  msg[EOC_CTL_B+9]  = bTableIndex;

	  iposEocSendDataStream(pid, 10, msg, 0,0,NULL);
	}
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}

}

/******************************************************************************/
/* Try to send EOC message to remove an entry in the static address table of  */
/* the remote CPE                                                             */
/******************************************************************************/
void appEocCpeRemoveMacReq (ipos_port_id pid, U8 bTableIndex)
{
  U8	msg[2];

  if (oampGetPortState(pid)==uSHOWTIME)
	{
    
    printf("\n EOC CPE REMOVE ADDRESS REQUEST \n");

    /* construct the data stream msg 	*/
    msg[EOC_CTL_B]    = EOC_PTMF_REMOVE_MAC_REQ;

    msg[EOC_CTL_B+1]  = bTableIndex;
    
    iposEocSendDataStream(pid, 2, msg, 0,0,NULL);
  }
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}
}

/******************************************************************************/
/* Try to send EOC message to read the Ethernet address filtering             */
/* configuration of the remote CPE                                            */
/******************************************************************************/
void appEocCpeReadConfigMacReq (ipos_port_id pid) 
{
  U8	msg[1];

	if (oampGetPortState(pid)==uSHOWTIME)
	{
    printf("\n EOC CPE READ CONFIG REQUEST \n");
   
    /* construct the data stream msg 	*/
    msg[EOC_CTL_B]    = EOC_PTMF_READ_CONFIG_REQ;
    
    iposEocSendDataStream(pid, 1, msg, 0,0,NULL);
  }
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}

}

/******************************************************************************/
/* Request to send EOC message to Flush the Learned address table             */
/* of the remote CPE                                                          */
/******************************************************************************/
void appEocFlushLearnedAddrReq (ipos_port_id pid )
{
  U8	msg[1];

	if (oampGetPortState(pid)==uSHOWTIME)
	{
    printf("\n EOC CPE FLUSH LEARNED ADDRESS REQUEST \n");
   
    /* construct the data stream msg 	*/
    msg[EOC_CTL_B]    = EOC_PTMF_FLUSH_LEARN_ADDR_REQ;
    
    iposEocSendDataStream(pid, 1, msg, 0,0,NULL);
  }
	else
	{
		printf("\n b%dp%d is not in showtime.",pid.bmeNum, pid.portNum);
	}
}

/******************************************************************************/
/* ETHERNET ADDRESS FILTERING EOC COMMAND (RESPONSE)                          */
/******************************************************************************/
/* Response to send EOC message to configure the remote CPE's Ethernet Address*/
/* filtering settings (Just the base settings/ Backward Compatible with       */
/* 3.0.15x)                                                                   */
/******************************************************************************/
void appEocCpeConfigMacResp (ipos_port_id pid,U8 uid,U32 upar,int len,U8 *data)
{
#if defined(VTU_R) && (defined(P2CPE) || defined(BME_CPE_20))

  tsIposPtmfEnetAddrFilterCfg		tsTempEnetAddrFilterConfig;

  printf("\n EOC CPE CONFIG MAC RESPONSE \n");

  iposPtmfReadAddrTabStatus(&tsTempEnetAddrFilterConfig);

  // Fill the Ethernet Address filter config structure from the message buffer
  tsTempEnetAddrFilterConfig.bAddrFilterEn              =  data[EOC_CTL_B+1];  
  tsTempEnetAddrFilterConfig.bLearningEn                =  data[EOC_CTL_B+2];    
  tsTempEnetAddrFilterConfig.bBroadCastFilterEn         =  data[EOC_CTL_B+3];  
  tsTempEnetAddrFilterConfig.bMultiCastFilterEn         =  data[EOC_CTL_B+4];  
  tsTempEnetAddrFilterConfig.bStaticAddrCount           =  data[EOC_CTL_B+5];  

#if 0
  tsTempEnetAddrFilterConfig.bAgingEn                   =  data[EOC_CTL_B+6];  
  
  tsTempEnetAddrFilterConfig.uiAgingCount               =  data[EOC_CTL_B+7];  
  tsTempEnetAddrFilterConfig.uiAgingCount              |=  (data[EOC_CTL_B+8] << 8);  
  tsTempEnetAddrFilterConfig.uiAddrEntryEn              =  data[EOC_CTL_B+9];  
  tsTempEnetAddrFilterConfig.uiAddrEntryEn             |=  (data[EOC_CTL_B+10] << 8);

  tsTempEnetAddrFilterConfig.bMaxReadCount              =  data[EOC_CTL_B+11]; 
#endif //#if 0

	iposPtmfAddrTabInit (&tsTempEnetAddrFilterConfig);
  
  macFilCfgShadow = tsTempEnetAddrFilterConfig;
  nvramUpdateBlk(2);
#endif
}

/******************************************************************************/
/* Response to send EOC message to Read all entries in the static address     */
/* table of the remote CPE                                                    */
/******************************************************************************/
void appEocCpeShowMacResp (ipos_port_id pid, 
                           U8 uid, 
                           U32 upar, 
                           int len, 
                           U8 *data )
{

#if defined(P2CPE) || defined(BME_CPE_20)

  tsIposPtmfEnetAddrFilterCfg		tsEocEnetAddrFilterConfig;
  int iIndex;

  printf("\n EOC CPE SHOW MAC ADDR RESPONSE \n");

	if (data[EOC_CTL_B] == EOC_PTMF_SHOW_MAC_REQ)
	{
    /* construct the data stream msg 	*/
    data[EOC_CTL_B] = EOC_PTMF_SHOW_MAC_RESP;

    iposPtmfReadAddrTabStatus(&tsEocEnetAddrFilterConfig);

    for (iIndex = 0; iIndex < MAX_FILTER_TABLE_ENTRY; iIndex ++)
    {
      // 8 byte Ethernet Address (2 MSB are padded with zeros)
      data[EOC_CTL_B+1 + (iIndex*8)] = 0;
      data[EOC_CTL_B+2 + (iIndex*8)] = 0;
      data[EOC_CTL_B+3 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][0];
      data[EOC_CTL_B+4 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][1];
      data[EOC_CTL_B+5 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][2];
      data[EOC_CTL_B+6 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][3];
      data[EOC_CTL_B+7 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][4];
      data[EOC_CTL_B+8 + (iIndex*8)] = tsEocEnetAddrFilterConfig.abEnetAddr[iIndex][5];
    }
  }
	iposEocSendDataStream(pid, 
                        (MAX_FILTER_TABLE_ENTRY * 8) + 1, 
                        data, 0,0,NULL );

#endif // defined(P2CPE) || defined(BME_CPE_20)
}

/******************************************************************************/
/* Response to send EOC message to add an entry in the static address table   */
/* of the remote CPE                                                          */
/******************************************************************************/
void appEocCpeAddMacResp (ipos_port_id pid, U8 uid, U32 upar, int len, U8 *data)
{

#if defined(P2CPE) || defined(BME_CPE_20)
	U8  bTableIndex;
  U8  abEnetAddr[6];

  printf("\n EOC CPE ADD ADDRESS RESPONSE \n");

	memcpy (abEnetAddr, &data[EOC_CTL_B+3], 6);

  bTableIndex = data[EOC_CTL_B+9];

 	iposPtmfAddAddrEntry (bTableIndex, abEnetAddr);
	
#endif // defined(P2CPE) || defined(BME_CPE_20)
}

/******************************************************************************/
/* Response to send EOC message to remove an entry in the static address table*/
/* of the remote CPE                                                          */
/******************************************************************************/
void appEocCpeRemoveMacResp (ipos_port_id pid, 
                             U8 uid, 
                             U32 upar, 
                             int len, 
                             U8 *data)
{

#if defined(P2CPE) || defined(BME_CPE_20)
	U8  bTableIndex;

  printf("\n EOC CPE REMOVE ADDRESS RESPONSE \n");

  bTableIndex = data[EOC_CTL_B+1];

  iposPtmfRemoveAddrEntry (bTableIndex);

#endif // defined(P2CPE) || defined(BME_CPE_20)
}

/******************************************************************************/
/* Response to send EOC message to Read remote CPE ethernet address filtering */
/* configuration                                                              */
/******************************************************************************/
void appEocCpeReadConfigMacResp ( ipos_port_id pid, 
                                  U8 uid, U32 upar, int len, U8 *data)
{
#if defined(P2CPE) || defined(BME_CPE_20)

  tsIposPtmfEnetAddrFilterCfg		tsEocEnetAddrFilterConfig;

  printf("\n EOC CPE READ CONFIG RESPONSE \n");

	if (data[EOC_CTL_B] == EOC_PTMF_READ_CONFIG_REQ)
	{
    /* construct the data stream msg 	*/
    data[EOC_CTL_B] = EOC_PTMF_READ_CONFIG_RESP;

	  iposPtmfReadAddrTabStatus(&tsEocEnetAddrFilterConfig);

		memcpy (&data[EOC_CTL_B+1], 
            &tsEocEnetAddrFilterConfig, 
            sizeof(tsEocEnetAddrFilterConfig));	
	}
	iposEocSendDataStream(pid, 
                        sizeof(tsEocEnetAddrFilterConfig) + 1 , 
                        data, 0,0,NULL );

#endif // defined(P2CPE) || defined(BME_CPE_20)


}

/******************************************************************************/
/* Complete the show MAC Addresses EOC command. This command is initiated at  */
/* the CO(Show MAC REQ) -> CPE (Show MAC RESP) -> CO (Show MAC Complete)      */
/******************************************************************************/
void appEocCpeShowMacComplete (ipos_port_id pid, 
                               U8 uid, 
                               U32 upar, 
                               int len, 
                               U8 *data )
{
  /*int i, iIndex;	variable i is only referred to in programming that has been commented out */
  int iIndex;

  printf("\n EOC CPE SHOW MAC ADDR RESPONSE-COMPLETE \n");

  for (iIndex = 0; iIndex < MAX_FILTER_TABLE_ENTRY; iIndex ++)
  {
    // 8 byte Ethernet Address (2 MSB are ignored)
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][0] = data[EOC_CTL_B+3 + (iIndex*8)];
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][1] = data[EOC_CTL_B+4 + (iIndex*8)];
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][2] = data[EOC_CTL_B+5 + (iIndex*8)];
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][3] = data[EOC_CTL_B+6 + (iIndex*8)];
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][4] = data[EOC_CTL_B+7 + (iIndex*8)];
    tsEnetAddrFilterConfig.abEnetAddr[iIndex][5] = data[EOC_CTL_B+8 + (iIndex*8)];
  }

/*
  printf ("\n tsIposPtmfEnetAddrFilterCfg.....");
  printf ("\n |->bAddrFilterEn      = %i", tsEnetAddrFilterConfig.bAddrFilterEn);
  printf ("\n |->bLearningEn        = %i", tsEnetAddrFilterConfig.bLearningEn);
  printf ("\n |->bAgingEn           = %i", tsEnetAddrFilterConfig.bAgingEn);
  printf ("\n |->bMultiCastFilterEn = %i", tsEnetAddrFilterConfig.bMultiCastFilterEn);
  printf ("\n |->bBroadCastFilterEn = %i", tsEnetAddrFilterConfig.bBroadCastFilterEn);
  printf ("\n |->uiAgingCount       = %i", tsEnetAddrFilterConfig.uiAgingCount);
  printf ("\n |->uiAddrEntryEn      = 0x%04x", tsEnetAddrFilterConfig.uiAddrEntryEn);
  printf ("\n |->bStaticAddrCount   = %i", tsEnetAddrFilterConfig.bStaticAddrCount);
  printf ("\n `->bMaxReadCount      = %i\n", tsEnetAddrFilterConfig.bMaxReadCount);

  for (i= 0;i < tsEnetAddrFilterConfig.bMaxReadCount; i++)
	{

    printf ("\n Ethernet Address [%i] = %02x.%02x.%02x.%02x.%02x.%02x",
            i+1,
            tsEnetAddrFilterConfig.abEnetAddr[i][0],
            tsEnetAddrFilterConfig.abEnetAddr[i][1],
            tsEnetAddrFilterConfig.abEnetAddr[i][2],
            tsEnetAddrFilterConfig.abEnetAddr[i][3],
            tsEnetAddrFilterConfig.abEnetAddr[i][4],
            tsEnetAddrFilterConfig.abEnetAddr[i][5]);
  }
*/

  // Release the Semaphore
  AddrFilterEocSema4 = 0;
}

/******************************************************************************/
/* Response to send EOC message to configure the remote CPE's Ethernet Address*/
/* filtering settings (All settings including the Static Addresses in table)  */
/******************************************************************************/
void appEocCpeConfigExtendMacResp (ipos_port_id pid, 
                                   U8 uid, U32 upar, int len, U8 *data)
{
#if defined(VTU_R) && (defined(P2CPE) || defined(BME_CPE_20))

  tsIposPtmfEnetAddrFilterCfg		tsTempEnetAddrFilterConfig;

  printf("\n EOC CPE CONFIG EXTENDED MAC RESPONSE \n");

  memcpy(&tsTempEnetAddrFilterConfig,
          &data[EOC_CTL_B + 1],
          sizeof(tsIposPtmfEnetAddrFilterCfg));

	iposPtmfAddrTabInit (&tsTempEnetAddrFilterConfig);
  
  macFilCfgShadow = tsTempEnetAddrFilterConfig;
  nvramUpdateBlk(2);
#endif
}

/******************************************************************************/
/* Response to send EOC message to add an entry in the static address table   */
/* of the remote CPE                                                          */
/******************************************************************************/

void appEocReadConfigMacComplete ( ipos_port_id pid, 
                                      U8 uid, U32 upar, int len, U8 *data)
{
  /*int i;	variable i is only referred to in programming that has been commented out */

  printf("\n EOC CPE READ CONFIG RESPONSE-COMPLETE \n");

	memcpy (&tsEnetAddrFilterConfig, 
          &data[EOC_CTL_B + 1],
          sizeof(tsEnetAddrFilterConfig));	

/*
  printf ("\n tsIposPtmfEnetAddrFilterCfg.....");
  printf ("\n |->bAddrFilterEn      = %i", tsEnetAddrFilterConfig.bAddrFilterEn);
  printf ("\n |->bLearningEn        = %i", tsEnetAddrFilterConfig.bLearningEn);
  printf ("\n |->bAgingEn           = %i", tsEnetAddrFilterConfig.bAgingEn);
  printf ("\n |->bMultiCastFilterEn = %i", tsEnetAddrFilterConfig.bMultiCastFilterEn);
  printf ("\n |->bBroadCastFilterEn = %i", tsEnetAddrFilterConfig.bBroadCastFilterEn);
  printf ("\n |->uiAgingCount       = %i", tsEnetAddrFilterConfig.uiAgingCount);
  printf ("\n |->uiAddrEntryEn      = 0x%04x", tsEnetAddrFilterConfig.uiAddrEntryEn);
  printf ("\n |->bStaticAddrCount   = %i", tsEnetAddrFilterConfig.bStaticAddrCount);
  printf ("\n `->bMaxReadCount      = %i\n", tsEnetAddrFilterConfig.bMaxReadCount);

  for (i= 0;i < tsEnetAddrFilterConfig.bMaxReadCount; i++)
	{

    printf ("\n Ethernet Address [%i] = %02x.%02x.%02x.%02x.%02x.%02x",
            i+1,
            tsEnetAddrFilterConfig.abEnetAddr[i][0],
            tsEnetAddrFilterConfig.abEnetAddr[i][1],
            tsEnetAddrFilterConfig.abEnetAddr[i][2],
            tsEnetAddrFilterConfig.abEnetAddr[i][3],
            tsEnetAddrFilterConfig.abEnetAddr[i][4],
            tsEnetAddrFilterConfig.abEnetAddr[i][5]);
  }
*/

  // Release the Semaphore
  AddrFilterEocSema4 = 0;
}

/******************************************************************************/
/* Response to send EOC message to Flush the Learned address table            */
/* of the remote CPE                                                          */
/******************************************************************************/
void appEocCpeFlushLearnedAddrResp (ipos_port_id pid,
                                    U8 uid, U32 upar, int len, U8 *data)
{
#if defined(P2CPE) || defined(BME_CPE_20)

  printf("\n EOC CPE FLUSH LEARNED ADDRESS RESPONSE \n");

 	iposPtmfEnetAddrFilterClearTable ();
	
#endif // defined(P2CPE) || defined(BME_CPE_20)
}

/******************************************************************************/
#endif //INI_SUPPORT
int
encodeOneByte( const void *pDataStruct, U8 **pPmsg, U8 ieLen )
{
	int	size = 0;
	U8	theByte = *((U8 *) pDataStruct);

	if (ieLen != 1)
	{
		printf( "\nWarning: IE encode one byte called with IE length of %d\n", ieLen );
	}

	**pPmsg = theByte;
	*pPmsg  += 1 ;
	size += 1;
	return( size );
}

int
encode16Bits( const void *pDataStruct, U8 **pPmsg, U8 ieLen )
{
	U16		theValue;

	if (ieLen != sizeof( U16 ))
	{
		printf( "\nWarning: IE encode 32 bits called with IE length of %d\n", ieLen );
	}

	theValue = *((U16*) pDataStruct);

	**pPmsg = ((theValue & 0x0000ff00) >> 8);
	*pPmsg  += 1 ;
	**pPmsg =  (theValue & 0x000000ff);
	*pPmsg  += 1 ;

	return( sizeof( U16 ) );
}
int
encode32Bits( const void *pDataStruct, U8 **pPmsg, U8 ieLen )
{
	U32			theValue;

	if (ieLen != sizeof( U32 ))
	{
		printf( "\nWarning: IE encode 32 bits called with IE length of %d\n", ieLen );
	}

	theValue = *((U32 *) pDataStruct);

	**pPmsg = ((theValue & 0xff000000) >> 24);
	*pPmsg  += 1 ;
	**pPmsg = ((theValue & 0x00ff0000) >> 16);
	*pPmsg  += 1 ;
	**pPmsg = ((theValue & 0x0000ff00) >> 8);
	*pPmsg  += 1 ;
	**pPmsg =  (theValue & 0x000000ff);
	*pPmsg  += 1 ;

	return( sizeof( U32 ) );
}

/* encodeString enforces the requirement that a string end with a NULL */

int
encodeString( const void *pDataStruct, U8 **pPmsg, U8 maxLen )
{
	U8	*pSource = (U8 *) pDataStruct;
	U8	*pDest = *pPmsg;
	U8	 iter;

	for (iter = 0; iter < maxLen - 1 && *pSource != 0; iter++)
	  *(pDest++) = *(pSource++);

	*pDest = 0;
	iter++;

	*pPmsg += iter;
	return( iter );
}

int
decodeOneByte( U8 *pMsg, void *pDataStruct, U8 ieLen )
{
	if (ieLen != 1)
	{
		printf( "\nWarning: IE decode one byte called with IE length of %d\n", ieLen );
	}

	*((U8 *) pDataStruct) = *pMsg;
	return( 1 );
}

int
decode16Bits( U8 *pMsg, void *pDataStruct, U8 ieLen )
{
	U16			theValue = 0;

	if (ieLen != sizeof( U16 ))
	{
		printf( "\nWarning: IE decode 16 bits called with IE length of %d\n", ieLen );
	}
   /* Force big endian */

	theValue |= (*(pMsg++) << 8);
	theValue |= *(pMsg++);

	*((U16 *) pDataStruct) = theValue;

	return( sizeof( U16 ) );
}

int
decode32Bits( U8 *pMsg, void *pDataStruct, U8 ieLen )
{
	U32			theValue = 0;

	if (ieLen != sizeof( U32 ))
	{
		printf( "\nWarning: IE decode 32 bits called with IE length of %d\n", ieLen );
	}

   /* Force big endian */

	theValue |= (*(pMsg++) << 24);
	theValue |= (*(pMsg++) << 16);
	theValue |= (*(pMsg++) << 8);
	theValue |= *(pMsg++);

	*((U32 *) pDataStruct) = theValue;

	return( sizeof( U32 ) );
}

int
decodeString( U8 *pMsg, void *pDataStruct, U8 ieLen )
{
	U8	*pDest = (U8 *) pDataStruct;
	U8	 iter, iter_2;

	for (iter = 0; iter < ieLen && *pMsg != 0; iter++)
	  *(pDest++) = *(pMsg++);

	if (iter < ieLen)
	  for (iter_2 = iter; iter_2 < ieLen; iter_2++)
	    *(pDest++) = 0;

	return( iter );	/* return count of non-zero U8's */
}

ieEncoder
appEocGetEncoder( U16 eocProtocol, U8 ieType, U8 ieSubtype )
{
	ieEncoder	retProgram = NULL;
	int		iter, found_the_entry = 0;

	for (iter = 0; iter < MAX_IE_PARSER_ENTRIES && found_the_entry == 0; iter++)
	{
		if (appIeParserTable[ iter ].eocProtocol == eocProtocol &&
		    appIeParserTable[ iter ].ieType == ieType &&
		    appIeParserTable[ iter ].ieSubtype == ieSubtype) {
			found_the_entry = 1;
			retProgram = appIeParserTable[ iter ].pIeEncoder;
		}
	}

	return( retProgram );
}

ieDecoder
appEocGetDecoder( U16 eocProtocol, U8 ieType, U8 ieSubtype )
{
	ieDecoder	retProgram = NULL;
	int		iter, found_the_entry = 0;

	for (iter = 0; iter < MAX_IE_PARSER_ENTRIES && found_the_entry == 0; iter++)
	{
		if (appIeParserTable[ iter ].eocProtocol == eocProtocol &&
		    appIeParserTable[ iter ].ieType == ieType &&
		    appIeParserTable[ iter ].ieSubtype == ieSubtype) {
			found_the_entry = 1;
			retProgram = appIeParserTable[ iter ].pIeDecoder;
		}
	}

	return( retProgram );
}

int
appEocRegIeParsers(
	U16 eocProtocol, U8 ieType, U8 ieSubtype,
	ieEncoder pTheEncoder, ieDecoder pTheDecoder
) {
	int	iter, found_an_entry = 0, retval = IPOS_SUCCESS;

	for (iter = 0; iter < MAX_IE_PARSER_ENTRIES && found_an_entry == 0; iter++)
	{
		if (appIeParserTable[ iter ].ieType == IE_NO_INFO)
		{
			appIeParserTable[ iter ].eocProtocol = eocProtocol;
			appIeParserTable[ iter ].ieType = ieType;
			appIeParserTable[ iter ].ieSubtype = ieSubtype;
			appIeParserTable[ iter ].pIeEncoder = pTheEncoder;
			appIeParserTable[ iter ].pIeDecoder = pTheDecoder;

			found_an_entry = 1;
		}
	}

	if (found_an_entry == 0)
	  retval = IPOS_ERROR;

	return( retval );
}

/************************************************************************
 * EOC Protocol Version (Who Are You?)
 ***********************************************************************/

#define IPOS_MSG_EOC_PROTOCOL		1

#define EOC_PROTOCOL_VERSION_INFO	2
#define IKANOS_BME_CPE_10		1
#define IKANOS_BME_CPE_20		2
#define EOC_VENDOR_ID_INFO		3
#define EOC_PROTOCOL_VENDOR_INFO 4

#define EOC_PROTOCOL_VERSION_RESEND_INTERVAL  3

typedef struct {
	ipos_ctrl_hdr	ctrlHdr;
	U16		eocProtocolVersion;
	U8		vendor_id[ 32 ];
} eoc_protocol_version_resp;
typedef struct {
		U16 eocProId;
		U16 eocProVerMajor;
		U16 eocProVerMinor;
        U32 eocVendorId;
		U16 eocProExtn;
} newVendorId;
typedef union {
	ipos_ctrl_hdr	ctrlHdr;
	U16		eocProtocolVersion;
	U8		vendor_id[ 32 ];
	struct {
		U16	eocProtocolID;
    	U16 eocProVerNum_major;
        U16 eocProVerNum_minor;
	    U32 t1VendorId;
		U16 eocProExtn;
	} venId;
} eoc_protocol_ver_resp;


/* First two entry points support user interface and are not directly part of EOC Protocol Version */

U16
uiGetEocProtocolVersion( void )
{
#ifdef BME_CPE_20
	return( IKANOS_BME_CPE_20 );
#else
	return( IKANOS_BME_CPE_10 );
#endif
}

const char *
uiGetVendorID( void )
{
	return( &ikanos_vendor_id[ 0 ] );
}

int
decodeVendorId (U8 *pMsgBuf,  void *pDataStruct, U8 ieLen)
{

	newVendorId theValue;

	if (ieLen != 12)
	{
		printf( "\nWarning: IE decode Vendor Id called with IE length of %d\n", ieLen );
	}

	decode16Bits(pMsgBuf, &(theValue.eocProId), 2);
	pMsgBuf += 2;
	decode16Bits(pMsgBuf, &(theValue.eocProVerMajor), 2);
	pMsgBuf += 2;
	decode16Bits(pMsgBuf, &(theValue.eocProVerMinor), 2);
	pMsgBuf += 2;
	decode32Bits(pMsgBuf, &(theValue.eocVendorId), 4);
	pMsgBuf += 4;
	decode16Bits(pMsgBuf, &(theValue.eocProExtn), 2); 

	*((newVendorId *) pDataStruct) = theValue;

 	return (ieLen); 

}

#ifdef VTU_O
static void
displayEocProVersion (eoc_protocol_ver_resp *pRemResp)
{


	if (pRemResp->venId.eocProtocolID == 1)
		printf("\nProtocol ID: Ikanos EOC Protocol \n");
	else
		printf ("\nProtocol ID:   %02x\n",pRemResp->venId.eocProtocolID);
	printf ("Protocol Version - Major:   %02x \n", pRemResp->venId.eocProVerNum_major);
	printf ("Protocol Version - Minor:   %02x \n", pRemResp->venId.eocProVerNum_minor);

    if (pRemResp->venId.t1VendorId == 0x23fb5)
	{
		printf("Vendor ID: IKANOS\t");
        printf ("Value: in Hex: %04lx, in Decimal: %lu\n", pRemResp->venId.t1VendorId, pRemResp->venId.t1VendorId);
	}
	else
		printf ("Vendor ID (Value): %04lx (HEX), %lu (DECIMAL) \n", pRemResp->venId.t1VendorId, pRemResp->venId.t1VendorId);

	if (pRemResp->venId.eocProExtn)
		printf(" Protocol Extn: %02x \n", pRemResp->venId.eocProExtn);

}

static void
uiReportEocProtocolVersion( ipos_port_id pid, U8 uid, int status, void *pData, int dataLen )
{
	U8	*pMsgBuf = (U8 *) pData;
	U8	*pMsgBase = pMsgBuf;
	int	 msgLen = pMsgBuf[ IPOS_MSGHDR_MSGLEN ];
	int	 size;
	U8	 ieType, ieLen, ieLen_2;
	eoc_protocol_ver_resp	 cpeResp;
	eoc_protocol_ver_resp	 *pRemoteResp = &cpeResp;

	ieDecoder   ourDecoder = NULL;

	/*printf( "\nuiReportEocProtocolVersion called for port b%dp%d with status %d\n",
		   pid.bmeNum, pid.portNum, status );*/

	if (status != IPOS_SUCCESS)
	{
		if (status == IPOSEOC_ERROR_TIMEOUT)
		  printf( "\nEOC protocol version timed out on port b%dp%d\n",
			   pid.bmeNum, pid.portNum
		  );
		else
		  printf( "\nEOC protocol version failed for port b%dp%d, status is %d\n",
			   pid.bmeNum, pid.portNum, status
		  );
	}
	else
	{

        size = iposEocDecodeCtrlHdr( pMsgBuf, &(pRemoteResp->ctrlHdr) );
		pMsgBuf += size;
		while( ((pMsgBuf - pMsgBase) < msgLen) && (*pMsgBuf != IE_NO_INFO) )
			{
				ieType = *pMsgBuf++;
				ieLen = *pMsgBuf++;

				ourDecoder = appEocGetDecoder( EOC_PROTOCOL_VERSION, ieType, IE_NO_INFO );
				if (ourDecoder == NULL)
				{
					printf(
				   "\nNo decoder for protocol EOC_PROTOCOL_VERSION, ie type %d, skipping\n",
				      ieType
					);
					pMsgBuf += ieLen;
				}
				else
				{
					switch (ieType)
					{
					  case EOC_PROTOCOL_VERSION_INFO:
						size = ourDecoder( pMsgBuf, &(pRemoteResp->eocProtocolVersion), ieLen );
						printf( "\nEOC protocol version is %d\n", pRemoteResp->eocProtocolVersion);
						break;

					  case EOC_VENDOR_ID_INFO:
						if (ieLen >= sizeof( pRemoteResp->vendor_id ))
						{
							printf(
					   "\nEOC VENDOR ID INFO exceeds maximun length of %d\n",
					      sizeof( pRemoteResp->vendor_id ) - 1
							);
							ieLen_2 = sizeof( pRemoteResp->vendor_id ) - 1;
						}
						else
						  ieLen_2 = ieLen;
						size = ourDecoder( pMsgBuf, &(pRemoteResp->vendor_id[ 0 ]), ieLen_2 );
						pRemoteResp->vendor_id[ ieLen_2 ] = 0;
                        printf( "Vendor ID is %s", &(pRemoteResp->vendor_id[ 0 ]));
						break;
                      case EOC_PROTOCOL_VENDOR_INFO:
						  size = ourDecoder( pMsgBuf, &(pRemoteResp->venId), ieLen );
						  displayEocProVersion (pRemoteResp);
						  break;
					  default:
						printf(
					    "\nUnrecognized ie type %d for protocol EOC_PROTOCOL_VERSION\n",
					       ieType
						);

						break;
					} /* switch on ieType */

					pMsgBuf += ieLen;
				} /* decoder available for Msg2Struct */

			} /* for each IE type in IPOS_MSG_EOC_PROTOCOL / ACK */
		
	}

	printf(PROMPT);
}
#endif

static int
eocProtocolVersionStruct2Msg( void *pStructBuf, U8 msgType, U8 *pBuf )
{
	int	 size = 0, size2 = 0;
	U8	 ack;
	U8	*pLocalBuf = pBuf;
	U8	**pMsgBuf = &pLocalBuf;

	if (msgType == IPOS_MSG_EOC_PROTOCOL) {
		ipos_ctrl_hdr	*pEocProtocolVersionHdr = (ipos_ctrl_hdr *) pStructBuf;

		ack = pEocProtocolVersionHdr->ack;
		if (ack == IPOS_ACK_CMD) {
			size2 = iposEocEncodeCtrlHdr( pEocProtocolVersionHdr, pMsgBuf );
			size = size2;
			**pMsgBuf = IE_NO_INFO;
			(*pMsgBuf)++;
			size++;
		}
		else {
			eoc_protocol_version_resp	*pOurResp = (eoc_protocol_version_resp *) pStructBuf;
			ieEncoder		ourEncoder = NULL;

			size2 = iposEocEncodeCtrlHdr( &(pOurResp->ctrlHdr), pMsgBuf );
			size = size2;

		/* verify both encoders are available.  get the one used 1st last, so it is ready to go */

			ourEncoder = appEocGetEncoder( EOC_PROTOCOL_VERSION, EOC_VENDOR_ID_INFO, IE_NO_INFO );
			if (ourEncoder != NULL)
			  ourEncoder = appEocGetEncoder(
					EOC_PROTOCOL_VERSION, EOC_PROTOCOL_VERSION_INFO, IE_NO_INFO
			  );

			if (ourEncoder != NULL)
			{
				**pMsgBuf = EOC_PROTOCOL_VERSION_INFO;
				*pMsgBuf += 2;
				size += 2;
				size2 = ourEncoder(
			   &pOurResp->eocProtocolVersion, pMsgBuf, sizeof( pOurResp->eocProtocolVersion )
				);
				size += size2;
				*(*pMsgBuf - size2 - 1) = size2;	/* ie length */

				**pMsgBuf = EOC_VENDOR_ID_INFO;
				*pMsgBuf += 2;
				size += 2;
				ourEncoder = appEocGetEncoder( EOC_PROTOCOL_VERSION, EOC_VENDOR_ID_INFO, IE_NO_INFO );
				size2 = ourEncoder(
			   &(pOurResp->vendor_id[ 0 ]), pMsgBuf, sizeof( pOurResp->vendor_id )
				);
				size += size2;
				*(*pMsgBuf - size2 - 1) = size2;	/* ie length */

				**pMsgBuf = IE_NO_INFO;
				*pMsgBuf += 1;
				size++;
			}
			else
			{
				**pMsgBuf = IE_NO_INFO;
				(*pMsgBuf)++;
				size2 = 1;
			}

		}

		pBuf[ IPOS_MSGHDR_MSGLEN ] = size;
	}
	else
	{
		printf( "\nUnrecognized message %d in EOC Protocol Version Struct to Msg\n", msgType );
		size = -1;
	}

	return( size );
}

void
uiGetEocProtocolVer( ipos_port_id pid )
{
#ifdef VTU_O
	U8		eocComplianceMsg[ MAX_MSG_SIZE ];
	int		lenEocCompliance;
	ipos_ctrl_hdr	eocProtocolVersionHdr;

	iposEocCmdSetCtrlHdr(
		&eocProtocolVersionHdr, EOC_PROTOCOL_VERSION, IPOS_MSG_EOC_PROTOCOL, IPOS_ACK_CMD, 0
	);
	lenEocCompliance = eocProtocolVersionStruct2Msg(
		       &eocProtocolVersionHdr, IPOS_MSG_EOC_PROTOCOL, &eocComplianceMsg[ 0 ]
	);
	iposEocCmdCoreSend( pid,
			   &eocComplianceMsg[ 0 ], lenEocCompliance,
			    0,
			    IPOS_NO_RESEND, EOC_PROTOCOL_VERSION_RESEND_INTERVAL,
			    uiReportEocProtocolVersion
	);
#endif
#ifdef VTU_R
	printf( "\nGet EOC Protocol Version not available from CPE user interface\n" );
#endif
}

#ifdef VTU_O
static int
decodeEocProtocolVersion( U8 *pMsg, void *pDataStruct, U8 ieLen )
{
	int	iter;
	union {
		U16	asU16;
		U8	asU8[ 2 ];
	} theValue;

	if (ieLen != sizeof( U16 ))
	{
		printf( "\nWarning: IE decode EOC protocol version called with IE length of %d\n", ieLen );
	}

   /* Force big endian */

	for (iter = 0; iter < 2; iter++)
	{
		theValue.asU8[ iter ] = *(pMsg++);
	}

	*((U16 *) pDataStruct) = theValue.asU16;

	return( 2 );
}

static void
coEocProtocolVersionHandler( ipos_port_id pid, int status, void *pEocMsg, int dataLen )
{
	int		msgClass = iposEocGetMsgClass( pEocMsg );	

	if (msgClass == IPOS_MSG_RESPONSE)
	{
		iposEocCmdCoreResp( pid, EOC_PROTOCOL_VERSION, pEocMsg, dataLen );
	}
	else 
	  printf( "\nEOC PROTOCOL VERSION received a message of unrecognized class %d\n", msgClass );
}
#endif

#ifdef VTU_R
static int
eocProtocolVersionMsg2Struct( U8 *pMsgBuf, void *pStructBuf, U8 *pMsgType )
{
	U8	 ack = pMsgBuf[ IPOS_MSGHDR_ACK ];
	int	 size;
	int	 retval = IPOS_SUCCESS;

	*pMsgType = *(pMsgBuf + EOC_TYPE_B);

	if (*pMsgType == IPOS_MSG_EOC_PROTOCOL)
	{
		if (ack == IPOS_ACK_CMD)
		{
			ipos_ctrl_hdr	*pCtrlHdr = (ipos_ctrl_hdr *) pStructBuf;

			size = iposEocDecodeCtrlHdr( pMsgBuf, pCtrlHdr );
		}
	}
		else
	  retval = IPOS_ERROR;
	return retval;
}
static int
encodeEocProtocolVersion( const void *pDataStruct, U8 **pPmsg, U8 ieLen )
{
	int	size = 0;
	U16	protocolVersion = *((U16 *) pDataStruct);

/* Force Big Endian format, even on a Little Endian CPU */

	**pPmsg = ((protocolVersion >> 8) & 0xff);	/* MSB */
	*pPmsg  += 1 ;
	**pPmsg = (protocolVersion & 0xff);		/* LSB */
	*pPmsg  += 1 ;
	size += 2;

	if (ieLen != size)
	{
		printf( "\nWarning: IE encode called with IE length of %d, expected %d\n", ieLen, size );
	}

	return( size );
}
static int
cpeEocProtocolVersionEventHandler( pIposEocPerPort pEocProtocolVersionPerPort, U8 *pEocMsg )
{
	U8	msgStruct[ MAX_EOC_PROTOCOL_STRUCT_SIZE ];
	U8	msgType;
	int	errCode = eocProtocolVersionMsg2Struct( pEocMsg, &msgStruct[ 0 ], &msgType );
	int	msgLen = 0;

	if (errCode != IPOS_SUCCESS)
	{
		printf( "\nCPE EOC PROTOCOL VERSION protocol handler received invalid message\n" );
	}
	else if (msgType == IPOS_MSG_EOC_PROTOCOL)
	{
		ipos_ctrl_hdr			*pCtrlHdr = (ipos_ctrl_hdr *) &msgStruct[ 0 ];
		eoc_protocol_version_resp 	 ourResp;
		U8		 		 msgBuf[ MAX_MSG_SIZE ];

/* default value for fields in the response is what was
   received from the CO,  Use memcpy to establish default */
   
		memcpy( &ourResp, pCtrlHdr, sizeof( *pCtrlHdr ) );
		ourResp.ctrlHdr.ack = IPOS_ACK_ACK;
#ifdef BME_CPE_20
		ourResp.eocProtocolVersion = IKANOS_BME_CPE_20;
#else
		ourResp.eocProtocolVersion = IKANOS_BME_CPE_10;
#endif
		strcpy( &ourResp.vendor_id[ 0 ], &ikanos_vendor_id[ 0 ] );
		msgLen = eocProtocolVersionStruct2Msg( &ourResp, IPOS_MSG_EOC_PROTOCOL, &msgBuf[ 0 ] );
		if (msgLen > 0)
		{
			errCode = iposEocSendDataStream(
			 pEocProtocolVersionPerPort->pid, msgLen, &msgBuf[ 0 ], 0, 0, NULL
			);
		}
		else
		  errCode = IPOS_ERROR;

	}

	return( errCode );
}

static void
cpeEocProtocolVersionHandler( ipos_port_id pid, int status, void *pEocMsg, int msgLen )
{
	int		msgClass = iposEocGetMsgClass( pEocMsg );	
	pIposEocPerPort pEocProtocolVersionPerPort = iposEocGetPerPort( pid, EOC_PROTOCOL_VERSION );

	if (pEocProtocolVersionPerPort == NULL) {
		printf( "\nError in EOC PROTOCOL VERSION protocol handler, no per port object for b%dp%d\n",
			   pid.bmeNum, pid.portNum
		);
		return;
	}

/* EOC Protocol Version on the CPE only responds to commands from the CO */

	if (msgClass == IPOS_MSG_COMMAND)
	{
		cpeEocProtocolVersionEventHandler( pEocProtocolVersionPerPort, pEocMsg );
	}
	else 
	  printf( "\nEOC_PROTOCOL_VERSION received a message of unrecognized class %d\n", msgClass );
}
#endif

void
appEocProtocolVersionInit( void )
{
#ifdef VTU_O
	iposEocRegHandler(  EOC_PROTOCOL_VERSION, 0, coEocProtocolVersionHandler );
	appEocRegIeParsers(
		EOC_PROTOCOL_VERSION, EOC_PROTOCOL_VERSION_INFO, IE_NO_INFO, NULL, decodeEocProtocolVersion
	);
	appEocRegIeParsers( EOC_PROTOCOL_VERSION, EOC_VENDOR_ID_INFO, IE_NO_INFO, NULL, decodeString );
	appEocRegIeParsers( EOC_PROTOCOL_VERSION, EOC_PROTOCOL_VENDOR_INFO, IE_NO_INFO, NULL, decodeVendorId );
#endif
#ifdef VTU_R
	iposEocRegHandler(  EOC_PROTOCOL_VERSION, 0, cpeEocProtocolVersionHandler );
	appEocRegIeParsers(
		EOC_PROTOCOL_VERSION, EOC_PROTOCOL_VERSION_INFO, IE_NO_INFO, encodeEocProtocolVersion, NULL
	);
	appEocRegIeParsers( EOC_PROTOCOL_VERSION, EOC_VENDOR_ID_INFO, IE_NO_INFO, encodeString, NULL );
#endif
}

/************************************************************************
 * Virtual EOC Message 1
 ***********************************************************************/

#define VIRTUAL_EOC_MSG_ACK	1
#define VIRTUAL_EOC_MSG_NACK	2
#define VIRTUAL_EOC_MSG_DATA	3

/* multibyte quantities are expressed as arrays of U8s to facilitate Big Endian format */

typedef struct {
	U8	cksum[ 2 ];
	U8	msgcode[ 2 ];
	U8	portNum[ 2 ];
	U8	length[ 2 ];
	U8	seqNum[ 2 ];
	U8	fill[ 2 ];
	U8	offset[ 4 ];
	U8	total[ 4 ];
	U8	data[ 0 ];
} iposEocHead_t;

#define MIN_LENGTH_VIRTUAL_MESSAGE_1	20
#define MAX_LENGTH_VIRTUAL_MESSAGE_1	100
#define LENGTH_CPE_VIRTUAL_MESSAGE_1	24

#define IPOS_VIRTUAL_MESSAGE_1_MSG_DATA		3
#define IPOS_VIRTUAL_MESSAGE_1_MSG_ACK		1

#define VIRTUAL_MESSAGE_1_RESEND_INTERVAL	4

static U16
checksumVirtualMessage1( U8 *data, U8 length )
{
	U8	iter;
	U16	checksum = 0;

	for (iter = 0; iter < length; iter++)
	  checksum += (U16) data[ iter ];
	return( checksum );
}

static int
virtualMessage1Filter( U8 *data, int len )
{
	int	retval = 0;
#ifdef VTU_R
	if (len >= MIN_LENGTH_VIRTUAL_MESSAGE_1 && len <= MAX_LENGTH_VIRTUAL_MESSAGE_1)
	{
		if (data[ 2 ] == 0 && data[ 3 ] == IPOS_VIRTUAL_MESSAGE_1_MSG_DATA)
		  retval = 1;
	}
#endif
#ifdef VTU_O
	if (len == LENGTH_CPE_VIRTUAL_MESSAGE_1)
	{

	  /* Rules:
	     1) 2nd 16 word must be IPOS_VIRTUAL_MESSAGE_1_MSG_ACK
	     2) record length (total field in (iposEocHead_t, a 32-bit quantity) must be 4

	     All multibyte quantites in Big Endian format
	   */

		U32	value32;

		decode32Bits( &data[ 16 ], &value32, 4 );
		if (data[ 2 ] == 0 && data[ 3 ] == IPOS_VIRTUAL_MESSAGE_1_MSG_ACK &&
		    value32 == 4)
		  retval = 1;
	}
#endif
	return( retval );
}

#ifdef VTU_O
static void
uiVirtualMessage1Callback( ipos_port_id pid, U8 uid, int status, void *pData, int dataLen )
{
	U16		 ourChecksum, theirChecksum;
	U32		 value32;
	iposEocHead_t	*ack = (iposEocHead_t *) pData;

	if (status != IPOS_SUCCESS)
	{
		if (status == IPOSEOC_ERROR_TIMEOUT)
		  printf( "\nVirtual Message 1 timed out on port b%dp%d, test failed\n",
			   pid.bmeNum, pid.portNum
		  );
		else
		  printf(
	   "Virtual Message 1 callback for port b%dp%d received error status of %d, test failed\n",
	    pid.bmeNum, pid.portNum, status
		  );
		printf(PROMPT);
		return;
	}

	if (dataLen != LENGTH_CPE_VIRTUAL_MESSAGE_1)
	{
		printf(
	   "Virtual Message 1 callback for port b%dp%d recevied packet of length %d, expected %d\n",
	    pid.bmeNum, pid.portNum, dataLen, LENGTH_CPE_VIRTUAL_MESSAGE_1
		);
	}
	else {
#ifdef SHOW_VIRTUAL_MESSAGE_1
		int	 iter;
		U8	*data = (U8 *) pData;

		printf( "\nVirtual Message 1 from port b%dp%d\n", pid.bmeNum, pid.portNum );
		for (iter = 0; iter < dataLen; iter++)
		  printf( "%d ", data[ iter ] );
		printf( "\n" );
#else
		printf( "\nVirtual Message 1 message received from port b%dp%d\n", pid.bmeNum, pid.portNum );
#endif

		ourChecksum = checksumVirtualMessage1(
			(U8 *) &(ack->msgcode[ 0 ]), dataLen - sizeof( ourChecksum )
		);

	   /* force big endian */

		theirChecksum = ( ((ack->cksum[ 0 ]) << 8) | (ack->cksum[ 1 ]) );
		printf( "local checksum: %u  0x%04x\n", ourChecksum, ourChecksum );
		printf( "remote checksum: %u  0x%04x\n", theirChecksum, theirChecksum );
		decode32Bits( &ack->data[ 0 ], &value32, sizeof( value32 ) );
		if (value32 == 1)
		  printf( "found expected data value of %lu\n", value32 );
		else
		  printf( "found unexpected data value of %lu\n", value32 );
	}

	printf(PROMPT);
}
#endif

void
uiSendVirtualMessage1( ipos_port_id pid )
{
#ifdef VTU_O
	int		 errCode;
	U8		 message[ MIN_LENGTH_VIRTUAL_MESSAGE_1 ];
	iposEocHead_t	*msg = (iposEocHead_t *) &message[ 0 ];
	pIposEocPerPort perPort = iposEocGetPerPort( pid, EOC_VIRTUAL_MESSAGE_1 );

	if (perPort == NULL)
	{
		printf( "\nPort b%dp%d not set up for virtual message 1\n", pid.bmeNum, pid.portNum );
		return;
	}

	errCode = iposSemTake( perPort->semCmd, IPOS_WAIT_FOREVER );
	if (errCode != OS_SUCCESS)
	{
		return;
	}

	memset( msg, 0, sizeof( *msg ) );

	msg->msgcode[ 0 ] = 0;
	msg->msgcode[ 1 ] = IPOS_VIRTUAL_MESSAGE_1_MSG_DATA;
	msg->portNum[ 0 ] = 0;
	msg->portNum[ 1 ] = pid.portNum;
	msg->length[ 0 ] = 0;
	msg->length[ 1 ] = sizeof( iposEocHead_t );
	msg->seqNum[ 0 ] = 0;
	msg->seqNum[ 1 ] = 123;		/* arbitrary value */

	errCode = iposEocSendDataStream(pid, sizeof( message ), &message[ 0 ], 0, 0, NULL);

	if (errCode != IPOS_SUCCESS) {
		iposSemGive( perPort->semCmd );
		iposEocCmdStateUpdate( perPort, IPOSEOC_EVNT_RESET );
	}
	else {
		perPort->uid = 0;
		perPort->resendInterval = VIRTUAL_MESSAGE_1_RESEND_INTERVAL;
		perPort->resendCount = 0;
		perPort->pCmdCb = uiVirtualMessage1Callback;
		memcpy( &(perPort->msgRsn[ 0 ]), &message[ 0 ], sizeof( message ) );
		perPort->msgLen = sizeof( message );

		iposEocCmdStateUpdate( perPort, IPOSEOC_EVNT_CMD_SENT );

		errCode = iposSetTmr(
			perPort->ptmrRsnd,
			VIRTUAL_MESSAGE_1_RESEND_INTERVAL,
			iposEocCmdCoreResend, (U32) perPort, (U32) 0
		);
	}
#endif
#ifdef VTU_R
	printf( "\nSend Virtual Message 1 not available from CPE user interface\n" );
#endif
}

#ifdef VTU_R
static void
cpeVirtualMessage1Handler( ipos_port_id pid, int status, void *pEocMsg, int msgLen )
{

	iposEocHead_t	*msg = (iposEocHead_t *) pEocMsg;
	U8		 response[ sizeof( iposEocHead_t ) + sizeof( U32 ) ];
	iposEocHead_t	*ack = (iposEocHead_t *) &response[ 0 ];
	U8		*data = &(ack->data[ 0 ]);
	U16		 checksum;

/* assume message arrives in Big Endian format, so that a memory copy works */

	memcpy( ack, msg, sizeof( iposEocHead_t ) );
	ack->msgcode[ 0 ] = 0;
	ack->msgcode[ 1 ] = IPOS_VIRTUAL_MESSAGE_1_MSG_ACK;
	ack->length[ 0 ] = 0;
	ack->length[ 1 ] = sizeof( iposEocHead_t ) + sizeof( U32 );

	ack->total[ 0 ] = ack->total[ 1 ] = ack->total[ 2 ] = 0;
	ack->total[ 3 ] = sizeof( U32 );

	data[ 0 ] = data[ 1 ] = data[ 2 ] = 0;
	data[ 3 ] = 1;					/* Ikanos CPE, all versions */

	checksum = checksumVirtualMessage1(
		&response[ sizeof( U16 ) ], sizeof( response ) - sizeof( U16 )
	);

	ack->cksum[ 0 ] = ((checksum << 8) & 0xff);
	ack->cksum[ 1 ] = (checksum & 0xff);

	iposEocSendDataStream( pid, sizeof( response ), &response[ 0 ], 0, 0, NULL );
}
#endif

#ifdef VTU_O
static void
coVirtualMessage1Handler( ipos_port_id pid, int status, void *pEocMsg, int msgLen )
{
	pIposEocPerPort perPort = iposEocGetPerPort( pid, EOC_VIRTUAL_MESSAGE_1 );
	if (perPort == NULL)
	{
		printf(
	   "\nCO virtual protocol 1 handler, port b%dp%d not set up for virtual protocol 1\n",
	      pid.bmeNum, pid.portNum
		);
	}
	else {
		if (perPort->stateCmd == IPOSEOC_STATE_CMD_IDLE )
		{
			printf(
		   "\nport b%dp%d, virtual protocol 1, response to command called in idle state\n",
			 perPort->pid.bmeNum, perPort->pid.portNum
			);
		}
		else {
			iposEocCmdStateUpdate( perPort, IPOSEOC_EVNT_RESP_RCVD );

			iposResetTmr( perPort->ptmrRsnd );
			iposSemGive( perPort->semCmd );
			if (perPort->pCmdCb != NULL)
			{
				(perPort->pCmdCb)(
					perPort->pid,
					perPort->uid, IPOS_SUCCESS,
					pEocMsg, msgLen
				);
			}

			iposEocCmdCoreReset( perPort );
		}
	}
}
#endif

static void
appVirtualMessage1Init( void )
{
#ifdef VTU_O
	iposEocRegHandler(  EOC_VIRTUAL_MESSAGE_1, 0, coVirtualMessage1Handler );
#endif
#ifdef VTU_R
	iposEocRegHandler(  EOC_VIRTUAL_MESSAGE_1, 0, cpeVirtualMessage1Handler );
#endif
}

#ifdef ALASKA
// #ifdef FILE_BASED
void ohmCmdProcess(ipos_port_id pid, char *ohmData)
{
  char str_data[255] ;
  int internalEocCmd = 0, reg_number = 32;
  int Cmd = 0 ;

  ShowtimeParams *pStp = getShowtimeParamsRef(pid) ;

    //OHM commands are supported only for VDSL2/ADSL2/2+
    if ((pStp->LineType & ADSL1_TYPE_SUPPORTED) ||
        (pStp->LineType & VDSL1_TYPE_SUPPORTED))
    {
        printf("Command support only for VDSL2 or ADSL2/2+") ;
        return ;
    }

  if (!ohm_trace_options[pid.portNum].val_changed)
  {
    ohm_trace_options[pid.portNum].trace_options = 0x80 ;
  }

  internalEocCmd = *ohmData ;

  switch (internalEocCmd)
  {
      case 1: /* Update Test Parameter */
        construct_ohm_command (pid, OHM_HPI_UTP, 0, 0) ;
        break ;

      case 3: /* Get Data */
        reg_number = ohmData[1];
        switch (reg_number)
        {
          case 0x1:
            Cmd = OHM_HPI_MGMTREAD ;
            break ;

          case 0x2:
            Cmd = OHM_HPI_INVID ;
            break ;

          case 0x3:
            Cmd = OHM_HPI_AUXID ;
            break ;

          case 0x4:
            Cmd = OHM_HPI_STEST_RSLT ;
            break ;

          case 0x5:
            Cmd = OHM_HPI_PMDCAP ;
            break ;

          case 0x6:
            Cmd = OHM_HPI_PMSCAP ;
            break ;
          case 0x7:
            Cmd = OHM_HPI_TPSCAP ;
            break ;

          case 0x8:
            Cmd = OHM_HPI_PMDCTRL ;
            break ;

          case 0x9:
            Cmd = OHM_HPI_PMSCTRL ;
            break ;

          case 0x10:
            Cmd = OHM_HPI_TPSCTRL ;
            break ;
        }

        construct_ohm_command (pid, Cmd, 0, 0x2) ;
        break ;

      case 4:
        strcpy((char *)str_data, ohmData);
        construct_ohm_command (pid, OHM_HPI_CLEAREOC, (int) str_data, 0x4) ;
        break ;

      case 5: /* Get Data -Test Parameters*/
        reg_number =  ohmData[1];
        switch (reg_number)
        {
          case 0x1:
            Cmd = OHM_HPI_TP_LATN ;
            break ;
          case 0x2:
            Cmd = OHM_HPI_TP_SATN ;
            break ;
          case 0x3:
            Cmd = OHM_HPI_TP_SNRM ;
            break ;
          case 0x4:
            Cmd = OHM_HPI_TP_ATTNDR ;
            break ;
          case 0x5:
            Cmd = OHM_HPI_TP_ACTATP_NE ;
            break ;
          case 0x6:
            Cmd = OHM_HPI_TP_ACTATP_FE ;
            break ;
        }

        construct_ohm_command (pid, Cmd, 0, 0x2) ;
        break ;

  } /* End of switch (internalEocCmd) */

} /* End of ohmCmdProcess*/
#else

void uiOhmCmdMenu (ipos_port_id pid)
{

  char timestr[8], str[256], *str_temp, *str_temp_wr, str_data[255] ;
  int stop_Eoc = 1, print_Eoc_Menu = 1, length = 0, count = 0 ;
  int internalEocCmd = 0, reg_number = 32, data_val = 0, data_present = 0 ;
       int Cmd = 0 ;
  int port_options = 32 ;
  ShowtimeParams *pStp = getShowtimeParamsRef(pid) ;
  
    //OHM commands are supported only for VDSL2/ADSL2/2+
    if ((pStp->LineType & ADSL1_TYPE_SUPPORTED) ||
        (pStp->LineType & VDSL1_TYPE_SUPPORTED))
    {
        printf("Command support only for VDSL2 or ADSL2/2+") ; 
        return ;
    }

  if (!ohm_trace_options[pid.portNum].val_changed) 
  {
    ohm_trace_options[pid.portNum].trace_options = 0x80 ;
  }

  while (stop_Eoc == 1) 
  {
    internalEocCmd = 0 ;

    if (print_Eoc_Menu) 
    {
                    printf("\n Overhead Command Menu \n") ;
                    printf("\n     1) Update Test Parameters") ;
#ifdef VTU_O
                    printf("\n     2) Send Control Commands List");
#endif
                    printf("\n     3) Get Commands List") ;
                    printf("\n     4) Set Commands List") ;
                    printf("\n     5) Single Read Test Param List") ;
      
                    //printf("\n     11) Enable/Disable OHM "); 
          
                    printf("\n     99) Exit this Menu");
             } 
             
             printf("\n\n Select Option: ");
             gets (str);

    if (strlen(str) < 1) 
    {
      print_Eoc_Menu = 0 ;
      continue ;
    }
    
    sscanf(str, "%i", &internalEocCmd) ;
    switch (internalEocCmd) 
    {
      case 1: /* Update Test Parameter */
        construct_ohm_command (pid, OHM_HPI_UTP, 0, 0) ;
        print_Eoc_Menu = 0 ;
        stop_Eoc = 0 ;
        break ;

#ifdef VTU_O
      case 2 : /* Control Commands */
        printf(" Available Control Commands: \n\n") ;
        printf(" 1) Perform Self Test\n") ;
        printf(" 2) Start Tx Corrupt CRC  3) Stop Tx Corrupt CRC\n") ;
        printf(" 4) Start Rx Corrupt CRC  5) Stop Rx Corrupt CRC\n") ;
        printf("Enter Option: ") ;
        gets(str) ;
         
        str_temp = str ; 
        while ( *str_temp++ == ' ') ; 

        if (strlen(--str_temp)) 
        { 
          sscanf(str_temp,"%d", &internalEocCmd) ;

          switch (internalEocCmd) 
          {
            case 0x1:
              Cmd = OHM_HPI_STEST ;
              break ;
            case 0x2: 
              Cmd = OHM_HPI_TXCRC_START ;
              break ;
            case 0x3: 
              Cmd = OHM_HPI_TXCRC_END ;
              break ;
            case 0x4: 
              Cmd = OHM_HPI_RXCRC_START ;
              break ;
            case 0x5: 
              Cmd = OHM_HPI_RXCRC_END ;
              break ;
            default:
              printf ("\n\r Invalid Control Command Option\n\r") ;
              return ;
          }
          
          construct_ohm_command (pid, Cmd, 0, 0) ;
          data_present = 0 ;
        }
        print_Eoc_Menu   = 0 ;
        stop_Eoc       = 0 ;
        break ;
#endif

      case 3: /* Get Data */
        printf(" Available Get Commands: \n\n") ;
        printf(" 1) Management Counters Read    2) Inventory ID\n") ;
        printf(" 3) Auxiliary ID                4) Self Test Result\n") ;

        if (pStp->LineType & ADSL2_TYPE_SUPPORTED) 
        { //not available for VDSL2 
            printf(" 5) PMD Capability              6) PMD-TC Capability\n") ;
            printf(" 7) TPS-TC Capability           8) PMD Control\n") ;
            printf(" 9) PMS-TC Control Params      10) TPS-TC Control Params\n") ;
        }            
#ifdef VTU_O        
        printf(" 11) Read Time \n") ;
#endif            
        printf("Enter Option: ") ;
        gets(str) ;
        check_value(str, &reg_number) ;
        switch (reg_number) 
        {
          case 0x1:
            Cmd = OHM_HPI_MGMTREAD ;
            break ;
          case 0x2: 
            Cmd = OHM_HPI_INVID ;
            break ;
          case 0x3: 
            Cmd = OHM_HPI_AUXID ;
            break ;
          case 0x4: 
            Cmd = OHM_HPI_STEST_RSLT ;
            break ;
          case 0x5: 
            Cmd = OHM_HPI_PMDCAP ;
            break ;
          case 0x6: 
            Cmd = OHM_HPI_PMSCAP ;
            break ;
          case 0x7: 
            Cmd = OHM_HPI_TPSCAP ;
            break ;
          case 0x8: 
            Cmd = OHM_HPI_PMDCTRL ;
            break ;
          case 0x9: 
            Cmd = OHM_HPI_PMSCTRL ;
            break ;
          case 0x10: 
            Cmd = OHM_HPI_TPSCTRL ;
            break ;
#ifdef VTU_O            
          case 0x11: 
            Cmd = OHM_HPI_READTIME ;
            break ;
#endif
          default:
            printf ("\n\r Invalid Get Option:0x%x\r", Cmd) ;
            return ;
        }
        
        construct_ohm_command (pid, Cmd, 0, 0x2) ;
        data_present     = 0 ;
        print_Eoc_Menu   = 0 ;
        stop_Eoc       = 0 ;
        break ;

      case 4:
        printf("Available Set Commands: \n\n") ;
        printf(" 1) Clear EOC\n") ;
#ifdef VTU_O
        printf(" 2) Set Time\n") ;
#endif
        printf("Enter Option: ") ;
        gets(str) ;
        check_value(str, &reg_number) ;
        str_temp = str_data ;

#ifdef VTU_O
        if (reg_number == 2) //set time
        {
          printf("\nEnter Time (in format HH:MM:SS) :") ;
          gets(timestr) ;
         
          while (check_time_value(timestr)) {
           printf("\nEnter Valid Time (in format HH:MM:SS) :") ;
           gets(timestr) ;
          }
          
          for (count = 0 ; count < OHM_SETTIME_LEN; count++) {
            data_val = timestr[count] ;
            if ((data_val < 0) || (data_val > 255)) 
		{
 		   printf("Invalid Data Entered") ;
  		   break ;
              }
              sprintf(str_temp, "%02x", data_val) ;
              str_temp += 2 ;
          }   
          *str_temp = '\0' ;
          data_present = 0x4 ;
          construct_ohm_command (pid, OHM_HPI_SETTIME, (int) str_data, data_present) ;
          data_present = 0 ;
        } 
        else 
#endif /* VTU_O*/
           if (reg_number == 1) //clearEOC
          {
             do {
                
                  printf("Enter Data Length(1-200): ") ;
                  gets(str) ;
                  str_temp_wr = str ; 

                  while ( *str_temp_wr++ == ' ') ;
            
                  if (strlen(--str_temp_wr))  
                    sscanf(str_temp_wr,"%d",&length) ;
              } while ((length > 200) || (length < 1 )) ;

              for (count = 0 ; count < length ; count++)
              {
                 printf("Byte[%d] (hex) is :", count) ;
                 gets(str) ;
                 check_value(str, &data_val) ;
                 if ((data_val < 0) || (data_val > 255)) 
                 {
                    printf("Invalid Data Entered") ;
                    break ;
                  }   
            
                 sprintf(str_temp, "%02x", data_val) ;
                 str_temp += 2 ;
              }
          
          *str_temp = '\0' ;
          data_present = 0x4 ;
          
          if ((data_val > 0) && (data_val < 255)) 
          {
            construct_ohm_command (pid, OHM_HPI_CLEAREOC, (int) str_data, data_present) ;
            data_present = 0 ;
          }
        }
        else 
            printf("\nInvalid option") ;

        print_Eoc_Menu = 0 ;
        stop_Eoc = 0 ;
        break ;
        
      case 5: /* Get Data -Test Parameters*/
        printf(" Test Parameter Read Commands: \n\n") ;
        printf(" 1) Line Attenuation (LATN)\n") ;
        printf(" 2) Signal Attenuation (SATN)\n") ;
        printf(" 3) Signal-to-Noise Margin (SNRM)\n") ;
        printf(" 4) Attainable Net Data Rate (ATTNDR)\n") ;
        printf(" 5) Near-end Actual Aggregate Transmit Power (ACTATP-ne)\n") ;
        printf(" 6) Far-end Actual Aggregate Transmit Power (ACTATP-fe)\n") ;
            
        printf("Enter Option: ") ;
        gets(str) ;
        check_value(str, &reg_number) ;
        switch (reg_number) 
        {
          case 0x1: 
            Cmd = OHM_HPI_TP_LATN ;
            break ;
          case 0x2: 
            Cmd = OHM_HPI_TP_SATN ;
            break ;
          case 0x3: 
            Cmd = OHM_HPI_TP_SNRM ;
            break ;
          case 0x4: 
            Cmd = OHM_HPI_TP_ATTNDR ;
            break ;
          case 0x5: 
            Cmd = OHM_HPI_TP_ACTATP_NE ;
            break ;
          case 0x6: 
            Cmd = OHM_HPI_TP_ACTATP_FE ;
            break ;
          default:
            printf ("\n\r Invalid Test Param Option\n\r") ;
            return ;
        }
        
        construct_ohm_command (pid, Cmd, 0, 0x2) ;
        data_present     = 0 ;
        print_Eoc_Menu   = 0 ;
        stop_Eoc       = 0 ;
        break ;


      case 11 :
        printf("Enable[1]/Disable[0] --> OHM [%x] : ", 
          (ohm_trace_options[pid.portNum].trace_options >> EOC_BIT) & 0x01) ;
        gets(str) ;
        check_value(str, &port_options);
        if ((port_options != 32) && ((port_options == 1) || (port_options == 0))) 
        {
          ohm_trace_options[pid.portNum].val_changed = 1 ;
          ohm_trace_options[pid.portNum].trace_options &= (~(1 << EOC_BIT)) ;
          ohm_trace_options[pid.portNum].trace_options |= (port_options << EOC_BIT);
          oampEocProtocolSet(&pid, 
              SET_EN_DI_TRACE_VAL, 
              &(ohm_trace_options[pid.portNum].trace_options),
              0,
              0) ;
        } 
        print_Eoc_Menu = 0;
        stop_Eoc = 0;
        break;

                    case 99 :
                         stop_Eoc = 0;
                         break;

                    default :
                         stop_Eoc = 1;
                         print_Eoc_Menu = 1;
                         break;

             } /* End of switch (internalEocCmd) */
     } /* End of while (stop_Eoc) */
     
} /* End of uiInternalEocMenu */
#endif


void
uiInternalEocMenu ( ipos_port_id pid )
{

	 char str[256], *str_temp, *str_temp_wr, str_data[255];
   int stop_Eoc = 1, print_Eoc_Menu = 1, length = 0, count = 0;
	 int internalEocCmd = 0, port_options = 32 , reg_number = 32, data_val = 0, data_present = 0;
   ShowtimeParams	*pStp = getShowtimeParamsRef (pid) ;
   
    //OHM commands are supported only for VDSL2/ADSL2/2+
    if ((pStp->LineType & ADSL2_TYPE_SUPPORTED) ||
        (pStp->LineType & VDSL2_TYPE_SUPPORTED))
    {
        printf("Command support only for VDSL1 or ADSL1") ; 
        return ;
    }
   
   if (!trace_options[pid.portNum].val_changed)
			trace_options[pid.portNum].trace_options = 0xFF;
	 
	 while (stop_Eoc == 1) {
       internalEocCmd = 0;
       
			 if (print_Eoc_Menu) {
					printf("\n Internal EOC Menu \n");
					printf("\n     1) Enable [1] / Disable [0] Internal Eoc Trace");
					printf("\n     2) EOC Trace Options (Refer option 90 for help) ");
					printf("\n     3) EOC Trace Log");
					printf("\n     4) Get Internal Eoc State");
#ifdef VTU_O
					printf("\n     5) Internal Eoc Self Test");
					printf("\n     6) Send Internal Eoc Command");
#endif
					printf("\n     7) Eoc Read Register");
					printf("\n     8) Eoc Write Register");
#ifdef VTU_O
					printf("\n     9) Read VTU_R Line Attenuation");
					printf("\n     10) Read VTU_R SNR Margin");
					printf("\n     11) Read VTU_R Configuration");
					printf("\n     12) Read VTU_R Vendor ID");
					printf("\n     13) Read VTU_R Revision Number");
					printf("\n     14) Read VTU_R Serial Number");
#endif
					printf("\n     90) Trace Options Information");
					printf("\n     99) Exit this Menu");
			 } /* End of if(print_Eoc_menu) */
			 
			 printf("\n\n Select Option: ");
			 gets (str);

			 if (strlen(str) < 1) {
					print_Eoc_Menu = 0;
					continue;
			 } /* End of if (strlen (str) ) */

			 sscanf(str, "%i", &internalEocCmd);

			 switch (internalEocCmd) {

					case 1 :
						   /* Get the Status of Eoc Trace */
							 printf("Port %x - Enter the New Trace State [%x] : ", pid.portNum,
									 (trace_options[pid.portNum].trace_options >> TRACE_BIT) & 0x01);
							 gets(str);
							 check_value(str, &port_options);
							 if ((port_options != 32) && ((port_options == 1) || (port_options == 0))) {
									 trace_options[pid.portNum].val_changed = 1;
							     trace_options[pid.portNum].trace_options &= 0xDF;
							     trace_options[pid.portNum].trace_options |= (port_options << TRACE_BIT);
							     oampEocProtocolSet(&pid, SET_EN_DI_TRACE_VAL, &(trace_options[pid.portNum].trace_options),0,0);
							 } else {
									/*
							 		 printf("Invalid Value \n"); */
							 }
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;

					case 2 :
						   /* EOC Trace Options */
						   printf("Port %x - Current Options are %x\n",pid.portNum,(trace_options[pid.portNum].trace_options & 0x1F));
							 printf("Enter the New Port Options (Hex) :");
							 gets(str);
							 check_value(str, &port_options);
							 if ((port_options <= 0x1F) && (port_options >= 0x00)) {
									 trace_options[pid.portNum].val_changed = 1;
									 trace_options[pid.portNum].trace_options &= 0xE0;
							     trace_options[pid.portNum].trace_options |= port_options;
							     oampEocProtocolSet(&pid, SET_EOC_TRACE_OPTIONS, &(trace_options[pid.portNum].trace_options),0,0);
							 } else {
									  /*
									  printf("Invalid Value \n"); */
							 }
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 
						 break;
					
					case 3:
						 /* Eoc Trace Log */

						 display_Eoc_LogMenu(pid);
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;

					case 4 :

						 /* Call the ipos command to get the state of the internal EOC
							* state machine. */

             oampEocProtocolGet(&pid,GET_EOC_STATE, 0, 0);
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 
						 break;
#ifdef VTU_O
					case 5 :	 
						 /* Call the function to do an Eoc self test */
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;

					case 6 :

						 /* Send EOC Command */
             printf("Available Commands are : \n");
						 printf(" 01) HOLD     02) RTN     03) SLFTST   04) REQCOR  05) REQEND \n");
						 printf(" 06) NOTCOR   07) NOTEND  08) EOD      09) REQTPU  10) NEXT   \n");
						 printf(" 11) RESERVED 12) DATA    13) RESERVED 14) WRITE0  15) WRITE1 \n"); 
						 printf(" 16) WRITE2   17) WRITE3  18) WRITE4   19) WRITE5  20) WRITE6 \n"); 
						 printf(" 21) WRITE7   22) WRITE8  23) WRITE9   24) WRITEA  25) WRITEB \n");
						 printf(" 26) WRITEC   27) WRITED  28) WRITEE   29) WRITEF  30) READ0  \n");
						 printf(" 31) READ1    32) READ2   33) READ3    34) READ4   35) READ5  \n");
						 printf(" 36) READ6    37) READ7   38) READ8    39) READ9   40) READA  \n");
						 printf(" 41) READB    42) READC   43) READD    44) READE   45) READF  \n");

						 printf("Enter the Command to be sent : ");
						 gets(str);

						 str_temp = str; 
             while ( *str_temp++ == ' '); 

	           if (strlen(--str_temp)) { 
 	               sscanf(str_temp,"%d",&internalEocCmd);
						     if ((internalEocCmd > 45) || (internalEocCmd < 1 )) {
										 /*
								     printf("Invalid Value\n");
										 */
						     } else {
                     data_val = 0;
						         data_present = 0;
						         if (internalEocCmd == 0x0C) {
								     /* We have to Send Data. */
								         printf("Enter the Data to be sent : ");
								         gets(str);
								         sscanf(str,"%x",&data_val);
								         data_present = 0x1;
						         }
						         construct_eoc_command(pid, internalEocCmd, data_val, data_present);
						         data_present = 0;
								 } 
						 }       
						 
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 break;
#endif

					case 7 :
             printf("Enter the Register Number [0 - F] : ");
						 gets(str);
						 check_value(str, &reg_number);
						 if ((reg_number != 32) && ((reg_number>= 0) && (reg_number<= 0xF))) {
                data_present = 0x2;
						    data_val = 0;
						    printf("Register is %x\n",reg_number);
						    construct_eoc_command(pid, reg_number, data_val, data_present);  
						    data_present = 0;
						 } else {
								/*
								printf("Invalid Value\n");
								*/
						 }
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 break;

					case 8 :
						 printf("Enter the Register Number [0 - F] : ");
						 gets(str);
						 check_value(str, &reg_number);
						 str_temp = str_data;
						 if ((reg_number != 32) && ((reg_number >= 0) && (reg_number <= 0xF))) {
								 printf("Enter the Length of the data to be sent (in bytes) (decimal values) : ");
						     gets(str);
                             str_temp_wr = str; 
                             while ( *str_temp_wr++ == ' '); 
	                         if (strlen(--str_temp_wr))  
                                sscanf(str_temp_wr,"%d",&length);

							 for (count = 0; count < length; count++)  {
								printf("Byte[%d] (hex) is :",count);
								gets(str);
								check_value(str, &data_val);
								if ((data_val < 0) || (data_val > 255)) {
									 printf("Invalid Data Entered");
									 break;
								}
						        sprintf(str_temp, "%02x", data_val);
								str_temp += 2;
							 }
							 *str_temp = '\0';
                             data_present = 0x4;
							 if ((data_val > 0) && (data_val < 255)) 
						       construct_eoc_command(pid, reg_number, (int) str_data, data_present);  
						     data_present = 0;
						 } else {
								/*
                 printf("Invalid Value\n");
								 */
						 }
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 break;
#ifdef VTU_O
					case 9 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 6;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;

					case 10 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 7;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;
					case 11 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 8;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;
					case 12 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 0;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;
					case 13 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 1;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;
						 break;
				  case 14 :
						 data_present = 0x2;
						 data_val = 0;
						 reg_number = 2;
						 construct_eoc_command(pid, reg_number, data_val, data_present);  
						 data_present = 0;
					   print_Eoc_Menu = 0;
						 stop_Eoc = 0;

						 break;
#endif
					case 90 :

						 printf(" Trace Options are (Enable - 1 / Disable - 0) : \n ");
						 printf("   Bit 4 - Trace Commands \n");
						 printf("     Bit 3 - Trace Messages \n");
						 printf("     Bit 2 - Trace Data Read/Write \n");
						 printf("     Bit 1 - Trace the Receiver \n");
						 printf("     Bit 0 - Trace the Transmitter \n");
						 printf("     For example, the value 1F will enable all the options. \n");
						 stop_Eoc = 1;
						 print_Eoc_Menu = 0;
					   break;
					case 99 :
						 stop_Eoc = 0;
						 break;

					default :
						 stop_Eoc = 1;
						 print_Eoc_Menu = 1;
						 break;

			 } /* End of switch (internalEocCmd) */
	 } /* End of while (stop_Eoc) */
	 
} /* End of uiInternalEocMenu */

void 
display_Eoc_LogMenu (ipos_port_id pid)
{
	 int eoc_logcmd = 0;
	 char str[255];

	 printf("\n   1. Display Event Log");
	 printf("\n   2. Clear Event Log");
	 printf("\n   99. Exit");

   printf("\n\n Select Option: ");
	 gets (str);

	 if (strlen(str) < 1) {
			 return;
   } /* End of if (strlen (str) ) */

	 sscanf(str, "%i", &eoc_logcmd);

	 switch(eoc_logcmd) {

			case 1 :
				 /* Get the EOC eventlog. */
				 get_EocEventLog( pid );
				 break;

		  case 2 :
				 /* Clear the event logs */
				 clear_EocEventLog( pid );
				 break;

			case 99 :
				 break;

			default :
				 printf("Invalid Eoc Event Log Selection %s\n",str);
				 break;
	 } /* end of switch(eoc_logcmd) */
	 return; 
} /* End of display_Eoc_LogMenu */

void 
construct_eoc_command (ipos_port_id pid, int internalEocCmd, int val, int flag)
{
   char str[255];
	
	 if (flag & 0x1) {
       /* we have some data to send. */
			 sprintf(str,"eosetdata:0:%i:%i:%x:%x;", pid.bmeNum, pid.portNum, EocCommands[internalEocCmd], val);
	 } else if (flag & 0x2) {
			 /* We have to Read a Register. */
			 sprintf(str,"eorxdata:0:%i:%i:%x;", pid.bmeNum, pid.portNum, EocCommands[30 + internalEocCmd]);
	 } else if (flag & 0x4) {
			 /* we have to send some data to a write register. */
			 sprintf(str,"eosetdata:0:%i:%i:%x:%s;", pid.bmeNum, pid.portNum, EocCommands[14 + internalEocCmd], (char *) val);
	 } else {
       /* We are sending a control command. */
			 sprintf(str,"eoctrltx:0:%i:%i:%d;", pid.bmeNum, pid.portNum, EocCommands[internalEocCmd]);
	 }
	 if (strlen(str))
       ReceiveTLCommand (str);
}

void construct_ohm_command (ipos_port_id pid, int Cmd, int val, int flag)
{
	char str[255];
	
	if (flag & 0x1) 
	{
		/*Set Data at remote VTU*/
		sprintf (str, "eosetdata:0:%i:%i:%x:%x;", pid.bmeNum, pid.portNum, Cmd, val) ;
	} 
	else if (flag & 0x2)
	{
		/*Get Data from remote VTU*/
		sprintf (str, "eorxdata:0:%i:%i:%x;", pid.bmeNum, pid.portNum, Cmd) ;
	} 
	else if (flag & 0x4) 
	{
		/*Send Data to remote VTU*/
		sprintf (str, "eosetdata:0:%i:%i:%x:%s;", pid.bmeNum, pid.portNum, Cmd, (char *) val) ;
	} 
	else 
	{
		/*Send a control command to remote XTU*/
             sprintf (str, "eoctrltx:0:%i:%i:%d;", pid.bmeNum, pid.portNum, Cmd) ;
	}

	if (strlen(str))
	{
		ReceiveTLCommand (str) ;
	}
	
	return ;
}

void
parse_internalEoc_Data(ipos_port_id    pid, oamp_cb_msg *pMsg)
{
	 int len = pMsg->parLen;
	 int i, count = 0;
	 float val = 0.0;
	 U8 opCode = pMsg->par[0];
   int data;
   U32 xdslType;
   U8* ptr ;
   U16 ausLatn[5]={0,} ;
   U16 ausSatn[5]={0,} ;
   U16 ausSnrm[5+1]={0,} ;
   U32 ulAttndr = 0 ;
   U16 usActatp_ne = 0 ;
   U16 usActatp_fe = 0 ;
   U32 ulCrc = 0, ulFec = 0 ;
   U32 ulFecEs = 0, ulEs = 0, ulSEs = 0, ulLosEs = 0, ulUnEs = 0 ;
   U32 ulHec = 0, ulHecCells = 0, ulUpCells = 0, ulBitErrs = 0;
   ShowtimeParams	*pSTparams = getShowtimeParamsRef (pid) ;

   /*
   printf("OpCode received is %x\n",opCode);
   */
	if (pSTparams == NULL)
		return ;
	 
	xdslType = pSTparams->LineType ;
	len--;
	ptr = &pMsg->par[1] ;
	
	if ((xdslType & ADSL2_TYPE_SUPPORTED) || (xdslType & VDSL2_TYPE_SUPPORTED))
	{
		switch (opCode) 
		{
			case OHM_HPI_READTIME:	//time
				printf("\nTime: ") ;
				for (count = 0; count < len; count++)
					printf("%c", ptr[count]);
                            printf("(HH:MM:SS)\n");
				break ;

			case OHM_HPI_INVID:	//inventory-id
				printf("\nVendorId:\n") ;
				for (count = 0; count < 8; count++)
					printf("%02x ", ptr[count]);
				printf("[ ") ;
				for (count = 2; count < 6; count++)
					printf("%c ", ptr[count]);
				printf("]") ;
				
				printf("\nVersion-Num:\n") ;
				for (count = 8; count < 24; count++)
					printf("%02x ", ptr[count]);
				printf("\n[ ") ;
				for (count = 8; count < 24; count++)
					printf("%c", ptr[count]);
				printf("]") ;

				printf("\nSerial-Num:\n") ;
				for (count = 24; count < 56; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_AUXID: //aux-id
				printf("AUX-ID:\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_STEST_RSLT: //self test result
				printf("Self Test Result\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_PMDCAP: //pmd-cap
				printf("PMD Cap\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_PMSCAP: //pms-cap
				printf("PMS-TC Cap\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_TPSCAP: //tps-cap
				printf("TPS-TC Cap\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_PMDCTRL: //pmd-control
				printf("PMD Control\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_PMSCTRL: //pms-control
				printf("PMS-TC Control:\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_TPSCTRL: //tps-control
				printf("TPS-TC Control\n") ;
				for (count = 0; count < len; count++)
					printf("%02x ", ptr[count]);
				break ;

			case OHM_HPI_MGMTREAD: //mgmt-counters
        				printf("\nFar End Management Counters") ;
        				printf("\n==========================") ;
                        XTRACT_4BYTE(ulFec, ptr) ;    printf("\nFec      = %u", ulFec) ;
                        XTRACT_4BYTE(ulCrc, ptr) ;    printf("\nCrc      = %u", ulCrc) ;
                        XTRACT_4BYTE(ulFecEs, ptr) ; printf("\nFecEs    = %u", ulFecEs) ;
                        XTRACT_4BYTE(ulEs, ptr) ;      printf("\nEs       = %u", ulEs) ;
                        XTRACT_4BYTE(ulSEs, ptr) ;    printf("\nSEs      = %u", ulSEs) ;
                        XTRACT_4BYTE(ulLosEs, ptr) ; printf("\nLosEs    = %u", ulLosEs) ;
                        XTRACT_4BYTE(ulUnEs, ptr) ;  printf("\nUnEs     = %u", ulUnEs) ;
                        if (xdslType & ADSL2_TYPE_SUPPORTED)
                        {
                           XTRACT_4BYTE(ulHec, ptr) ;        printf ("\nHec      = %u", ulHec) ;
                           XTRACT_4BYTE(ulHecCells, ptr) ; printf ("\nHecCells = %u", ulHecCells) ;
                           XTRACT_4BYTE(ulUpCells, ptr) ;  printf ("\nUpCells  = %u", ulUpCells) ;
                           XTRACT_4BYTE(ulBitErrs, ptr) ;   printf ("\nBitErrs  = %u", ulBitErrs) ;
                            }
 				break ;

			/*********************TEST PARAMETERS**********/

			case OHM_HPI_TP_LATN: //LATN
                            if (xdslType & ADSL2_TYPE_SUPPORTED) {
                                XTRACT_2BYTE(ausLatn[0], ptr) ;
    				    val = 0 + (ausLatn[0] * (0.1)) ; 
				printf("Line Attenuation (LATN): %.2f dB \n", val) ;
                            } else {
                                for (i = 0; i < 5; i++) {
                                    XTRACT_2BYTE(ausLatn[i], ptr) ;
                                    val = 0 + (ausLatn[i] * (0.1)) ; 
	                             printf("Line Attenuation (LATNpb-%d) : %.2f dB\n", i, val) ;
                                }
                            }
				break;
			
			case OHM_HPI_TP_SATN: //SATN
                            if (xdslType & ADSL2_TYPE_SUPPORTED) {
                                XTRACT_2BYTE(ausSatn[0], ptr) ;
				    val = 0 + (ausSatn[0] * (0.1)) ; 
				printf("Signal Attenuation (SATN): %.2f dB \n", val) ;
                            } else {
                                for (i = 0; i < 5; i++) {
                                    XTRACT_2BYTE(ausSatn[i], ptr) ;
                                    val = 0 + (ausSatn[i] * (0.1)) ; 
	                             printf("Signal Attenuation (SATNpb-%d) : %.2f dB\n", i, val) ;
                                }
                            }
				break ;
				
			case OHM_HPI_TP_SNRM: //SNRM
                            if (xdslType & ADSL2_TYPE_SUPPORTED) {
                                XTRACT_2BYTE(ausSnrm[0], ptr) ;
				    if ((ausSnrm[0] & (1<<15)) != 0) {
					    data = (ausSnrm[0] | 0xFFFF0000) ; /* Convert to -ve interger */
				} else {
					    data = ausSnrm[0] ;
				}
	                        val = 0 + (data * (0.1)) ; 
				printf("SNR Margin (SNRM): %.2f dB \n", val) ;
                            } else {//vdsl2
                                for (i = 0; i < 6; i++) {
                                   XTRACT_2BYTE(ausSnrm[i], ptr) ;
				       if ((ausSnrm[i] & (1<<15)) != 0) 
    					    data = (ausSnrm[i] | 0xFFFF0000) ; /* Convert to -ve interger */
                                   else 
					    data = ausSnrm[i] ;
                                   val = 0 + (data * (0.1)) ; 
                                   if (i == 0 ) 
    				            printf("SNR Margin (SNRM-avg): %.2f dB \n", val) ;
                                   else
             				     printf("SNR Margin (SNRMpb-%d): %.2f  dB \n", i-1, val) ;
                                }//for
                            }
				break ;
				
			case OHM_HPI_TP_ATTNDR: //ATTNDR
				ulAttndr	= *((unsigned int*)ptr) ;
				printf("Attainable Net Data Rate (ATTNDR): %lu (bits/sec)\n", ulAttndr) ;
				break ;
				
			case OHM_HPI_TP_ACTATP_NE: //ACTATP_NE
				usActatp_ne = *((unsigned short*)ptr) ;
				if ((usActatp_ne & (1<<15)) != 0) {
					data = (usActatp_ne | 0xFFFF0000) ; /* Convert to -ve interger */
				} else {
					data = usActatp_ne ;
				}
	                     val = 0 + (data * (0.1)) ; //adsl2/2+
				printf("Near_End Actual Aggregate Transmit Power (ACTATP): %.2f dBm \n", val) ;
				break ;

			case OHM_HPI_TP_ACTATP_FE: //ACTATP_FE
				usActatp_fe = *((unsigned short*)ptr) ;
				if ((usActatp_fe & (1<<15)) != 0) {
					data = (usActatp_fe | 0xFFFF0000) ; /* Convert to -ve interger */
				} else {
					data = usActatp_fe ;
				}
	                     val = 0 + (data * (0.1)) ; //adsl2/2+
				printf("Far_End Actual Aggregate Transmit Power (ACTATP): %.2f dBm \n", val) ;
				break ;
							
			default:
				printf("Invalid OpCode received:0x%x\n", opCode); 
				break;
		}
		printf ("\n\r"); printf ("%s ", PROMPT);
		return ;
	}
	else {
	 switch (opCode) {
			case VENDOR_ID :
				 printf("Vendor ID Received is :");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case VENDOR_REVNO :
				 printf("Vendor Revision Number is :");
				 pMsg->par[len] = '\0';
				 printf("%s ",&(pMsg->par[1]));
				 break;
		  case VTUR_SRNO :
				 printf("VTU-R Serial Number is :");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case SLFTST_RESULTS :
				 printf("Self Test Results are :");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case VENDOR_REG1 :
				 printf("Vendor Discretionary Register 1 is :");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case VENDOR_REG2 :
				 printf("Vendor Discretionary Register 2 is :");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case VTUR_CONFIG :
				 printf("VTU-R Configuration:");
				 for (count = 1; count < len; count++)
						 printf("0x%x ",pMsg->par[count]);
				 break;
			case LINE_ATTEN :
				 printf("Line Atten is :");
				 val = 0 + (pMsg->par[1] * (0.25));
				 printf("%.2f dB\n",val);
				 break;
			case SNR_MARGIN :
				 printf("SNR Margin is :");
				 val = (-31.75) + (pMsg->par[1] * (0.25));
				 printf("%.2f dB\n",val);
				 break;
			case GET_EOC_STATE :
				 printf("EOC State is : ");
				 printf("%s\n",get_eoc_state[(int)pMsg->par[1]]);
				 printf("Latch State is : ");
				 printf("%s\n",get_latch_state[(int)pMsg->par[2]]);
				 break;
			default :
				 printf("Invalid OpCode received, %x \n", opCode); 
				 break;
	 }
   }
}

void
check_value(char *str, int *port_options)
{
   while ( *str++ == ' '); 

	 if (strlen(--str)) 
	    sscanf(str,"%x",&(*port_options));

}

int
check_time_value(unsigned char *pTimeStr)
{
    int i ; 
    
    if ((strlen(pTimeStr) != OHM_SETTIME_LEN) || (pTimeStr[2] != ':' ) || (pTimeStr[5] != ':' )) 
        return 1 ; //failed
    
    for (i = 0; i < OHM_SETTIME_LEN; i++)
    {
        if ((i == 2) || (i == 5)) 
        { 
            pTimeStr[i] = 0x3a ; //colon(:) value in ascii is 0x3a
        } 
        else if ((pTimeStr[i] < '0') || (pTimeStr[i] > '9')) 
        {
            return 1 ; //fail
        }
    }
    
    return 0 ; //validation passed
}


unsigned int OhmGetMaxNumOfTonePerLineType (unsigned int ulLineType)
{
    unsigned int ulMaxTone = 0 ;

    if (((ulLineType & ADSL2_ANNEX_A) == ADSL2_ANNEX_A) || 
        ((ulLineType & ADSL2_ANNEX_B) == ADSL2_ANNEX_B)) 
    {
            ulMaxTone = 256 ; 
    } 
    else if (((ulLineType & ADSL2_PLUS_ANNEX_A) == ADSL2_PLUS_ANNEX_A) || 
        ((ulLineType & ADSL2_PLUS_ANNEX_B) == ADSL2_PLUS_ANNEX_B) || 
        ((ulLineType & ADSL2_PLUS_ANNEX_M) == ADSL2_PLUS_ANNEX_M) || 
        ((ulLineType & ADSL2_PLUS_ANNEX_L) == ADSL2_PLUS_ANNEX_L)) 
    {
        ulMaxTone = 512 ; 
    } 
    else if (VDSL2_TYPE_SUPPORTED)
    {
            ulMaxTone = 4096 ; 
    }
    else 
    {
        printf("\n Invalid Line Type:0x%x", ulLineType) ;
    }        
    
    return ulMaxTone ; 
}

