#include <stdio.h>
#include <stdlib.h>
#include "windows.h"

// User api for Dxb.  Sources file defines include path, currently ..\dsapi\inc.
#include "dsioctl.h"
#include "dsuser.h"

// Firmware goo
#include "dxbtypes.h"
#include "ll_control.h"
#include "iwan_control.h"
#include "fr_cont.h"
#include "iphd.h"


// Global defines
//  SNID is 1-based
#define		SNID_01		0x01
#define		SNID_02		0x02
#define		SNID_03		0x03
#define		SNID_04		0x04

// Channel ID is 1-based
#define		CHANID_01	0x01
#define		CHANID_02	0x02
#define		CHANID_03	0x03
#define		CHANID_04	0x04

BOOL	DebugPrint = TRUE ;
//#define		PUTMSG		1

// Function prototypes
INT
HandleRequests (
	HANDLE	hFile,
	HANDLE	hStream,
	ULONG	Snid,
	ULONG	ChanId) ;


/*
 * Send the adapter an IWAN_SET_SNID ioctl
 */
BOOL
IwanSetSnid (
	HANDLE	hFile,
	HANDLE	hStream,
	ULONG	Snid,
	ULONG	ChanId)
{
	wan_snioc_t	SetSnid = { 0 } ;
	BOOL bSuccess ;


#define	IWAN_CLASS_FR	2
	SetSnid.w_type = WAN_SNID ;
	SetSnid.w_class = IWAN_CLASS_FR ;
	SetSnid.w_chanid = ChanId ;
	SetSnid.w_snid = Snid ;

	if (DebugPrint)
		printf ("IwanSetSnid: w_type 0x%x, w_chanid 0x%x, w_snid 0x%x\n",
			SetSnid.w_type, SetSnid.w_chanid, SetSnid.w_snid) ;

	bSuccess = DsIoctl (hFile, hStream, W_SETSNID, &SetSnid, sizeof SetSnid) ;

	if ( !bSuccess )
		printf ("IwanSetSnid failed!\n") ;

	return (bSuccess) ;
}


/*
 * Send the adapter a W_DOCONNECT command to bypass the connect_cfg stuff
 */
int
IwanDoConnect (
	HANDLE	hFile,
	HANDLE	hStream,
	ULONG	Snid,
	ULONG	ChanId)
{
	wan_hdioc_t		DoConnect = { 0 } ;
	wan_hdioc_t		*pDoConnect ;
	connect_cfg_t	ConnectCfg = { 0 } ;
	connect_cfg_t	*pConnectCfg ;
	int				Error = 0 ;
	uchar			*pBothConnect ;
	int				BothSize = (sizeof (wan_hdioc_t) + sizeof (connect_cfg_t)) ;


	DoConnect.w_type = WAN_HDR ;
	DoConnect.w_chanid = ChanId ;
	DoConnect.w_snid = Snid ;

	ConnectCfg.baud = 2048000 ;
	ConnectCfg.options = 0 ;
	ConnectCfg.fill_mask[ChanId-1] = 0xFF ;
	ConnectCfg.mode = HDLC_MODE ;
	ConnectCfg.timeslot_mask = 1 << (ChanId-1) ;
	ConnectCfg.fnum = 2 ;
	ConnectCfg.crc = CRC32 ;
	ConnectCfg.inv = 0 ;
	ConnectCfg.bsize = 2048 ;
	ConnectCfg.dtmf = 0 ;

	pBothConnect = malloc (BothSize) ;
	if ( !pBothConnect )
	{
		printf ("Could not malloc space for the Connect structures!!!\n") ;
		return (-1) ;
	}

	memcpy ((caddr_t) pBothConnect,
			(caddr_t) &DoConnect,
			sizeof (wan_hdioc_t)) ;
	memcpy ((caddr_t) (pBothConnect + sizeof (wan_hdioc_t)),
			(caddr_t) &ConnectCfg,
			sizeof (connect_cfg_t)) ;

	pDoConnect = (wan_hdioc_t *) pBothConnect ;
	pConnectCfg = (connect_cfg_t *) (pDoConnect + 1) ;

	if (DebugPrint)
	{
		printf ("IwanDoConnect: w_type(0x%x), w_chanid(0x%x), w_snid(0x%x)\n",
			pDoConnect->w_type, pDoConnect->w_chanid, pDoConnect->w_snid) ;

		printf ("Channel %d params: baud(%d) options(0x%x) mode(%s) ts_mask(0x%x) "
			"fnum(%d) crc(%s) inv(%s) bsize(0x%x) dtmf(%s)\n",
			ChanId, pConnectCfg->baud, pConnectCfg->options,
			(pConnectCfg->mode == HDLC_MODE) ? "HDLC" : "Other",
			pConnectCfg->timeslot_mask, pConnectCfg->fnum,
			(pConnectCfg->crc == CRC32) ? "CRC-32" : "CRC-16",
			(pConnectCfg->inv) ? "YES" : "NO", pConnectCfg->bsize,
			(pConnectCfg->dtmf) ? "YES" : "NO") ;
	}

	Error = DsIoctl (hFile, hStream, W_DOCONNECT, pBothConnect, BothSize) ;
//	Error = DsIoctl (hFile, hStream, W_DOCONNECT, &DoConnect, sizeof (wan_hdioc_t)) ;

	printf ("IwanDoConnect returned (0x%x).\n", Error) ;

	return (Error) ;
}


