#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#include "DigiDga.h"

/*
#define IOCTL_DIGI_CONTROLLER_SPECIAL        CTL_CODE(FILE_DEVICE_CONTROLLER, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_CONTROLLER_DATA       CTL_CODE(FILE_DEVICE_CONTROLLER, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DIGI_GET_PORT_STATUS  CTL_CODE(FILE_DEVICE_CONTROLLER, 2055, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define MAX_IRPS 64
#define PORT_ERROR_FILE_SIZE  13
#define MAX_DMODE_PORTS     256
#define MAX_DMODE_RX_BUFFER 5
#define MAX_DMODE_PUT_EVENT 10

typedef unsigned long ULONG, *PULONG;
typedef unsigned short USHORT, *PUSHORT;
typedef unsigned char UCHAR, *PUCHAR;
typedef UCHAR BOOLEAN;           
typedef LONG NTSTATUS;
#if 0
typedef __int64 LONGLONG;
typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    };
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER;
#endif
typedef struct 
{
   ULONG Version;
   ULONG ComPort;
   PVOID DeviceExt;
   ULONG State;

   USHORT Tin, Tout, Tmax;
   USHORT Rin, Rout, Rmax;
   USHORT Edelay, Iflag, Oflag, Cflag;
   UCHAR  Iempty, Ilow, Idata;
   UCHAR  Xon, Xoff, Hflow;
   UCHAR Tbusy, Mstat, Mint;
   UCHAR Buffer[3];
   struct {
      ULONG  Bin, Bout, Bmax, ScannedBytes, InsertCount;
      BOOLEAN  ScanForSpecialChar;
      PUCHAR Buffer;
      PVOID   ActiveIrp;
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         LARGE_INTEGER  StartTime;
         LARGE_INTEGER  Time;
         ULONG          Interval;
         ULONG          Multiplier;
         ULONG          Total;
         ULONG          Type;
         PVOID          Irp;
      } Timeout;
   } Read;
   
   struct {
      PVOID ActiveIrp;
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      PVOID CompletedIrp[MAX_IRPS];
      NTSTATUS CompletedIrpStatus[MAX_IRPS];
      struct {
         // This is the kernel timer structure used to handle
         // total time request timing.
         LARGE_INTEGER  StartTime;
         ULONG    Total;
         ULONG    Multiplier;
         ULONG    Type;
         // This field is meant to be a record for tracking the irp associated
         // with the timeout, and not a means to reference it directly.
         PVOID     Irp;
      } Timeout;
      
   }  Write;
   struct {
      ULONG History, Mask, Active, Status;
      PVOID Irp;
   }  Wait;
} PORT_STATUS, *PPORT_STATUS;

typedef struct _ASYN_PORT_STATUS
{
   ULONG Version;
   ULONG ComPort;
   PVOID DeviceExt;
   ULONG State;
   ULONG Busy;

   USHORT SyncOutNum, SyncInNum;
   ULONG  Speed;
   USHORT Rmax;
   USHORT Iflag, Oflag, Cflag, Xflag;
   UCHAR  Iempty, Ilow, Idata;
   UCHAR  Xon, Xoff, Mflow;
   USHORT Ttime, Tmax;
   UCHAR  Rtime;
   USHORT Estat, Eint;
   UCHAR  Mstat, Mint;
   USHORT Ltime;
   USHORT OpenStateMask;
   USHORT Norun, Noflow, Nframe, Nparity, Nbreak;
   struct {
      USHORT   Total;
      USHORT   LineNumber;
      UCHAR    FileName[PORT_ERROR_FILE_SIZE];
   } PortError;
   ULONG  TotalRxBytesBuffered;
   ULONG  TotalWriteBytes, TotalReadBytes;
   ULONG  Tout, TxBytesPending;
   USHORT RxBufCount;
   ULONG  TimedWritePutEvent;
   UCHAR  Buffer[3];
   struct {
      PVOID   Ptr[MAX_DMODE_RX_BUFFER];
      USHORT  Size[MAX_DMODE_RX_BUFFER];
      USHORT  Start[MAX_DMODE_RX_BUFFER];
      USHORT  Len[MAX_DMODE_RX_BUFFER];
   } RxQ;
   struct {
      PVOID   Put[MAX_DMODE_PUT_EVENT];
      USHORT  Command[MAX_DMODE_PUT_EVENT];
      PVOID   Irp[MAX_DMODE_PUT_EVENT];
      USHORT  Reason[MAX_DMODE_PUT_EVENT];
      USHORT  State[MAX_DMODE_PUT_EVENT];
   } PutQ;
   struct {
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
   } DispatchQ;
   struct {
      PVOID   Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         ULONG          Interval;
         ULONG          Multiplier;
         ULONG          Total;
         PVOID          Irp;
      } Timeout;
   } Read;
   
   struct {
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
      struct {
         ULONG    Total;
         ULONG    Multiplier;
         // This field is meant to be a record for tracking the irp associated
         // with the timeout, and not a means to reference it directly.
         PVOID     Irp;
      } Timeout;
      
   }  Write;
   struct {
      ULONG History, Mask, Active, Status;
      PVOID Irp;
   }  Wait;
   struct {
      PVOID Irp[MAX_IRPS];
      NTSTATUS IrpStatus[MAX_IRPS];
   } CompleteOutboundIrp;
} ASYN_PORT_STATUS, *PASYN_PORT_STATUS;

typedef struct _ASYN_CARD_STATUS
{
   ULONG State;
   ULONG Type;
   PVOID DeviceExt;
   ULONG NumberOfPorts;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } PutPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } GetPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } RxPool;
   struct {
      USHORT Count;
      USHORT LowTide;
      USHORT HighTide;
      USHORT Size;
   } ExtRxPool;
   UCHAR OpenPorts[MAX_DMODE_PORTS];
} ASYN_CARD_STATUS, *PASYN_CARD_STATUS;

#define DIGI_IOCTL_DBGOUT     0x00000001
#define DIGI_IOCTL_TRACE      0x00000002
#define DIGI_IOCTL_DBGBREAK   0x00000003

typedef struct _DIGI_IOCTL_
{
   ULONG dwCommand;
   ULONG dwBufferLength;
   CHAR Char[1024];
} DIGI_IOCTL, *PDIGI_IOCTL;
*/
#define DBGP(x) printf(#x"==0x%p\n", (x))
#define DBGX(x) printf(#x"==0x%0*X\n", sizeof(x)*2, (x))
#define DBGD(d) printf(#d"==%d\n", (d))

