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

                                                 
extern void ReportCardStatusAsyn(HANDLE hCtrl, DWORD ComPort);
extern void ReportComStatus(HANDLE hCtrl, DWORD ComPort);
extern void ReportComStatusAsyn(HANDLE hCtrl, DWORD ComPort);
extern void Monitor(HANDLE hCtrl, DWORD ComPort, DWORD Flags);
extern void SetDebugLevel(HANDLE hCtrl, DWORD ComPort, DWORD Flags);

const CHAR RegSerialComm[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM";

CHAR DigiAsynPrefix[] = "\\\\.\\DIGIASYN";

void
CharToUpperBuff(
   char  *pPtr, 
   int   nLen
   )
{
   while (nLen--)
   {
      *pPtr = (char)toupper( *pPtr);
      pPtr++;
   }
}

BOOL FindDeviceForPort(DWORD ComPort, char *DeviceName, DWORD NameLength)
{
   LONG Status;
   HKEY hSerialCom = 0;
   char	tempName[64];
   int Result = 0;
   
   Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                         RegSerialComm,
                         0,
                         KEY_READ,
                         &hSerialCom);

   

   if (Status==ERROR_SUCCESS)
   {
      DWORD i, j;
      CHAR Value[MAX_PATH], Data[MAX_PATH];
      DWORD ValueLength, DataLength, Type, DataPort = 0;

      for (i=0; Status==ERROR_SUCCESS && ComPort!=DataPort; i++)
      {
         ValueLength = sizeof(Value);
         DataLength = sizeof(Data);

         Status = RegEnumValue(hSerialCom,
                               i,
                               Value,
                               &ValueLength,
                               0,
                               &Type,
                               Data,
                               &DataLength);

         if (Status==ERROR_SUCCESS)
         {
            CharToUpperBuff(Data, strlen(Data));
            Result = sscanf(Data, "COM%d", &DataPort);
            if ((Result != 0) && (Result != EOF))
            {
                if (DataPort==ComPort)
                {
				    CharToUpperBuff(Value, strlen(Value));
				    for (j=8; Value[j]>='A' && Value[j]<='Z' && j<NameLength-5; j++)
				    {
					    tempName[j-8] = Value[j];
				    }
				    for (; Value[j]>='0' && Value[j]<='9' && j<NameLength-5; j++)
				    {
					    tempName[j-8] = Value[j];
				    }
				    tempName[j-8] = '\0';

				    sprintf(DeviceName, "%s%s", DigiAsynPrefix,tempName);
                }
            }
         }
		 else
		 {
			 printf( "Error could not open the key\n");
		 }
      }
   }

   if (hSerialCom)
   {
      CloseHandle(hSerialCom);
   }

   return (BOOL)(Status==ERROR_SUCCESS);
}

void Usage()
{
   printf("dgmode v2.0\n");
   printf("\n\tCOM port utility for Digi Intelligent products.\n\n");
   printf("Usage: dgmode COMx Command [Parameters]\n");
   printf("\n");
   printf("Legal Commands:\n");
   printf("    Monitor - Allows monitoring of data, modem status and NT events.\n");
   printf("        Parameters: \n");
   printf("            -F# (Optional)  Allows user to specify what will be monitored.\n");
   printf("                To calculate #, add the following values:\n");
   printf("                1 - Data\n");
   printf("                2 - Modem Status signals\n");
   printf("                4 - NT Events\n");
   printf("                For example, -F1 will monitor only data, and -F7 (1+2+4) will \n");
   printf("                monitor Data, Modem Signals and NT Events.\n");
   printf("\n");
   printf("    Status - Returns internal driver status of individual port.  Information\n");
   printf("        may not be useful or intelligible to average user.\n\n");
   printf("    Card - Returns internal driver status of port's adapter.  Information\n");
   printf("        may not be useful or intelligible to average user.\n");
}