PutMsg (
	HANDLE	hFile,
	HANDLE	hStream)
{
	int		i ;
	UCHAR	Buf[256] = { 0 } ;
	char	Buf_Char = 'A' ;
	BOOL	bSuccess ;


	// Fill the buffer characters
	for (i = 0; i < sizeof (Buf); i++)
	{
		Buf[i] = Buf_Char ;

		if (Buf_Char == 'Z')
			Buf_Char = 'A' ;
		else
			++Buf_Char ;
	}

	bSuccess = DsPutMsg (hFile, hStream, NULL, 0, &Buf[0], sizeof (Buf), DS_PRIORITY_LOW) ;
	if ( !bSuccess )
	{
		printf ("DsPutMsg failed!!!\n") ;
	}

	return (bSuccess) ;
}


/*
 * Get the stats to see if anything happened (tx/rx/error)
 */
int
IWanGetStats (
	HANDLE	hFile,
	HANDLE	hStream,
	ULONG	Snid,
	ULONG	ChanId)
{
	wan_stioc_t			Stats = { 0 } ;
	wan_stioc_t			*pStats ;
	iwan_chan_stats_t	GetStats = { 0 } ;
	iwan_chan_stats_t	*pGetStats ;
	uchar				*pBothStats ;
	int					BothSize = (sizeof (wan_stioc_t) + sizeof (iwan_chan_stats_t)) ;
	int					Error = 0 ;


	Stats.w_type = WAN_STATS ;
	Stats.w_spare = 0 ;
	Stats.w_stats_offset = sizeof (wan_stioc_t) ;
	Stats.w_snid = Snid ;
	Stats.w_chanid = ChanId ;

	pBothStats = malloc (BothSize) ;
	if ( !pBothStats )
	{
		printf ("Could not malloc space for the Stats structures!!!\n") ;
		return (-1) ;
	}

	memcpy ((caddr_t) pBothStats, (caddr_t) &GetStats, sizeof (wan_stioc_t)) ;

	Error = DsIoctl (hFile, hStream, W_GETSTATS, &GetStats, sizeof (wan_stioc_t)) ;

	pStats = (wan_stioc_t *) pBothStats ;
	pGetStats = (iwan_chan_stats_t *) (pStats + 1) ;

	if (Error)
		printf ("IwanGetStats returned (0x%x).\n", Error) ;

	if (!Error)
	{
#if 0
		printf ("W_GETSTATS Results:\n"
			"\tsf_err(0x%x) loss_err(0x%x) crc_err(0x%x) nob_err(0x%x)\n"
			"\tlfd_err(0x%x) ra_err(0x%x) rof_err(0x%x) no_inn_space(0x%x)\n"
			"\tno_wan_mp(0x%x) no_fe_and_no_c(0x%x) tx_size_err(0x%x)\n"
			"\trx_size_err(0x%x) tx_prep(0x%x) tx_good(0x%x) rx_good(0x%x)\n"
			"\tt_hi(0x%x) t_fi(0x%x) t_ifc(0x%x) t_sf(0x%x) t_err(0x%x) t_fo(0x%x)\n"
			"\tr_hi(0x%x) r_fi(0x%x) r_ifc(0x%x) r_sf(0x%x) r_err(0x%x) r_fo(0x%x)\n",
			pGetStats->sf_err, pGetStats->loss_err, pGetStats->crc_err, pGetStats->nob_err,
			pGetStats->lfd_err, pGetStats->ra_err, pGetStats->rof_err, pGetStats->no_inn_space,
			pGetStats->no_wan_mp, pGetStats->no_fe_and_no_c, pGetStats->tx_size_err,
			pGetStats->rx_size_err, pGetStats->tx_prep, pGetStats->tx_good,
			pGetStats->rx_good, pGetStats->t_hi, pGetStats->t_fi, pGetStats->t_ifc,
			pGetStats->t_sf, pGetStats->t_err, pGetStats->t_fo, pGetStats->r_hi,
			pGetStats->r_fi, pGetStats->r_ifc, pGetStats->r_sf, pGetStats->r_err,
			pGetStats->r_fo) ;
#else
		if (pGetStats->sf_err)
			printf ("sf_err (0x%x)\n", pGetStats->sf_err) ;
		if (pGetStats->loss_err)
			printf ("loss_err (0x%x)\n", pGetStats->loss_err) ;
		if (pGetStats->crc_err)
			printf ("crc_err (0x%x)\n", pGetStats->crc_err) ;
		if (pGetStats->nob_err)
			printf ("nob_err (0x%x)\n", pGetStats->nob_err) ;
		if (pGetStats->lfd_err)
			printf ("lfd_err (0x%x)\n", pGetStats->lfd_err) ;
		if (pGetStats->ra_err)
			printf ("ra_err (0x%x)\n", pGetStats->ra_err) ;
		if (pGetStats->rof_err)
			printf ("rof_err (0x%x)\n", pGetStats->rof_err) ;
		if (pGetStats->no_inn_space)
			printf ("no_inn_space (0x%x)\n", pGetStats->no_inn_space) ;
		if (pGetStats->no_wan_mp)
			printf ("no_wan_mp (0x%x)\n", pGetStats->no_wan_mp) ;
		if (pGetStats->no_fe_and_no_c)
			printf ("no_fe_and_no_c (0x%x)\n", pGetStats->no_fe_and_no_c) ;
		if (pGetStats->tx_size_err)
			printf ("tx_size_err (0x%x)\n", pGetStats->tx_size_err) ;
		if (pGetStats->rx_size_err)
			printf ("r_size_err (0x%x)\n", pGetStats->rx_size_err) ;
		if (pGetStats->tx_prep)
			printf ("tx_prep (0x%x)\n", pGetStats->tx_prep) ;
		if (pGetStats->tx_good)
			printf ("tx_good (0x%x)\n", pGetStats->tx_good) ;
		if (pGetStats->rx_good)
			printf ("rx_good (0x%x)\n", pGetStats->rx_good) ;
		if (pGetStats->t_hi)
			printf ("t_hi (0x%x)\n", pGetStats->t_hi) ;
		if (pGetStats->t_fi)
			printf ("t_fi (0x%x)\n", pGetStats->t_fi) ;
		if (pGetStats->t_ifc)
			printf ("t_ifc (0x%x)\n", pGetStats->t_ifc) ;
		if (pGetStats->t_sf)
			printf ("t_sf (0x%x)\n", pGetStats->t_sf) ;
		if (pGetStats->t_err)
			printf ("t_err (0x%x)\n", pGetStats->t_err) ;
		if (pGetStats->t_fo)
			printf ("t_fo (0x%x)\n", pGetStats->t_fo) ;
		if (pGetStats->r_hi)
			printf ("r_hi (0x%x)\n", pGetStats->r_hi) ;
		if (pGetStats->r_fi)
			printf ("r_fi (0x%x)\n", pGetStats->r_fi) ;
		if (pGetStats->r_ifc)
			printf ("r_ifc (0x%x)\n", pGetStats->r_ifc) ;
		if (pGetStats->r_sf)
			printf ("r_sf (0x%x)\n", pGetStats->r_sf) ;
		if (pGetStats->r_err)
			printf ("r_err (0x%x)\n", pGetStats->r_err) ;
		if (pGetStats->r_fo)
			printf ("r_fo (0x%x)\n", pGetStats->r_fo) ;
#endif // 0
	}

	return (Error) ;
}


