/**
* @file icss_statistics.c
*
* @brief Main file for Statistics implementation
*        Contains Statistics getter functions
*
* \par
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* \par
*/

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include "icss_statistics.h"
#include "icss_learning.h"

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**Holder for PRU Statistics*/
pruStatistics pruStats[NUM_PORTS];
/**Holder for Statistics measured on host side*/
hostStatistics hostStats[NUM_PORTS];
/** Variable containing list of implemented protocols*/
extern uint16_t numImplementedProtocols;
/**list of identified protocol types, rest initialized to zero*/
extern Uint16 protocol_impl[MAX_NUM_PROTOCOL_IMPLEMENTED];


#ifdef TEST_DEBUG
int doNotUpdateStatsTX[NUM_PORTS];
int doNotUpdateStatsRX[NUM_PORTS];
#endif
/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
/**
* @brief   Read statistics from PRU DRAM Memory into structure
*
* @retval none
*/
void ReadStatsFromPRU() {

	volatile UInt8 *statsPointer;
	Uint8 *pruStatStructPtr;

	pruStatStructPtr = (Uint8*)(&(pruStats[HWPORT0]));
	statsPointer = (UInt8*)(PRU0_DRAM_BASE_ADDRESS + STATISTICS_OFFSET);
	memcpy((void*)pruStatStructPtr, (void*)statsPointer, STAT_SIZE);

	pruStatStructPtr = (Uint8*)(&(pruStats[HWPORT1]));
	statsPointer = (UInt8*)(PRU1_DRAM_BASE_ADDRESS + STATISTICS_OFFSET);
	memcpy((void*)pruStatStructPtr, (void*)statsPointer, STAT_SIZE);

	return;
}

/**
* @brief   compute secondary statistics from basic counters
*
*
* @retval none
*/
void ConsolidateStats(void) {

	/*Get the stats from PRU*/
	ReadStatsFromPRU();

}

/**
* @brief   clear switch statistics
*
* @retval none
*/
void PurgeStats(void) {
	UInt32 *statsPointer;
	/*clear PRU stats*/
	statsPointer = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + STATISTICS_OFFSET);
	memset(statsPointer, 0x0, STAT_SIZE);

	statsPointer = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + STATISTICS_OFFSET);
	memset(statsPointer, 0x0, STAT_SIZE);

	/*clear host stats*/
	statsPointer = (UInt32*)(&(hostStats[HWPORT0]));
	memset(statsPointer, 0x0, sizeof(hostStatistics));

	statsPointer = (UInt32*)(&(hostStats[HWPORT1]));
	memset(statsPointer, 0x0, sizeof(hostStatistics));

	/*clear host stats*/
	statsPointer = (UInt32*)(&(pruStats[HWPORT0]));
	memset(statsPointer, 0x0, sizeof(pruStatistics));

	statsPointer = (UInt32*)(&(pruStats[HWPORT1]));
	memset(statsPointer, 0x0, sizeof(pruStatistics));

}

/**
* @brief   Do the stats initialization, call at the beginning of the frame
*
* @retval none
*/
void InitStats(void) {

	PurgeStats();

#ifdef TEST_DEBUG
	doNotUpdateStatsTX[HWPORT0] = 0;
	doNotUpdateStatsTX[HWPORT1] = 0;

	doNotUpdateStatsRX[HWPORT0] = 0;
	doNotUpdateStatsRX[HWPORT1] = 0;
#endif
}

/**
* @brief   Call every time a packet is received, updates Rx related statistics
*
* @param macAddr pointer to mac address, stored in 8 bit locations
* @param packet_len packet length in bytes
* @param protIdent Protocol Type
* @param portNum incoming port number
*
* @retval none
*/
void UpdateRxstats(Uint8* macAddr,UInt32 packet_len,Uint16 protIdent, UInt32 portNum)
{
	UInt8 count=0;
	Bool prot_found = false;
	Uint8 Bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

#ifdef TEST_DEBUG
	//This is to make sure that the stats query and other custom queries are not counted
	if(doNotUpdateStatsRX[portNum]) {
		//clear the flag
		doNotUpdateStatsRX[portNum] = 0;
		return;
	}
#endif

	//Broadcast
	if(COMPARE_MAC(macAddr, Bcast_mac))
	{
		hostStats[portNum].rxBcast++;
	}
	else if((macAddr[0] & 0x01) == 1u)      /*Multicast*/
	{
		hostStats[portNum].rxMcast++;
	}
	else /*unicast*/
	{
		hostStats[portNum].rxUcast++;
	}

	hostStats[portNum].rxOctets += packet_len;

	for(count=0; count < numImplementedProtocols; count++)
	{
		if(protIdent == protocol_impl[count])
		{
			prot_found = true;
			break;
		}
	}

	if (!prot_found)
	{
		hostStats[portNum].rxUnknownProtocol++;
	}
}

/**
* @brief   Call every time a packet is transmitted, updates Tx related statistics
*
* @param macAddr pointer to mac address, stored in 8 bit locations
* @param packet_len packet length in bytes
* @param portNum incoming port number
*
* @retval none
*/
void UpdateTxstats(Uint8* macAddr,UInt32 packet_len, UInt32 portNum) {

#ifdef TEST_DEBUG
	//This is to make sure that the stats query and other custom queries are not counted
	if(doNotUpdateStatsTX[portNum]) {
		//clear the flag
		doNotUpdateStatsTX[portNum] = 0;
		return;
	}
#endif

	Uint8 Bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

	if(COMPARE_MAC(macAddr, Bcast_mac))
	{
		hostStats[portNum].txBcast++;
	}
	else if((macAddr[0] & 0x01) == 1u)
	{
		hostStats[portNum].txMcast++;
	}
	else
	{
		hostStats[portNum].txUcast++;
	}

	hostStats[portNum].txOctets += packet_len;

}
/**
* @brief   Enable Statistics on Switch
*
* @retval none
*/
void EnableStatistics(void) {
	volatile Uint8 *portStatusPtr;
	volatile Uint8  portStatus;


	portStatusPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + STAT_CTRL_OFFSET);
	portStatus = *(portStatusPtr);

	portStatus &= ~(SWITCH_STAT_DISABLED_MASK);

	/*write back*/
	*(portStatusPtr) = portStatus;

}

/**
* @brief   Disable Statistics on Switch
*
* @retval none
*/
void DisableStatistics(void) {

	volatile Uint8 *portStatusPtr;
	volatile Uint8 portStatus;


	portStatusPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + STAT_CTRL_OFFSET);
	portStatus = *(portStatusPtr);

	portStatus |= SWITCH_STAT_DISABLED_MASK;

	/*write back*/
	*(portStatusPtr) = portStatus;

}

