/*++
*******************************************************************************
* 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:

   SdlcTrace.cpp

Abstract:

   Sdlc trace implementation.

Author:

   Darin Haugen

--*/
#include "stdafx.h"
#include "Diagnostic.h"
#include "DataSource.h"
#include "Tracer.h"
#include "SdlcTrace.h"
#include "TraceStatView.h"
//#include "wan_control.h" - this has the wan_trace_t and related structs

/////////////////////////////////////////////////////////////////////////////
// CSdlcTraceSheet

class CSdlcTraceSheet : public CTraceSheet
{
	DECLARE_DYNAMIC(CSdlcTraceSheet)
	
	CTraceStatView    m_BufferStats;
//	CSdlcLineLapdView m_LapdStats;
//	CSdlcLineIl3View  m_Il3Stats;

	virtual void AddTracePages();	

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

// Operations
public:

// Overrides

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

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

IMPLEMENT_DYNAMIC(CSdlcTraceSheet, CTraceSheet)

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

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


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

/////////////////////////////////////////////////////////////////////////////
// CSdlcTraceSheet message handlers

void CSdlcTraceSheet::AddTracePages()
{
	AddPage(&m_BufferStats);
//	AddPage(&m_Il3Stats);
}

//IMPLEMENT_SERIAL(CSdlcTraceData, CTraceData, 2);


/////////////////////////////////////////////////////////////////////////////
// CSdlcTraceData

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

CSdlcTraceData::~CSdlcTraceData()
{
}

CTraceSheet *CSdlcTraceData::CreateTraceSheet()
{
	return new CSdlcTraceSheet(this, _T(""));
}

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

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

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

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

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

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


/////////////////////////////////////////////////////////////////////////////
// CSdlcFrame
LPCSTR CSdlcFrame::GetProtocol() const
{
#if 0
	return FilterTest(fmLapd) ? "Q921" : "Q931";
#else
	return "SDLC";
#endif // 0
}

void CSdlcFrame::GetDescription(CString& txt) const
{
#if 0
	if ( FilterTest(fmIl3) )
		AddIl3MessageType( txt );
	else
		AddSFrameType( txt );
#endif // 0
}


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


void CSdlcFrame::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 CSdlcFrame::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 CSdlcFrame::AddSFrameType( CString& msg ) const
{
	PUCHAR Payload = GetData();

	//  Analyze the Control field to determine frame type
	switch ( (Payload[1] >> 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 CSdlcFrame::TreeDataSdlcSupervisoryFrame(CTreeCtrl& tree, HTREEITEM hParent)
{
	PUCHAR Payload = GetData();
	CString msg = "Frame Type: ";
	AddSFrameType( msg );
	(void)InsertTreeItem(tree, msg, hParent, 1, 2);

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

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


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

	//  Analyze the Control field to determine frame type
	switch ( Payload[1] )
	{

		// With the Final Bit (Rare)
		case 0x13:	msg += "UI (Unnumbered information)";		break;
		case 0x17:	msg += "[R|S]IM (Set Initialization Mode)";	break;
		case 0x1f:	msg += "DM (Disconnected Mode)";			break;
		case 0x33:	msg += "UP (Unnumbered Poll)";				break;
		case 0x53:	msg += "DISC (No Tx/Rx)";					break;
		case 0x73:	msg += "UA (Unnumbered Command ACK)";		break;
		case 0x93:	msg += "SNRM (Set Normal Response Mode)";	break;
		case 0x97:	msg += "FRMR (Invalid Frame Received)";		break;
		case 0xBF:	msg += "XID (Exchange Station Identity)";	break;
		case 0xD7:	msg += "CFGR (Configure)";					break;
		case 0xDF:	msg += "SNRME (SNRM Extended)";				break;
		case 0xF3:	msg += "TEST (Test Pattern)";				break;
		case 0xFF:	msg += "BCN (Beacon)";						break;

		// Without the Final Bit (Rare)
		case 0x03:	msg += "UI (Unnumbered information)";		break;
		case 0x07:	msg += "[R|S]IM (Set Initialization Mode)";	break;
		case 0x0f:	msg += "DM (Disconnected Mode)";			break;
		case 0x23:	msg += "UP (Unnumbered Poll)";				break;
		case 0x43:	msg += "DISC (No Tx/Rx)";					break;
		case 0x63:	msg += "UA (Unnumbered Command ACK)";		break;
		case 0x83:	msg += "SNRM (Set Normal Response Mode)";	break;
		case 0x87:	msg += "FRMR (Invalid Frame Received)";		break;
		case 0xAF:	msg += "XID (Exchange Station Identity)";	break;
		case 0xC7:	msg += "CFGR (Configure)";					break;
		case 0xCF:	msg += "SNRME (SNRM Extended)";				break;
		case 0xE3:	msg += "TEST (Test Pattern)";				break;
		case 0xEF:	msg += "BCN (Beacon)";						break;
		default:    msg += "Unknown";							break;
	}
}


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

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

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


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

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

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

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

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


// Ioctl sent down to start\stop trace
class CSdlcTraceSwitch : public CStat<wan_trace_t>
{
public :
	CSdlcTraceSwitch(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; }
};


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

		ThrowSwitch(m_SwitchOn, sOn);
	}
}


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

	ThrowSwitch(m_SwitchOff, sOff);
}