int _cdecl
main (int argc, char *argv[])
{
   DWORD i;
   DWORD ComPort = 0;
   char DeviceName[32];
   HANDLE hController;
   DWORD Flags = 0;
   BOOLEAN bDigiAsyn = FALSE;
   BOOLEAN bSetDebugLevel = FALSE;

   BOOL CardStatus = FALSE;
   BOOL ComStatus = FALSE;
   BOOL ComMonitor = FALSE;

   BOOL IsWin2k = FALSE;   // Default to NT4
   int Result = 0;

   if (argc <= 1)
   {
      Usage();
      return 0;
   }

   // determine at runtime which OS version: NT4 or Win2k
   {
      OSVERSIONINFO			version;

      version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

      if (GetVersionEx(&version))
         IsWin2k = version.dwMajorVersion > 4;
   }

   for (i=1; i<(DWORD)argc; i++)
   {
      CharToUpperBuff(argv[i], strlen(argv[i]));
      if (bSetDebugLevel)
      {
         Result = sscanf(argv[i], "%x", &Flags);
         if ((Result == 0) || (Result == EOF))
         {
            printf("Invalid parameter: %s\n", argv[i]);
            return 1;
         }
      }
      else if (!strncmp(argv[i], "COM", 3))
      {
         Result = sscanf(argv[i], "COM%d", &ComPort);
         if ((Result == 0) || (Result == EOF))
         {
            printf("Invalid parameter: %s\n", argv[i]);
            return 1;
         }
         printf("Com port %d\n", ComPort);

         if ( IsWin2k )
         {
            strcpy( DeviceName, "\\\\.\\DigiAsyn2dj" );
            bDigiAsyn = TRUE;
         }
         else
         {
			 printf( "The Device Name is %s\n", DeviceName );
             if (!FindDeviceForPort(ComPort, DeviceName, sizeof(DeviceName)))
             {
                 printf("COM%d not found %s\n", ComPort, DeviceName );
                 return 1;
             }
             if (!strncmp( DeviceName, DigiAsynPrefix, sizeof(DigiAsynPrefix)) -1)
             {
                 bDigiAsyn = TRUE;
			 }
  
		 }
      }
      else if (!strcmp(argv[i], "CARD"))
      {
         CardStatus = TRUE;
      }
      else if (!strcmp(argv[i], "STATUS"))
      {
         ComStatus = TRUE;
      }
      else if (!strcmp(argv[i], "MONITOR"))
      {
         ComMonitor = TRUE;
         Flags = 0x7;
      }
      else if (!strncmp(argv[i], "-F", 2))
      {
         Result = sscanf(argv[i], "-F%d", &Flags);
         if ((Result == 0) || (Result == EOF))
         {
            printf("Invalid parameter: %s\n", argv[i]);
            return 1;
         }
      }
      //
      // Allow setting the DebugMask for kernel debug traces.
      // This is a "hidden" feature, it's not reported in the usage types.
      // 
      else if (!strcmp(argv[i], "DEBUG"))
      {
         bSetDebugLevel = TRUE;
      }
      else if (!strncmp(argv[i], "-?", 2) ||
               !strncmp(argv[i], "-HELP", 5) ||
               !strncmp(argv[i], "HELP", 4))
      {
         Usage();
         return 0;
      }
      else
      {
         printf("Invalid parameter: %s\n", argv[i]);
         return 1;
      }
   }

   hController = CreateFile(DeviceName,
                            GENERIC_READ|GENERIC_WRITE, 
                            FILE_SHARE_READ|FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
                            INVALID_HANDLE_VALUE);
   if (hController==INVALID_HANDLE_VALUE)
   {
      printf("%s not found\a\n", DeviceName);
      return 1;
   }

   if (hController!=INVALID_HANDLE_VALUE)
   {
      if (CardStatus)
      {
         ReportCardStatusAsyn(hController, ComPort);
      }
      if (ComStatus)
      {
         if (bDigiAsyn)
         {
            ReportComStatusAsyn(hController, ComPort);
         }
         else
         {
            ReportComStatus(hController, ComPort);
         }
      }
      if (ComMonitor)
      {
         Monitor(hController, ComPort, Flags);
      }
      if (bSetDebugLevel)
      {
         SetDebugLevel( hController, ComPort, Flags);
      }
   }

   if (hController!=INVALID_HANDLE_VALUE)
   {
      CloseHandle(hController);
   }

   return 0;
}
