    /*====================================================================*
     *
     *   Copyright (c) 2013 Qualcomm Atheros, Inc.
     *
     *   All rights reserved.
     *
     *   Redistribution and use in source and binary forms, with or
     *   without modification, are permitted (subject to the limitations
     *   in the disclaimer below) provided that the following conditions
     *   are met:
     *
     *   * Redistributions of source code must retain the above copyright
     *     notice, this list of conditions and the following disclaimer.
     *
     *   * Redistributions in binary form must reproduce the above
     *     copyright notice, this list of conditions and the following
     *     disclaimer in the documentation and/or other materials
     *     provided with the distribution.
     *
     *   * Neither the name of Qualcomm Atheros nor the names of
     *     its contributors may be used to endorse or promote products
     *     derived from this software without specific prior written
     *     permission.
     *
     *   NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
     *   GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
     *   COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
     *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     *   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     *   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *--------------------------------------------------------------------*/

    /*====================================================================*
     *
     *   signed LinkStatistics (struct plc * plc);
     *
     *   plc.h
     *
     *   this plugin for plcstat reads device link statistics using a
     *   VS_LNK_STATS message and displays information on stdout; since
     *   the output may not suite all requirements, users are encouraged
     *   to modify as needed; there is way too much data displayed here;
     *
     *   some code is duplicated for the sake of modularity;
     *
     *
     *   Contributor(s):
     *      Charles Maier <cmaier@qca.qualcomm.com>
     *
     *--------------------------------------------------------------------*/

    #ifndef LINKSTATISTICS_SOURCE
    #define LINKSTATISTICS_SOURCE

    #include <stdint.h>
    #include <memory.h>
    #include <inttypes.h>

    #include "../plc/plc.h"
    #include "../tools/memory.h"
    #include "../tools/number.h"
    #include "../tools/error.h"

    /*====================================================================*
     *   constants;
     *--------------------------------------------------------------------*/

    #define PAD ' '
    #define DIGITS 16

    /*====================================================================*
     *   variables;
     *--------------------------------------------------------------------*/

    #ifndef __GNUC__
    #pragma pack (push,1)
    #endif

    typedef struct __packed transmit

    {
    	uint64_t NUMTXMPDU_ACKD;
    	uint64_t NUMTXMPDU_COLL;
    	uint64_t NUMTXMPDU_FAIL;
    	uint64_t NUMTXPBS_PASS;
    	uint64_t NUMTXPBS_FAIL;
    }

    transmit;
    typedef struct __packed receive

    {
    	uint64_t NUMRXMPDU_ACKD;
    	uint64_t NUMRXMPDU_FAIL;
    	uint64_t NUMRXPBS_PASS;
    	uint64_t NUMRXPBS_FAIL;
    	uint64_t SUMTURBOBER_PASS;
    	uint64_t SUMTURBOBER_FAIL;
    	uint8_t NUMRXINTERVALS;
    	uint8_t RXINTERVALSTATS [1];
    }

    receive;
    typedef struct __packed interval

    {
    	uint8_t RXPHYRATE_MBPS_0;
    	uint64_t NUMRXPBS_PASS;
    	uint64_t NUMRXPBS_FAIL;
    	uint64_t SUMTURBOBER_PASS;
    	uint64_t SUMTURBOBER_FAIL;
    }

    interval;

    #ifndef __GNUC__
    #pragma pack (pop)
    #endif

    /*====================================================================*
     *
     *   unsigned error_rate (uint64_t passed, uint64_t failed);
     *
     *   compute error rate for a given quantity; the error rate is the
     *   ratio of failures to attempts;
     *
     *--------------------------------------------------------------------*/

    static float error_rate (uint64_t passed, uint64_t failed)

    {
    	if ((passed) || (failed))
    	{
    		return ((float)(failed * 100) / (float)(passed + failed));
    	}
    	return (0);
    }

    /*====================================================================*
     *
     *   float fec_bit_error_rate (struct receive * receive);
     *
     *   compute the FEC-BER from the VS_LNK_STATS when DIRECTION=1 and
     *   LID=0xF8;
     *
     *--------------------------------------------------------------------*/

    static float fec_bit_error_rate (struct receive * receive)

    {
    	float FECBitErrorRate = 0;
    	if (receive->SUMTURBOBER_PASS || receive->SUMTURBOBER_FAIL)
    	{
    		float TotalSumOfBitError = 100 * (float)(receive->SUMTURBOBER_PASS + receive->SUMTURBOBER_FAIL);
    		float TotalSumOfBits = 8 * 520 * (float)(receive->NUMRXPBS_PASS + receive->NUMRXPBS_FAIL);
    		FECBitErrorRate = TotalSumOfBitError / TotalSumOfBits;
    	}
    	return (FECBitErrorRate);
    }

    /*====================================================================*
     *
     *   void transmit (struct transmit * transmit);
     *
     *   display transmit statistics in fixed field format;
     *
     *--------------------------------------------------------------------*/

    static void TransmitStatistics (struct transmit * transmit)

    {
    	printf ("    TX");
    	printf (" %20" PRId64, transmit->NUMTXPBS_PASS);
    	printf (" %20" PRId64, transmit->NUMTXPBS_FAIL);
    	printf (" %6.2f%%", error_rate (transmit->NUMTXPBS_PASS, transmit->NUMTXPBS_FAIL));
    	printf (" %20" PRId64, transmit->NUMTXMPDU_ACKD);
    	printf (" %20" PRId64, transmit->NUMTXMPDU_FAIL);
    	printf (" %20" PRId64, transmit->NUMTXMPDU_COLL);
    	printf (" %6.2f%%", error_rate (transmit->NUMTXMPDU_ACKD, transmit->NUMTXMPDU_FAIL));
    	printf ("\n");
    	return;
    }

    /*====================================================================*
     *
     *   void Receive (struct receive * receive);
     *
     *   display receive statistics in fixed field format;
     *
     *--------------------------------------------------------------------*/

    static void ReceiveStatistics (struct receive * receive)

    {
    	printf ("    RX");
    	printf (" %20" PRId64, receive->NUMRXPBS_PASS);
    	printf (" %20" PRId64, receive->NUMRXPBS_FAIL);
    	printf (" %6.2f%%", error_rate (receive->NUMRXPBS_PASS, receive->NUMRXPBS_FAIL));
    	printf (" %20" PRId64, receive->NUMRXMPDU_ACKD);
    	printf (" %20" PRId64, receive->NUMRXMPDU_FAIL);
    	printf (" %6.2f%%", error_rate (receive->NUMRXMPDU_ACKD, receive->NUMRXMPDU_FAIL));
    	printf ("\n");
    	return;
    }

    /*====================================================================*
     *
     *   void Receive (struct receive * receive);
     *
     *   display receive statistics in fixed field format for each slot;
     *   the last line sumarizes results for all slots;
     *
     *--------------------------------------------------------------------*/

    static void Receive2 (struct receive * receive)

    {
    	struct interval * interval = (struct interval *)(receive->RXINTERVALSTATS);
    	uint8_t slot = 0;
    	while (slot < receive->NUMRXINTERVALS)
    	{
    		printf (" %1d", slot);
    		printf (" %3d", interval->RXPHYRATE_MBPS_0);
    		printf (" %20" PRId64, interval->NUMRXPBS_PASS);
    		printf (" %20" PRId64, interval->NUMRXPBS_FAIL);
    		printf (" %6.2f%%", error_rate (interval->NUMRXPBS_PASS, interval->NUMRXPBS_FAIL));
    		printf (" %20" PRId64, interval->SUMTURBOBER_PASS);
    		printf (" %20" PRId64, interval->SUMTURBOBER_FAIL);
    		printf (" %6.2f%%", error_rate (interval->SUMTURBOBER_PASS, interval->SUMTURBOBER_FAIL));
    		printf ("\n");
    		interval++;
    		slot++;
    	}
    	printf ("   ALL");
    	printf (" %20" PRId64, receive->NUMRXPBS_PASS);
    	printf (" %20" PRId64, receive->NUMRXPBS_FAIL);
    	printf (" %6.2f%%", error_rate (receive->NUMRXPBS_PASS, receive->NUMRXPBS_FAIL));
    	printf (" %20" PRId64, receive->SUMTURBOBER_PASS);
    	printf (" %20" PRId64, receive->SUMTURBOBER_FAIL);
    	printf (" %6.2f%%", error_rate (receive->SUMTURBOBER_PASS, receive->SUMTURBOBER_FAIL));
    	printf (" %6.2f%%", fec_bit_error_rate (receive));
    	printf ("\n");
    	return;
    }

    /*====================================================================*
     *
     *   signed LinkStatistics (struct plc * plc);
     *
     *
     *--------------------------------------------------------------------*/

    signed LinkStatistics (struct plc * plc)

    {
    	struct channel * channel = (struct channel *)(plc->channel);
    	struct message * message = (struct message *)(plc->message);

    #ifndef __GNUC__
    #pragma pack (push,1)
    #endif

    	struct __packed vs_lnk_stats_request
    	{
    		struct ethernet_hdr ethernet;
    		struct qualcomm_hdr qualcomm;
    		uint8_t MCONTROL;
    		uint8_t DIRECTION;
    		uint8_t LID;
    		uint8_t MACADDRESS [ETHER_ADDR_LEN];
    	}
    	* request = (struct vs_lnk_stats_request *) (message);
    	struct __packed vs_lnk_stats_confirm
    	{
    		struct ethernet_hdr ethernet;
    		struct qualcomm_hdr qualcomm;
    		uint8_t MSTATUS;
    		uint8_t DIRECTION;
    		uint8_t LID;
    		uint8_t TEI;
    		uint8_t LSTATS [1];
    	}
    	* confirm = (struct vs_lnk_stats_confirm *) (message);

    #ifndef __GNUC__
    #pragma pack (pop)
    #endif

    	memset (message, 0, sizeof (* message));
    	EthernetHeader (&request->ethernet, channel->peer, channel->host, channel->type);
    	QualcommHeader (&request->qualcomm, 0, (VS_LNK_STATS | MMTYPE_REQ));
    	plc->packetsize = (ETHER_MIN_LEN - ETHER_CRC_LEN);
    	request->MCONTROL = plc->pushbutton;
    	request->DIRECTION = plc->module;
    	request->LID = plc->action;
    	memcpy (request->MACADDRESS, plc->RDA, sizeof (request->MACADDRESS));
    	if (SendMME (plc) <= 0)
    	{
    		error (PLC_EXIT (plc), errno, CHANNEL_CANTSEND);
    		return (-1);
    	}
    	if (ReadMME (plc, 0, (VS_LNK_STATS | MMTYPE_CNF)) <= 0)
    	{
    		error (PLC_EXIT (plc), errno, CHANNEL_CANTREAD);
    		return (-1);
    	}
    	if (confirm->MSTATUS)
    	{
    		Failure (plc, PLC_WONTDOIT);
    		return (-1);
    	}
    	if (confirm->DIRECTION == 0)
    	{
    		printf ("   DIR");
    		printf (" ----------- PBs PASS");
    		printf (" ----------- PBs FAIL");
    		printf (" PBs ERR");
    		printf (" ---------- MPDU ACKD");
    		printf (" ---------- MPDU FAIL");
    		printf ("\n");
    		TransmitStatistics ((struct transmit *)(confirm->LSTATS));
    		printf ("\n");
    	}
    	if (confirm->DIRECTION == 1)
    	{
    		printf ("   DIR");
    		printf (" ----------- PBs PASS");
    		printf (" ----------- PBs FAIL");
    		printf (" PBs ERR");
    		printf (" ---------- MPDU ACKD");
    		printf (" ---------- MPDU FAIL");
    		printf ("\n");
    		ReceiveStatistics ((struct receive *)(confirm->LSTATS));
    		printf ("\n");
    		printf ("   PHY");
    		printf (" ----------- PBs PASS");
    		printf (" ----------- PBs FAIL");
    		printf (" PBs ERR");
    		printf (" ----------- BER PASS");
    		printf (" ----------- BER FAIL");
    		printf (" BER ERR");
    		printf ("\n");
    		Receive2 ((struct receive *)(confirm->LSTATS));
    		printf ("\n");
    	}
    	if (confirm->DIRECTION == 2)
    	{
    		printf ("   DIR");
    		printf (" ----------- PBs PASS");
    		printf (" ----------- PBs FAIL");
    		printf (" PBs ERR");
    		printf (" ---------- MPDU ACKD");
    		printf (" ---------- MPDU FAIL");
    		printf ("\n");
    		TransmitStatistics ((struct transmit *)(confirm->LSTATS));
    		ReceiveStatistics ((struct receive *)(confirm->LSTATS + sizeof (struct transmit)));
    		printf ("\n");
    		printf ("   PHY");
    		printf (" ----------- PBs PASS");
    		printf (" ----------- PBs FAIL");
    		printf (" PBs ERR");
    		printf (" ----------- BER PASS");
    		printf (" ----------- BER FAIL");
    		printf (" BER ERR");
    		printf ("\n");
    		Receive2 ((struct receive *)(confirm->LSTATS + sizeof (struct transmit)));
    		printf ("\n");
    	}
    	return (0);
    }

    #endif

[PREV] [HOME] [NEXT]