VOID
HexDumpBuffer (
	IN	PVOID	Buf,
	IN	INT		Length)
{
	PCHAR	bp = Buf;
	INT		addr = 0;
	INT		j;

	printf ("Dump starting at addr: %6.6x, len: %.2x\n", addr, Length);

	for (j=0; j < Length; j++, addr++)
	{
		if ((j & 0xf) == 0)
			printf ("\n%6.6x = ", addr);

		printf ("%2.2x ", *bp);
		bp++;
	}

	printf ("\n");
}


INT
HandleRequests (
	HANDLE	hFile,
	HANDLE	hStream,
	ULONG	Snid,
	ULONG	ChanId)
{
	BOOLEAN			Quit = FALSE;
	INT				status = 0;
	CHAR			str[80], ch, c;
	INT				num;
	BOOLEAN			done = FALSE, Ret = TRUE;
	CHAR			*p;


	if ( Ret == FALSE )
	{
		printf ("DoRegisterIoctl returned an error (%d)!\n", Ret) ;
		return (1) ;
	}

	while ( !Quit )
	{
		//  initialize the variables
		ch = num = c = 0 ;
		memset (str, '\0', 80) ;

		printf ("\ncommand? > ") ;

		p = str ;
		while ((*p++ = getchar ()) != '\n') ;

		sscanf (str, "%c %d\n", &ch, &num) ;
//		printf ("ch=%c  num=%d\n", ch, num) ;

		switch (ch)
		{
		//  place a packet into the transmit queue
		case 't':
		case 'T':
			Ret = PutMsg (hFile, hStream) ;
			IWanGetStats (hFile, hStream, Snid, ChanId) ;

			if ( Ret == FALSE )
				printf ("DoWriteIoctl returned an error (%d)!\n", Ret) ;

			break ;

		//  read a packet from the receive queue
		case 'r':
		case 'R':
//			Ret = PutMsg (hFile, hStream, &Packet) ;
//			IWanGetStats (hFile, hStream, Snid, ChanId) ;

			if ( Ret == FALSE )
				printf ("DoOpenIoctl returned an error (%d)!\n", Ret) ;

			break ;

		case 's':
		case 'S':
			IWanGetStats (hFile, hStream, Snid, ChanId) ;
			break ;

		//  quit this program
		case 'q':
		case 'Q':
			Quit = TRUE ;
			break ;

		//  unknown command
		default:
			printf ("Unknown Command!\n") ;
			break ;
		}
	}



	return (0) ;
}


