/*++
*******************************************************************************
* Copyright (c) 1990-98 Digi International Inc., All Rights Reserved          *
*                                                                             *
* This software contains proprietary and confidential information of Digi     *
* International Inc.  By accepting transfer of this copy, Recipient agrees    *
* to retain this software in confidence, to prevent disclosure to others,     *
* and to make no use of this software other than that for which it was        *
* delivered.  This is an unpublished copyrighted work of Digi International   *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly   *
* prohibited.                                                                 *
*                                                                             *
* Restricted Rights Legend                                                    *
*                                                                             *
* Use, duplication, or disclosure by the Government is subject to             *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in         *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or        *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -          *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                       *
*                                                                             *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343          *
*                                                                             *
*******************************************************************************
Module Name:

   HdlcTrace.cpp

Abstract:

   Hdlc trace implementation.

Author:

   Shal Jain

--*/
#include "stdafx.h"
#include "Diagnostic.h"
#include "DataSource.h"
#include "Tracer.h"
#include "TraceStatView.h"



/////////////////////////////////////////////////////////////////////////////
// CHdlcTraceSheet

class CHdlcTraceSheet : public CTraceSheet
{
	DECLARE_DYNAMIC(CHdlcTraceSheet)
	
	CTraceStatView    m_BufferStats;