void ReportComStatus(HANDLE hCtrl, DWORD ComPort)
{
   PORT_STATUS Port;
   DWORD BytesReturned, i;
   BOOL Status;
   OVERLAPPED Overlapped;

   memset(&Overlapped, 0, sizeof(Overlapped));
   Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


   printf("Querying COM%d\n", ComPort);
   Status = DeviceIoControl(hCtrl,
                            IOCTL_DIGI_GET_PORT_STATUS,
                            &ComPort, sizeof(ComPort),
                            &Port, sizeof(Port),
                            &BytesReturned,
                            &Overlapped);
   if (!Status)
   {
      if (GetLastError()==ERROR_IO_PENDING)
      {
         Status = GetOverlappedResult(hCtrl,
                                      &Overlapped,
                                      &BytesReturned,
                                      TRUE);
      }
   }

   if (Status)
   {
      printf("Query successful.  %d bytes returned.\n", BytesReturned);
      DBGD(Port.State);
	  DBGX(Port.Speed);
      DBGX(Port.Tin);
      DBGX(Port.Tout);
      DBGX(Port.Tmax);
      DBGX(Port.Rin);
      DBGX(Port.Rout);
      DBGX(Port.Rmax);
      DBGX(Port.Edelay);
      DBGX(Port.Iflag);
      DBGX(Port.Oflag);
      DBGX(Port.Cflag);
	  DBGX(Port.Xflag);
	  DBGX(Port.Ttime);
	  
	  DBGX(Port.Estat);
	  DBGX(Port.Norun);
	  DBGX(Port.Noflow);
	  DBGX(Port.Nframe);
	  DBGX(Port.Nparity);
	  DBGX(Port.Nbreak);
	  DBGX(Port.Ltime);

      DBGX(Port.Iempty);
      DBGX(Port.Ilow);
      DBGX(Port.Idata);
      DBGX(Port.Xon);
      DBGX(Port.Xoff);
      DBGX(Port.Mflow);
      DBGX(Port.Tbusy);
      DBGX(Port.Mstat);
      DBGX(Port.Mint);


      DBGX(Port.Read.Bin);
      DBGX(Port.Read.Bout);
      DBGX(Port.Read.Bmax);
      DBGX(Port.Read.ScannedBytes);
      DBGX(Port.Read.InsertCount);
      DBGX(Port.Read.ScanForSpecialChar);      
      DBGX(Port.Read.Timeout.Interval);
      DBGX(Port.Read.Timeout.Multiplier);
      DBGX(Port.Read.Timeout.Total);
      DBGP(Port.Read.Timeout.Irp);


      DBGX(Port.Write.Timeout.Constant);
      DBGX(Port.Write.Timeout.Multiplier);
      DBGP(Port.Write.Timeout.Irp);
      

      DBGX(Port.Wait.History);
      DBGX(Port.Wait.Mask);
      DBGX(Port.Wait.Active);
      DBGP(Port.Wait.Irp);
   }
   else
   {
      printf("Query failed %d\n", GetLastError());
   }

}
/***************************************************************************************
**
**	void ReportComStatusAsyn( HANDLE hCtrl, DWORD ComPort )
**
**	Purpose: To get the good stuff from the card, and when I do, I am so happy that
**		I want to show the world. "Hello World" 
**
*****************************************************************************************/
void ReportComStatusAsyn(HANDLE hCtrl, DWORD ComPort)
{
   PORT_STATUS		Port;
   DWORD			BytesReturned, i;
   BOOL				Status;
   OVERLAPPED		Overlapped;

   memset(&Overlapped, 0, sizeof(Overlapped));
   Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


   printf("Querying COM%d\n", ComPort);
   Status = DeviceIoControl(hCtrl,
                            IOCTL_DIGI_GET_PORT_STATUS,
                            &ComPort, sizeof(ComPort),
                            &Port, sizeof(Port),
                            &BytesReturned,
                            &Overlapped);
   if (!Status)
   {
      if (GetLastError()==ERROR_IO_PENDING)
      {
         Status = GetOverlappedResult(hCtrl,
                                      &Overlapped,
                                      &BytesReturned,
                                      TRUE);
      }
   }

   if (Status)
   {
      printf("Query successful.  %d bytes returned.\n", BytesReturned);

      printf("Port#=0x%04x State0x%04x\n", ComPort, Port.State );

      printf("\tSpeed=%6d\tIflag=0x%04x\n", Port.Speed, Port.Iflag);

      printf("Oflag=0x%04x\tCflag=0x%04x\tXflag=0x%04x\tRmax =0x%04x\n",
             Port.Oflag, Port.Cflag, Port.Xflag, Port.Rmax);

      printf("Ttime=0x%04x\tEstat=0x%04x\tMstat=0x%04x\n",
             Port.Ttime, Port.Estat, Port.Mstat);

      printf("Mint =0x%04x\tLtime=0x%04x\n",
             Port.Mint, Port.Ltime);

      printf("Xon=0x%02x  Xoff=0x%02x  Mflow=0x%02x\n",
             Port.Xon, Port.Xoff, Port.Mflow);

      printf("Line Errors: ");
      if ( !(Port.Norun | Port.Noflow | Port.Nframe | Port.Nparity | Port.Nbreak))
      {
         printf("NONE\n");
      }
      else
      {
         if (Port.Norun)
         {
            printf("ORun=0x%08x ", Port.Norun);
         }
         if (Port.Noflow)
         {
            printf("OFlow=0x%08x ", Port.Noflow);
         }
         if (Port.Nframe)
         {
            printf("Frame=0x%08x ", Port.Nframe);
         }
         if (Port.Nparity)
         {
            printf("Parity=0x%08x ", Port.Nparity);
         }
         if (Port.Nbreak)
         {
            printf("Break=0x%08x ", Port.Nbreak);
         }
         printf("\n");
      }


      printf("Tout      =0x%08x\tTxBytesPending=0x%08x\n",
             Port.Tout, (Port.Tin - Port.Tout));


      printf("ReadBytes =0x%08x\n",
              Port.Rout);

      printf("\nRead & Write Timeouts(Hex):\n");

      printf("Read : Mult=%08x Total=%08x Inter=%08x Irp=0x%p\n",
             Port.Read.Timeout.Multiplier, Port.Read.Timeout.Total,
             Port.Read.Timeout.Interval, Port.Read.Timeout.Irp);

      printf("Write: Mult=%08x Total=%08x                Irp=0x%p\n",
             Port.Write.Timeout.Multiplier, Port.Write.Timeout.Constant,
             Port.Write.Timeout.Irp);

      printf("Wait : Mask=0x%04x   History=0x%04x  Irp=0x%p\n",
              Port.Wait.Mask, Port.Wait.History, Port.Wait.Irp);
      
	  printf("\n");

   }
   else
   {
      printf("Query failed %d\n", GetLastError());
   }
}
/**************************************************************************************
**
**	void ReportCardStatusAsyn( HANDLE hCtrl, DWORD ComPort )
**
**	Purpose: Is to report the Asyn status of the card.
**
***************************************************************************************/
void ReportCardStatusAsyn(HANDLE hCtrl, DWORD ComPort)
{
   CARD_STATUS Card;
   DWORD BytesReturned, i;
   BOOL Status;
   OVERLAPPED Overlapped;

   memset(&Overlapped, 0, sizeof(Overlapped));
   Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


   printf("Querying Card for COM%d\n", ComPort);
   Status = DeviceIoControl(hCtrl,
                            IOCTL_DIGI_GET_CONTROLLER_DATA,
                            &ComPort, sizeof(ComPort),
                            &Card, sizeof(Card),
                            &BytesReturned,
                            &Overlapped);
   if (!Status)
   {
      if (GetLastError()==ERROR_IO_PENDING)
      {
         Status = GetOverlappedResult(hCtrl,
                                      &Overlapped,
                                      &BytesReturned,
                                      TRUE);
      }
   }

   if (Status)
   {
      BOOLEAN fNoneOpen = TRUE;

      printf("Query successful.  %d bytes returned.\n", BytesReturned);
      printf("CardExt=0x%p\tState0x%04x\n", 
             Card.DeviceExt, Card.State);

      printf("Free Pools: Avail LowTide HighTide ElementSize:-\n");
      printf("Put Events: %5d %5d   %5d     %5d\n",
         Card.PutPool.Count, Card.PutPool.LowTide, 
         Card.PutPool.HighTide, Card.PutPool.Size);
      printf("Get Events: %5d %5d   %5d     %5d\n",
         Card.GetPool.Count, Card.GetPool.LowTide, 
         Card.GetPool.HighTide, Card.GetPool.Size);
      printf("Rx  Data  : %5d %5d   %5d     %5d\n",
         Card.RxPool.Count, Card.RxPool.LowTide, 
         Card.RxPool.HighTide, Card.RxPool.Size);
      printf("ExtRxData : %5d %5d   %5d     %5d\n",
         Card.ExtRxPool.Count, Card.ExtRxPool.LowTide, 
         Card.ExtRxPool.HighTide, Card.ExtRxPool.Size);

      printf("Total Active Ports= %d\n", Card.NumberOfPorts);
      printf("Active COM Numbers: ");

      for (i=0; i<MAX_DMODE_PORTS; i++)
      {
         if (Card.OpenPorts[i])
         {
            fNoneOpen = FALSE;
            printf("%d ", Card.OpenPorts[i]);
         }
      }
      if (fNoneOpen)
      {
         printf("NONE");
      }
      printf("\n");
   }
   else
   {
      printf("Query failed %d\n", GetLastError());
	  printf("Not a supported call by DigiAsyn.sys\n" );
   }

}
/******************************************************************************
**
**	void SetDebugLevel( HANDLE hCtrl, DWORD ComPort, DWORD Flags )
**
**	Purpose: To set the debug level
**
*******************************************************************************/
void SetDebugLevel(HANDLE hCtrl, DWORD ComPort, DWORD Flags)
{
   OVERLAPPED Overlapped;
   DWORD BytesReturned;
   BOOL Status;
   DIGI_IOCTL DebugLevel;

   printf("Setting DebugLevel for COM%d =0x%x\n", ComPort, Flags);

   memset(&Overlapped, 0, sizeof(Overlapped));
   Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


   DebugLevel.dwCommand = DIGI_IOCTL_TRACE;
   DebugLevel.dwBufferLength = sizeof(Flags);
   *((DWORD *)&DebugLevel.Char[0]) = Flags;

   Status = DeviceIoControl(hCtrl,
                            IOCTL_DIGI_CONTROLLER_SPECIAL,
                            &DebugLevel, sizeof(DebugLevel),
                            NULL, 0,
                            &BytesReturned,
                            &Overlapped);
   if (!Status)
   {
      if (GetLastError()==ERROR_IO_PENDING)
      {
         Status = GetOverlappedResult(hCtrl,
                                      &Overlapped,
                                      &BytesReturned,
                                      TRUE);
      }
   }

   if (Status)
   {
      printf("DebugLevel Set successful.  %d bytes returned.\n", BytesReturned);
   }
   else
   {
      printf("DebugLevel Set failed %d\n", GetLastError());
	  printf("Not a supported call by DigiAysn \n");
   }
}