void __cdecl
main (int argc, char *argv[])
{
	PCHAR	pName = NULL;
	PCHAR	pPrefix = "\\\\.\\";
	PCHAR	pFullName = NULL;
	HANDLE	hFile = NULL;
//	HANDLE	hStream = NULL;
	HANDLE	hIWAN = NULL;
	ULONG	Snid = SNID_01 ;
	ULONG	cb;
	BOOL	bSuccess;


	// Get nt adapter name from commandline and prefix it with \\.\\

	if ( argc != 2 )
	{
		printf( "\nUsage: csutest <dxb_device_name>\n\n"
		        "    csutest DigiDxb3\n\n" );
		goto Exit;
	}

	pName = argv[1];
	cb = strlen (pPrefix) + strlen (pName) ;

	pFullName = malloc (cb) ;
	if ( !pFullName )
	{
		printf( "Error allocating devicename buffer, cb %d\n", cb );
		goto Exit;
	}

	strcpy (pFullName, pPrefix) ;
	strcat (pFullName, pName) ;

	/*
	 * Open Dxb driver
	 */

	hFile = CreateFile (pFullName,
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING, 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf( "Error opening file %s\n", pFullName );
		goto Exit;
	}

	/*
	 * Now do streams stuff
	 */


	// Open IWAN
	printf ("Doing a DsOpen of 'IWAN'\n") ;
	bSuccess = DsOpen (hFile, "IWAN", &hIWAN) ;
	if ( !bSuccess )
	{
		printf ("DsOpen of IWAN failed!\n") ;
		goto Exit ;
	}
	printf ("Opened 'IWAN'\n") ;

	printf ("Setting Snid of %d, ChannelId %d\n", Snid, CHANID_01) ;
	if (!IwanSetSnid (hFile, hIWAN, Snid, CHANID_01))
		goto Exit ;

	if (!IwanDoConnect (hFile, hIWAN, Snid, CHANID_01))
		goto Exit ;

	// Get user input for Tx/Rx actions
	HandleRequests (hFile, hIWAN, Snid, CHANID_01) ;


Exit:

	printf ("Closing 'IWAN'\n") ;
	DsClose (hFile, hIWAN) ;


	if (hFile)
		CloseHandle (hFile) ;

	if (pFullName)
		free (pFullName) ;

	return ;
}