	virtual void AddTracePages();	

// Construction
public:
	CHdlcTraceSheet(CTraceData *, UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
	CHdlcTraceSheet(CTraceData *, LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);

// Operations
public:

// Overrides

// Implementation
public:
	virtual ~CHdlcTraceSheet() {};

	// Generated message map functions
protected:
	//{{AFX_MSG(CHdlcTraceSheet)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

IMPLEMENT_DYNAMIC(CHdlcTraceSheet, CTraceSheet)

CHdlcTraceSheet::CHdlcTraceSheet(CTraceData *td, UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CTraceSheet(td, nIDCaption, pParentWnd, iSelectPage)
{
}

CHdlcTraceSheet::CHdlcTraceSheet(CTraceData *td, LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CTraceSheet(td, pszCaption, pParentWnd, iSelectPage)
{
}


BEGIN_MESSAGE_MAP(CHdlcTraceSheet, CTraceSheet)
	//{{AFX_MSG_MAP(CHdlcTraceSheet)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHdlcTraceSheet message handlers

void CHdlcTraceSheet::AddTracePages()
{
	AddPage(&m_BufferStats);
}



/////////////////////////////////////////////////////////////////////////////
// CHdlcTraceData

CHdlcTraceData::CHdlcTraceData(DWORD baud, CDWordArray& circuits) : CTraceData(baud)
{
	m_ScratchFrame = CreateFrame();
//	ClearTraceStats();
}

CHdlcTraceData::~CHdlcTraceData()
{
}

CTraceSheet *CHdlcTraceData::CreateTraceSheet()
{
	return new CHdlcTraceSheet(this, _T(""));
}

void CHdlcTraceData::Serialize(CArchive& ar)
{
//	CTraceData::Serialize(ar);

#pragma message("Add support for Serialization of Hdlc Traces!")
}

void CHdlcTraceData::ProcessFrame(const strbuf& control, const strbuf& data)
{
	CTraceData::ProcessFrame(control, data);
	CHdlcFrame *frame = (CHdlcFrame *)m_ScratchFrame;

//	PUCHAR Payload = frame->GetData();
//	frame->SetFilterMask( (Payload[2] & 0x01)==0 ? fmIl3 : fmLapd );
}

BOOL CHdlcTraceData::DoFilterOptions(DWORD& mask, CDWordArray *circuit)
{
#pragma message( "Build a filter dialog" )	
	return FALSE;
}

void CHdlcTraceData::ClearTraceStats()
{
	CTraceData::ClearTraceStats();
#pragma message( "Add trace stats and code to clear them" )
}

/////////////////////////////////////////////////////////////////////////////
// CHdlcFrame
LPCSTR CHdlcFrame::GetProtocol() const
{
#if 0
	return "PPP";	// <-- what is this protocol
#else
	return "HDLC";
#endif // 0
}

void CHdlcFrame::GetDescription(CString& txt) const
{
}


void CHdlcFrame::DisplayTreeData(CTreeCtrl& tree, const CTraceData *td, CFrame *pFramePrev)
{
	CFrame::DisplayTreeData(tree, td, pFramePrev);	 
//	TreeDataSdlc(tree, TVI_ROOT);
}

#if 0
void CHdlcFrame::TreeDataSdlc(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg = "Control - ";
	AddSFrameType( msg );
	HTREEITEM item = InsertTreeItem(tree, msg, hParent, 0, 4);
	TreeDataSdlcAddress( tree, item );

	#define SDLC_FRAMETYPE 0x03
	switch ( Payload[1] & SDLC_FRAMETYPE )
	{
		case 1:	// Supervisory frame
			TreeDataSdlcSupervisoryFrame( tree, item );
			break;

		case 3:	// Unnumbered frame
			TreeDataSdlcUnnumberedFrame( tree, item );
			break;

		case 0:
		case 2:	// Information frame
			TreeDataSdlcInfoFrame( tree, item );
			break;
	}
}


void CHdlcFrame::TreeDataSdlcAddress(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg;

	msg.Format( "Station Address: 0x%x", Payload[0] );
	(void)InsertTreeItem( tree, msg, hParent, 0, 1 );
}


void CHdlcFrame::AddSFrameType( CString& msg ) const
{
	PUCHAR Payload = GetData();

	//  Analyze the Control field to determine frame type
	switch ( (Payload[2] >> 2) & 3 )
	{
		case 0x00:	msg += "RR (receive ready)";			break;
		case 0x01:	msg += "RNR (receive not ready)";		break;
		case 0x02:	msg += "REJ (reject)";					break;
		default:    msg += "Unknown";						break;
	}
}


void CHdlcFrame::TreeDataSdlcSupervisoryFrame(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg = "Frame Type: ";
	AddSFrameType( msg );
	(void)InsertTreeItem(tree, msg, hParent, 2, 3);

	msg.Format( "Poll Final bit, (P/F): %d", GetPF(Payload[2]) );
	(void)InsertTreeItem( tree, msg, hParent, 3, 4 );

	msg.Format( "Receive sequence number, N(R): %d", GetNr(Payload[2]) );
	(void)InsertTreeItem( tree, msg, hParent, 3, 4 );
}


void CHdlcFrame::AddUFrameType( CString& msg ) const
{
	PUCHAR Payload = GetData();

	//  Analyze the Control field to determine frame type
	switch ( ((Payload[2] >> 2) & 3) | (Payload[2] & 0x1C) )
	{
		case 0x00:	msg += "UI (Unnumbered information)";		break;
		case 0x01:	msg += "[R|S]IM (Set Initialization Mode)";	break;
		case 0x03:	msg += "DM (Disconnected Mode)";			break;
		case 0x04:	msg += "UP (Unnumbered Poll)";				break;
		case 0x08:	msg += "DISC (No Tx/Rx)";					break;
		case 0x0C:	msg += "UA (Unnumbered Command ACK)";		break;
		case 0x10:	msg += "SNRM (Set Normal Response Mode)";	break;
		case 0x11:	msg += "FRMR (Invalid Frame Received)";		break;
		case 0x18:	msg += "CFGR (Configure)";					break;
		case 0x17:	msg += "XID (Exchange Station Identity)";	break;
		case 0x1B:	msg += "SNRME (SNRM Extended)";				break;
		case 0x1C:	msg += "TEST (Test Pattern)";				break;
		case 0x1F:	msg += "BCN (Beacon)";						break;
		default:    msg += "Unknown";							break;
	}
}


void CHdlcFrame::TreeDataSdlcUnnumberedFrame(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg = "Frame Type: ";

	AddUFrameType( msg );
	(void)InsertTreeItem( tree, msg, hParent, 2, 3 );

	msg.Format( "Poll Final bit (P/F): %d", GetPF(Payload[2]) );
	(void)InsertTreeItem( tree, msg, hParent, 2, 3 );
}


void CHdlcFrame::TreeDataSdlcInfoFrame(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg;

	msg.Format( "Send sequence number, N(S): %d", GetNs(Payload[2]) );
	(void)InsertTreeItem(tree, msg, hParent, 2, 3);

	msg.Format( "Receive sequence number, N(R): %d", GetNr(Payload[2]) );
	(void)InsertTreeItem(tree, msg, hParent, 3, 4);

	msg.Format( "Poll Final bit, (P/F): %d", GetPF(Payload[2]) );
	(void)InsertTreeItem( tree, msg, hParent, 3, 4 );

	ULONG cb = GetDataLen() - 3;	// size - header
	msg.Format( "Data: Number of data bytes remaining = %d (0x%x)", cb, cb );
	(void)InsertTreeItem( tree, msg, hParent, 4, cb + 3 );
}

#endif

// Ioctl sent down to start\stop trace
class CHdlcTraceSwitch : public CStat<wan_trace_t>
{
public :
	CHdlcTraceSwitch(DWORD Snid, eSwitch Pos = sOn) : 
		CStat<wan_trace_t>(Pos == sOff ? W_TRACEOFF : W_TRACEON)
		{ wan_trace_snid = Snid; }

//		{ l_type = W_TRACE;l_level = SDLC_DAT;l_snid = Snid; }
};

CHdlcTracer::CHdlcTracer(CDataSource *ds) : CTracer(ds, stWANS)
{
	// if no failure then turn trace on
	if (!Fail())
	{
		m_SwitchOn = new CHdlcTraceSwitch(m_Snid);

		ThrowSwitch(m_SwitchOn, sOn);
	}
}


CHdlcTracer::~CHdlcTracer()
{
	// turn trace off
	m_SwitchOff = new CHdlcTraceSwitch(m_Snid, sOff);

	ThrowSwitch(m_SwitchOff, sOff);
}
