/****************************************************************/
/*                                                              */
/*          PROGRAM:  ELRAD.DLL                                 */
/*                                                              */
/*            MODUL:  ELRAD.C                                   */
/*                                                              */
/*      APPLICATION:  DASYLab DEMO DEVICE DRIVER                */
/*                    ELRAD Edition                             */
/*																*/
/*            TOOLS:  MS VISUAL C++ VERSION 1.0                 */
/*                                                              */
/*          CREATED:  1.7.1992 / R. Borghoff                    */
/*                                                              */
/*          CHANGES:  translated german -> english              */
/*                    installed interrupt handler               */
/*                    inserted comments for documentation       */
/*                    7.7.1993/FO                               */
/*                    synchron output                           */
/*                    24.7.1993/FO                              */
/*					  created sample signals for ELRAD 			*/
/*                                                      		*/
/*                                                              */
/*        COPYRIGHT:  (c) BY DATALOG 1992-1994                  */
/*                                                              */
/*          COMMENT:  This demo driver module is adapted from   */
/*					  the DASYLab toolkit for data acquisition  */
/*                    drivers. This module calculates signals   */
/*                    for different channels. Communication     */
/*                    is simulated by using an interrupt        */
/*                    handler to feed samples into the FIFOs.   */
/*                                                              */
/****************************************************************/

/********************** INCLUDE FILES ***************************/

/* Windows */
#include <windows.h>

/* Compiler */
#include <bios.h>
#include <dos.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* DASYLab driver interface */
#include "treiber.h"

/* application */
#include "elrad.h"

/********************** DEFINES *********************************/

/* to supress warnings of not used parameters */
#define UNUSED(X)                       X=X

/********************** PROTOTYPES ******************************/

/* Timer rate = 14.31818 MHz / 12.0 / 65536.0 = 18.2065... Hz */
#define TIMER_RATE   ( 14318180.0 / 12.0 / 65536.0 )

/* simulate hardware */
short ChValue (UINT, double, double, DWORD);    		/* simulates samples */
int SineWave (double, double);                  		/* calculate sine wave */
int SquareWave (double, double);                		/* calculate square wave */
int TriangleWave (double, double);              		/* ...       triangle wave */
int PulsPause (double, double);                 		/* ...       pulses */
int PeriodicStepResponse(double mV, double w);			/* simulates periodic step response of second order system */

/* interrupt handling */
void FAR interrupt INTHANDLER (void);   /* interrupt handling routine */
void InitIRQ (void);
void CloseIRQ (void);

void FillInfoStruct (void);
void KillBuffer (void);
void Help (HWND, int, WORD);
BOOL FAR PASCAL DlgCardDef (HWND, WORD, WORD, DWORD);
BOOL FAR PASCAL DlgAbout (HWND, WORD, WORD, DWORD);
BOOL FAR PASCAL DlgDummy (HWND, WORD, WORD, DWORD);
UINT AnzahlAktiveBits (DWORD CorpusDelicti);
static UINT Num_AI_Channels (void);

/****************** TYPES & VARS FOR TIMER-INTERRUPT HANDLING *****/

typedef struct RegistersTag
{
   unsigned ax;
   unsigned bx;
   unsigned cx;
   unsigned dx;
   unsigned cs;
   unsigned ds;
   unsigned es;
   unsigned si;
   unsigned di;
   unsigned bp;
   unsigned sp;
   unsigned ip;
   unsigned flags;
} REGISTERS;

typedef REGISTERS *PREGISTERS;
typedef REGISTERS NEAR *NPREGISTERS;
typedef REGISTERS FAR *LPREGISTERS;

#define DOSSVC_GETVECT          0x35
#define DOSSVC_SETVECT          0x25
#define INTNUM                  0x08

static union REGS Regs;
static struct SREGS SRegs;

static void (interrupt FAR * lpOldHandler) ();  /* Address of the old handler. */

/********************** GLOBALE VARIABLEN ***********************/


DRV_INFOSTRUCT far *InfoStruct; /* global Parameters */
char _huge *BufferAdr;          /* Communication Buffer for anal. Input */
LPSAMPLE bufferadr;             /* same Buffer as BufferAdr */
DWORD BlockSizeInSamples;       /* for fast acess */
DWORD BufferSizeInSamples;      /* "              */
DWORD StartTime;                /* for starttime of measure */
DWORD BlockNr;                  /* number of acquisited block */
DWORD FreqInMS;                 /* 1/Freqeunzy in ms */
BOOL MeasRun = FALSE;           /* status measure running */
DWORD MaxBlocks;
HANDLE hMemB1;                  /* handle tp memory block */
WORD InitOk = 0;                /* status driver init completed */
WORD AnzahlChannel;             /* count of aktive analog input channels */
DWORD GetIndex = 0;             /* index to last free buffer-element */
BOOL BufferVoll = FALSE;        /* status = data for DASYLab */
DWORD MaxBufferIndex = 0;       /* index of last buffer element */
DWORD MaxRamSize = DEFAULTRAMSIZE;
HANDLE hInst = NULL;            /* handle to previous WINDOWS-instance */
BOOL BufferFree = TRUE;         /* status buffer free */
int GainInfo[8] =
{-2, 1, 2, 4, 4, 4, 4, 4};      /* Gainvalues */
int EmptyGainInfo[8] =
{1, 1, 1, 1, 1, 1, 1, 1};       /* Gainvalues group 2 */
static char VxDVersion[80];
static char DLLVersion[80];
static char acStrBuffer[80];
static char acStrTemp[80];
static char szString[128];
int InputScanList[512];         /* list of channelnumbers to acquire */

 /* all volatile variables will be changed   */
 /* by interrupts or hardware at moments     */
 /* unknown to the compiler !!               */

volatile DWORD Info = 0;                /* Information about measure status */
volatile BOOL BufferWrapped = FALSE;    /* has FIFO pointer wrapped arround */
volatile DWORD BufferIndex = 0;         /* index to actual buffer-element   */
volatile DWORD count;                   /* count of interrupt-event         */

/* simulation */
double Input_mV;                /* amplitude of signals                     */
double freq;                    /* signal frequenzy                         */
BOOL OutputChannel;             /* is outputchannel active                  */
BOOL DigitalInput;
BOOL OutputDigital;
BOOL Counter;

volatile WORD Channel = 0;
volatile DWORD AOCount = 0;
volatile DWORD DOCount = 0;

HW_COMPONENT FAR HW_Comp[10];

/****************************************************************/
/*      NAME      : LibMain                                     */
/*      FUNKTION  : Init DLL                                    */
/****************************************************************/

BOOL FAR PASCAL __export LibMain (HINSTANCE hInstDLL, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
{
   BOOL bRVal = TRUE;

   UNUSED (lpszCmdLine);

   if (wHeapSize)
   {
      UnlockSegment (wDataSeg);
   }

   hInst = hInstDLL;

   return bRVal;
}


/****************************************************************/
/*      NAME      : WEP                                         */
/*      FUNKTION  : shut down DLL                               */
/****************************************************************/

int FAR PASCAL __export WEP (int nShutdownFlag)
{
   UNUSED (nShutdownFlag);

   return 1;
}


/****************************************************************/
/*      NAME      : INTHANDLER                                  */
/*      FUNKTION  : Interrupt-handling                          */
/****************************************************************/


void FAR interrupt INTHANDLER (void)
{
   if ((GetIndex > BufferIndex) && (!BufferWrapped))    /* check FIFO */
   {
      Info = DRV_AI_OVRRN;
   }
   else
   {
      if ( AnzahlChannel != 0 )
      {

         Channel %= AnzahlChannel;
   
         /* feed channel value in FIFO */
         bufferadr[BufferIndex] = (short) ChValue (InputScanList[Channel], Input_mV, freq, count / 4);
   
         /* increment FIFO index and wrap around */
         BufferIndex++;
         if (BufferIndex == BufferSizeInSamples)
         {
            BufferIndex = 0;
            BufferWrapped = TRUE;
         }
   
         /* and register interuppt call */
         count++;
   
         /* switch channel */
         Channel++;
      }

      if (Channel == AnzahlChannel)
      {
         if (DigitalInput)
         {
            static char DigCount = 0;

            bufferadr[BufferIndex] = (SAMPLE) ((~DigCount << 8) + DigCount);
            DigCount++;

            /* increment FIFO index and wrap around */
            BufferIndex++;
            if (BufferIndex == BufferSizeInSamples)
            {
               BufferIndex = 0;
               BufferWrapped = TRUE;
            }
         }

         if (Counter)
         {

            bufferadr[BufferIndex] = 1;

            /* increment FIFO index and wrap around */
            BufferIndex++;
            if (BufferIndex == BufferSizeInSamples)
            {
               BufferIndex = 0;
               BufferWrapped = TRUE;
            }
         }

         if (OutputChannel)
         {
            /* TO DO: place synchron output code here !!! */

            AOCount++;
            if (AOCount == InfoStruct->AO_BufferSize)
            {
               AOCount = 0;
            }
         }

         if (OutputDigital)
         {
            /* TO DO: place synchron output code here !!! */

            DOCount++;
            if (DOCount == InfoStruct->DO_BufferSize)
            {
               DOCount = 0;
            }
         }
      }
   }

   /* call original interrupt routine */
   lpOldHandler ();
}

/****************************************************************/
/*      NAME      : InitIRQ                                     */
/*      FUNKTION  : Initialize Interrupt-hander                 */
/****************************************************************/

void InitIRQ (void)
{
   /* see Compiler, BIOS and MSDOS docomentation */
   Regs.h.ah = DOSSVC_GETVECT;
   Regs.h.al = INTNUM;
   intdosx (&Regs, &Regs, &SRegs);
   FP_SEG (lpOldHandler) = SRegs.es;
   FP_OFF (lpOldHandler) = Regs.x.bx;

   /* Install the new interrupt handler. */
   Regs.h.ah = DOSSVC_SETVECT;
   Regs.h.al = INTNUM;
   SRegs.ds = HIWORD ((DWORD) INTHANDLER);
   Regs.x.dx = LOWORD ((DWORD) INTHANDLER);
   intdosx (&Regs, &Regs, &SRegs);
}

/****************************************************************/
/*      NAME      : CloseIRQ                                    */
/*      FUNKTION  : Resore old Interrupt-handling               */
/****************************************************************/

void CloseIRQ (void)
{
   /* Uninstall the interrupt handler. */
   Regs.h.ah = DOSSVC_SETVECT;
   Regs.h.al = INTNUM;
   SRegs.ds = HIWORD ((DWORD) lpOldHandler);
   Regs.x.dx = LOWORD ((DWORD) lpOldHandler);
   intdosx (&Regs, &Regs, &SRegs);
}


/****************************************************************/
/*  NAME      : DRV_GetBufStatus                                */
/*  FUNKTION  : 1 - if buffer full 0 - otherwise                */
/****************************************************************/

int FAR PASCAL __export DRV_GetBufStatus (void)
{
   long Delta;

   if (MaxBlocks == -1L)
      return FALSE;

   Delta = (long) BufferIndex - GetIndex;

   if (Delta < 0 && BufferWrapped)
   {
      Delta += BufferSizeInSamples;
   }

   InfoStruct->ADI_PercentFull = (100L * Delta) / BufferSizeInSamples;

   BufferVoll = (Delta >= (long) BlockSizeInSamples);

   return BufferVoll;
}


/****************************************************************/
/*      NAME      : DRV_GetBuf                                  */
/*      FUNKTION  : gets buffer adress, locks buffer            */
/****************************************************************/

LPSAMPLE FAR PASCAL __export DRV_GetBuf (void)
{
   LPSAMPLE lHilf;

   if (BufferVoll)
   {
      /* get adress of data */

      lHilf = ((LPSAMPLE) bufferadr) + GetIndex;

      /* increment number of processed data block */
      BlockNr++;
   }
   else
   {
      lHilf = 0l;
   }

   return lHilf;
}



/****************************************************************/
/*      NAME      : DRV_SetBufFree                              */
/*      FUNKTION  : unlocks buffer                              */
/****************************************************************/

int FAR PASCAL __export DRV_SetBufFree (void)
{

   /* mark processed data - one block processed */
   GetIndex += BlockSizeInSamples;

   if (GetIndex >= BufferSizeInSamples)
   {
      GetIndex %= BufferSizeInSamples;
      BufferWrapped = FALSE;
   }

   if (MaxBlocks && !--MaxBlocks)
   {
      DRV_StopMeas ();
      MaxBlocks = (DWORD) - 1L;
   }

   return DRV_FUNCTION_OK;
}

/****************************************************************/
/*      NAME      : DRV_GetMeasInfo                             */
/*      FUNKTION  :                                             */
/****************************************************************/

DWORD FAR PASCAL __export DRV_GetMeasInfo (void)
{
   /* during acquisition the interrupt handler sets the global variable info */

   return Info;
}



/****************************************************************/
/*      NAME      : DRV_ShowError                               */
/*      FUNKTION  : M.Box with error message                    */
/****************************************************************/

int FAR PASCAL __export DRV_ShowError (void)
{
   LoadString (hInst, (int) InfoStruct->Error, ((LPSTR) acStrBuffer), 75);
   wsprintf (szString, "%s", (LPSTR) acStrBuffer);
   MessageBox (GetActiveWindow (), szString, MESSAGE_HEADER, MB_OK | MB_ICONSTOP);
   InfoStruct->Error = 0;

   return DRV_FUNCTION_OK;
}



/****************************************************************/
/*      NAME      : FillInfoStruct                              */
/*      FUNKTION  : internal routine to fill info struct        */
/****************************************************************/

void FillInfoStruct (void)
{
   UINT n;
   static char HelpFile[16];

   LoadString (hInst, STR_CARDTYP_0, acStrBuffer, 12);
   _fstrcpy (InfoStruct->DeviceName, (LPSTR) acStrBuffer);

   InfoStruct->Features = SUPPORT_DEFAULT | SUPPORT_OUT_ALL;
   InfoStruct->SupportedAcqModes = DRV_AQM_CONTINUOUS | DRV_AQM_STOP;
   InfoStruct->MaxFreq = 18.21;
   InfoStruct->MinFreq = 18.2;

   InfoStruct->Max_AI_Channel = 8;
   InfoStruct->Max_AO_Channel = 1;
   InfoStruct->Max_DI_Channel = 1;
   InfoStruct->Max_DO_Channel = 1;
   InfoStruct->Max_CT_Channel = 1;
   InfoStruct->DIO_Width = 16;

   /* Several default settings */
   _fmemset (HW_Comp, 0, sizeof (HW_Comp));
   _fmemset (InfoStruct->AI_ChInfo, 0, sizeof (InfoStruct->AI_ChInfo));
   _fmemset (InfoStruct->DI_ChInfo, 0, sizeof (InfoStruct->DI_ChInfo));
   _fmemset (InfoStruct->CT_ChInfo, 0, sizeof (InfoStruct->CT_ChInfo));
   _fmemset (InfoStruct->AO_ChInfo, 0, sizeof (InfoStruct->AO_ChInfo));
   _fmemset (InfoStruct->DO_ChInfo, 0, sizeof (InfoStruct->DO_ChInfo));

   /* Channels vs. Hardware */
   InfoStruct->NumHardwareComponents = 2;
   InfoStruct->HW_Comp = HW_Comp;

   /* First Hardware component */
   strcpy (HW_Comp[0].ShortName, "First");
   strcpy (HW_Comp[0].LongName, "First Hardware Component");
   HW_Comp[0].AI.FirstChan = 0;
   HW_Comp[0].AI.NumChannels = 5;
   HW_Comp[0].AI.GainInfo = InfoStruct->GainInfo;
   HW_Comp[0].AO.FirstChan = 0;
   HW_Comp[0].AO.NumChannels = 1;
   HW_Comp[0].DI.FirstChan = 0;
   HW_Comp[0].DI.NumChannels = 1;
   HW_Comp[0].DO.FirstChan = 0;
   HW_Comp[0].DO.NumChannels = 1;
   HW_Comp[0].CT.FirstChan = 0;
   HW_Comp[0].CT.NumChannels = 1;

   /* Second Hardware component (assume second channel to be reserved) */
   strcpy (HW_Comp[1].ShortName, "Second");
   strcpy (HW_Comp[1].LongName, "Second Hardware Component");
   HW_Comp[1].AI.FirstChan = 5;
   HW_Comp[1].AI.NumChannels = 3;
   HW_Comp[1].AI.GainInfo = EmptyGainInfo;

   for (n = 0; n < InfoStruct->Max_AO_Channel; n++)
   {
      InfoStruct->AO_ChInfo[n].OutputRange_Min = -5.0;
      InfoStruct->AO_ChInfo[n].OutputRange_Max = 5.0;
      InfoStruct->AO_ChInfo[n].Resolution = 4096L;      /* == 12 Bit */
   }

   for (n = 0; n < InfoStruct->Max_AI_Channel; n++)
   {
      InfoStruct->AI_ChInfo[n].InputRange_Max = +5.0;
      InfoStruct->AI_ChInfo[n].InputRange_Min = -5.0;
      InfoStruct->AI_ChInfo[n].Resolution = 16384L;     /* == 14 Bit */
      InfoStruct->AI_ChInfo[n].BaseUnit = DRV_BASE_UNIT_2COMP;
   }

   /* Assume for demonstration that channel 1 is not available */
   InfoStruct->AI_ChInfo[1].Flags |= AI_FLG_UNAVAILABLE;

   for (n = 0; n < 8; n++)
   {
      InfoStruct->GainInfo[n] = GainInfo[n];
   }

   /* Assume one digital port with the lower 12 bits as input and the upper 4 as output */
   InfoStruct->DI_ChInfo[0].AvailBits = 0x0FFF;
   InfoStruct->DO_ChInfo[0].AvailBits = 0xF000;

   /* Set default gain */
   for (n = 0; n < HW_Comp[0].AI.NumChannels; n++)
   {
      InfoStruct->AI_ChSetup[n].GainCode = 1;
   }
   for (; n < InfoStruct->Max_AI_Channel; n++)
   {
      InfoStruct->AI_ChSetup[n].GainCode = 0;
   }

   LoadString (hInst, STR_HELPFILE, (LPSTR) acStrBuffer, 13);
   lstrcpy ((LPSTR) HelpFile, (LPSTR) acStrBuffer);
   InfoStruct->HelpFileName = HelpFile;
   InfoStruct->HelpIndex = 0;
   LoadString (hInst, STR_VERSION, (LPSTR) szString, 32);
   wsprintf ((LPSTR) DLLVersion, "%s/%s", (LPSTR) szString, (LPSTR) __DATE__);
   InfoStruct->DLL_Version = DLLVersion;
   wsprintf ((LPSTR) VxDVersion, "%s", (LPSTR) "-----/-----");
   InfoStruct->VxD_Version = VxDVersion;
}


/****************************************************************/
/*      NAME      : DRV_AllocDADIOBuffer                        */
/*      FUNKTION  : recalculates buffer size                    */
/*        PARAMETER 1 --> size of buffer in samples             */
/****************************************************************/

LPSAMPLE FAR PASCAL __export DRV_AllocDADIOBuffer (DWORD Size, LPHBUFFER hBuf)
{
   LPSTR bufferadr;
   HANDLE hMem;

   if (Size > 64 * 1024L)
   {
      Size = 64 * 1024L;
   }

   if (!MeasRun)
   {
      Size = Size * sizeof (SAMPLE);
      GlobalCompact ((DWORD) Size);
      hMem = GlobalAlloc (SPEICHERMODE, (DWORD) Size);
      if (!hMem)
      {
         InfoStruct->Error = DRV_ERR_NOTENOUGHMEM;
         return NULL;
      }
      GlobalFix (hMem);
      GlobalPageLock ((HGLOBAL) hMem);
      bufferadr = GlobalLock (hMem);
      *hBuf = ((DWORD) ((WORD) hMem) << 16);
      return (LPSAMPLE) bufferadr;
   }

   InfoStruct->Error = DRV_ERR_MEASRUN;
   return NULL;
}


/****************************************************************/
/*      NAME      : DRV_KillDADIOBuffer                         */
/*      FUNKTION  : frees previous allocated global memory      */
/****************************************************************/

int FAR PASCAL __export DRV_KillDADIOBuffer (HBUFFER hBuf)
{
   HANDLE hMem;

   hMem = (HANDLE) HIWORD (hBuf);
   if (!MeasRun)
   {
      GlobalUnfix (hMem);
      GlobalPageUnlock ((HGLOBAL) hMem);
      GlobalUnlock (hMem);
      GlobalFree (hMem);
      return DRV_FUNCTION_OK;
   }

   InfoStruct->Error = DRV_ERR_MEASRUN;
   return DRV_FUNCTION_FALSE;
}


/****************************************************************/
/*      NAME      : DRV_AllocADIBuffer                          */
/*      FUNKTION  : recalculate size of buffer                  */
/*        PARAMETER 1 --> size of buffer in samples             */
/****************************************************************/

int FAR PASCAL __export DRV_AllocADIBuffer (DWORD Size)
{
   if (!MeasRun)
   {
      KillBuffer ();
      MaxRamSize = Size * sizeof (SAMPLE);
      GlobalCompact ((DWORD) MaxRamSize);
      hMemB1 = GlobalAlloc (SPEICHERMODE, (DWORD) MaxRamSize);
      if (!hMemB1)
      {
         MaxRamSize = 0;
         InfoStruct->DriverBufferSize = 0;
         InfoStruct->Error = DRV_ERR_NOTENOUGHMEM;
         BufferFree = TRUE;
         return DRV_FUNCTION_FALSE;
      }
      GlobalFix (hMemB1);
      GlobalPageLock ((HGLOBAL) hMemB1);
      BufferAdr = (char _huge *) GlobalLock (hMemB1);
      BufferFree = FALSE;
      InfoStruct->DriverBufferSize = Size;
      return DRV_FUNCTION_OK;
   }
   InfoStruct->Error = DRV_ERR_MEASRUN;
   return DRV_FUNCTION_FALSE;
}



/****************************************************************/
/*      NAME      : DRV_InitDevice                              */
/*      FUNKTION  : installed  VDALOG.386                       */
/*        PARAMETER 1 --> ADRESS OF INFOSTRUKT                  */
/****************************************************************/

int FAR PASCAL __export DRV_InitDevice (DRV_INFOSTRUCT far * StructAdr)
{

   if (!InitOk)
   {
      /* store pointer to parameter struct */
      InfoStruct = (DRV_INFOSTRUCT far *) StructAdr;


      /* check DASYLab Version on consistence */
      
      if ( (InfoStruct->Version != DRV_VERSION) && (InfoStruct->Version != DRV_VERSION_DEMO) )
      {
         LoadString (hInst, STR_WRONGSTRUCT, ((LPSTR) acStrTemp), 40);
         wsprintf (szString, "%s", (LPSTR) acStrTemp);
         MessageBox (GetActiveWindow (), szString, MESSAGE_HEADER, MB_OK | MB_ICONSTOP);
         return DRV_FUNCTION_FALSE;
      }
      
      
      _fstrcpy (InfoStruct->DriverName, "Demo Driver from Driver Toolkit");
      LoadString (hInst, STR_VERSION, (LPSTR) szString, 32);
      wsprintf ((LPSTR) DLLVersion, "%s/%s", (LPSTR) szString, (LPSTR) __DATE__);
      InfoStruct->DLL_Version = DLLVersion;
      wsprintf ((LPSTR) VxDVersion, "%s", (LPSTR) "-----/-----");
      InfoStruct->VxD_Version = VxDVersion;
      InitOk = (WORD) DRV_AllocADIBuffer (DEFAULTRAMSIZE);
      FillInfoStruct ();

      /* Set default frequency + block size */
      InfoStruct->AI_Frequency = TIMER_RATE;
      InfoStruct->ADI_BlockSize = 8;

      return InitOk;
   }
   return DRV_FUNCTION_FALSE;
}


/****************************************************************/
/*  NAME      : DRV_TestStruct                                  */
/*  FUNKTION  : Test parameters of INFOSTRUCT                   */
/****************************************************************/

int FAR PASCAL __export DRV_TestStruct (void)
{
   DWORD MinBuffer;
   DWORD BlockSize;
   int c, i;                    /* for-loop variables */

   /* initialization complete */
   if (!InitOk)
   {
      InfoStruct->Error = DRV_ERR_DEVICENOTINIT;
      return DRV_FUNCTION_FALSE;
   }
   /* TestStruct nevver called during acquisition */
   if (MeasRun)
   {
      InfoStruct->Error = DRV_ERR_MEASRUN;
      return DRV_FUNCTION_FALSE;
   }
   /* When TestStruct called, all buffers must be allocated */
   if (BufferFree)
   {
      InfoStruct->Error = DRV_ERR_NOTENOUGHMEM;
      return DRV_FUNCTION_FALSE;
   }
   /* check if buffersize not to big */
   if (InfoStruct->DriverBufferSize * sizeof (SAMPLE) != MaxRamSize)
   {
      InfoStruct->Error = DRV_ERR_BUFSIZETOBIG;
      return DRV_FUNCTION_FALSE;
   }
   /* check if any channel is active */
   if (!(Num_AI_Channels ()) && !(InfoStruct->DI_Channel) && !(InfoStruct->CT_Channel) &&
       !(InfoStruct->AO_Channel) && !(InfoStruct->DO_Channel))
   {
      InfoStruct->Error = DRV_ERR_NOCHANNEL;
      return DRV_FUNCTION_FALSE;
   }
   /* check rate-parameters */
   if (InfoStruct->AI_Frequency > InfoStruct->MaxFreq)
   {
      InfoStruct->AI_Frequency = InfoStruct->MaxFreq;
      InfoStruct->Error = DRV_WARN_CHANGEFREQ;
      return DRV_FUNCTION_FALSE;
   }
   if (InfoStruct->AI_Frequency < InfoStruct->MinFreq)
   {
      InfoStruct->AI_Frequency = InfoStruct->MinFreq;
      InfoStruct->Error = DRV_WARN_CHANGEFREQ;
      return DRV_FUNCTION_FALSE;
   }
   /* this driver can work with one rate = 18.2 Hz */
   if (InfoStruct->AI_Frequency != InfoStruct->MaxFreq)
   {
      InfoStruct->AI_Frequency = InfoStruct->MaxFreq;
   }
   if (InfoStruct->DI_FreqRate <= 0)
      InfoStruct->DI_FreqRate = 1;
   if (InfoStruct->AO_FreqRate <= 0)
      InfoStruct->AO_FreqRate = 1;
   if (InfoStruct->DO_FreqRate <= 0)
      InfoStruct->DO_FreqRate = 1;


   /* be sure, that the whole bufferlength is */
   /* a multiple of the blocksize                         */

   if (InfoStruct->DriverBufferSize * sizeof (SAMPLE) != MaxRamSize)
      DRV_AllocADIBuffer (InfoStruct->DriverBufferSize);
   BlockSize = InfoStruct->ADI_BlockSize * sizeof (SAMPLE);     /* Recalculate from SAMPLES to BYTES */
   MinBuffer = BlockSize * (MaxRamSize / BlockSize);
   if (MinBuffer != MaxRamSize)
   {
      DRV_AllocADIBuffer (MinBuffer / sizeof (SAMPLE));
   }

   BufferIndex = 0l;
   MaxBufferIndex = MaxRamSize / sizeof (SAMPLE);
   BlockNr = 0;

   /* calculate count of active channels */
   AnzahlChannel = (WORD) (Num_AI_Channels ());
   OutputChannel = (BOOL) (InfoStruct->AO_Channel != (DWORD) 0);
   DigitalInput = (BOOL) (InfoStruct->DI_Channel != (DWORD) 0);
   OutputDigital = (BOOL) (InfoStruct->DO_Channel != (DWORD) 0);
   Counter = (BOOL) (InfoStruct->CT_Channel != (DWORD) 0);

   /* check and store which channels to poll in local array (access-time) */
   for (c = 0, i = 0; i < 512; i++)
   {
      if (InfoStruct->AI_Channel[i >> 4] & (1L << (i & 15)))
      {
         InputScanList[c] = i + 1;
         c++;
      }
   }

   /* calculate sizes in sample */
   BlockSizeInSamples = InfoStruct->ADI_BlockSize;
   BufferSizeInSamples = InfoStruct->DriverBufferSize;

   FreqInMS = (DWORD) (1000.0 / (InfoStruct->AI_Frequency / BlockSize));

   return DRV_FUNCTION_OK;
}



/****************************************************************/
/*      NAME      : DRV_StartMeas                               */
/*      FUNKTION  :                                             */
/****************************************************************/


UINT AnzahlAktiveBits (DWORD CorpusDelicti)
{
   UINT Result = 0;
   DWORD Maske = 1L;
   int i;

   for (i = 0; i < 32; i++)
   {
      if ((Maske & CorpusDelicti) != 0)
         Result++;
      Maske <<= 1;
   }
   return Result;
}


static UINT Num_AI_Channels (void)
{
   UINT NumAI;

   UINT i;

   NumAI = 0;
   for (i = 0; i < 32; i++)
      NumAI += AnzahlAktiveBits (InfoStruct->AI_Channel[i]);

   return NumAI;
}

void SetSimulationValues ()
{
   Input_mV = 4000.0;
   freq = 0.03;
}


int FAR PASCAL __export DRV_StartMeas (void)
{
   HCURSOR OldCursor;

   /* show WAIT-status with cursor                           */
   OldCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));

   /* set internal status variables */
   MeasRun = TRUE;                               /* process running   */
   Info = DRV_MEASRUN;                           /* hardware acquires */

   if (InfoStruct->AcquisitionMode == DRV_AQM_STOP)
      MaxBlocks = InfoStruct->MaxBlocks;
   else
      MaxBlocks = 0;

   /* set amplitude and frequenzy of signals */
   SetSimulationValues ();

   /* (re-)set vars for buffer handling */
   count = 0;
   BufferWrapped = FALSE;
   GetIndex = 0;
   bufferadr = (short _huge *) BufferAdr;

   Channel = 0;
   AOCount = 0;
   DOCount = 0;

   /* store time */
   StartTime = GetCurrentTime ();

   /* chain new interrupt vector */
   InitIRQ ();

   /* reset cursor */
   SetCursor (OldCursor);

   /* Only for demo purpose: Show some meessage */
   strcpy (InfoStruct->Message, "run");

   /* interrupt working, and done ... */
   return DRV_FUNCTION_OK;
}


/****************************************************************/
/*      NAME      : DRV_StopMeas                                */
/*      FUNKTION  :                                             */
/****************************************************************/

int FAR PASCAL __export DRV_StopMeas (void)
{
   Info = 0;

   strcpy (InfoStruct->Message, "");

   if (InitOk)                                   /* IST TREIBER INSTALLIERT ? */
   {
      if (MeasRun)
      {
         CloseIRQ ();
         MeasRun = FALSE;
      }
      MaxBlocks = 0;
      return DRV_FUNCTION_OK;
   }
   else
   {
      InfoStruct->Error = DRV_ERR_DEVICENOTINIT;
      return DRV_FUNCTION_FALSE;
   }
}



/****************************************************************/
/*      NAME      : DRV_KillDevice                              */
/*      FUNKTION  : frees resourcen                             */
/****************************************************************/

int FAR PASCAL __export DRV_KillDevice (void)
{
   if (InitOk)
   {
      KillBuffer ();            /* SPEICHER FREIGEBEN      */
      InitOk = FALSE;

      return DRV_FUNCTION_OK;
   }
   return DRV_FUNCTION_FALSE;
}



/****************************************************************/
/*      NAME      : KillBuffer                                  */
/*      FUNKTION  : frees global memory                         */
/*      GEAENDERT : 29.06.92                                    */
/****************************************************************/

void KillBuffer (void)
{
   if (!BufferFree)
   {
      GlobalUnfix (hMemB1);
      GlobalPageUnlock ((HGLOBAL) hMemB1);
      GlobalUnlock (hMemB1);
      GlobalFree (hMemB1);
      BufferFree = TRUE;
   }
}

/**** the folowing routines are not used in this example
***** they represent dummy-routines which sets the error
***** variables !!
****/

/****************************************************************/
/*      NAME      : DRV_WriteAO                                 */
/*      FUNKTION  : writes asynchron analog output              */
/*        PARAMETER 1 --> channel                               */
/*                PARAMETER 2 --> value                         */
/****************************************************************/


int FAR PASCAL __export DRV_WriteAO (DWORD ch, DWORD wert)
{

   HCURSOR hcur;

   /* here is the place for output routines                     */
   /* we show an wait cursor instead                            */
   /* this is just to show the output function                  */

   hcur = SetCursor (LoadCursor (NULL, IDC_WAIT));
   SetCursor (hcur);

   UNUSED (ch);
   UNUSED (wert);

   return DRV_FUNCTION_OK;
}

/****************************************************************/
/*      NAME      : DRV_WriteDO                                 */
/*      FUNKTION  : writes asynchron digital output             */
/*        PARAMETER 1 --> channel                               */
/*        PARAMETER 2 --> value                                 */
/****************************************************************/

int FAR PASCAL __export DRV_WriteDO (DWORD ch, DWORD wert)
{
   InfoStruct->Error = DRV_ERR_NOHWSUPPORT;

   UNUSED (ch);
   UNUSED (wert);

   return DRV_FUNCTION_FALSE;
}

/****************************************************************/
/*      NAME      : DRV_ReadDI                                  */
/*      FUNKTION  : reads digital channel                       */
/*        PARAMETER 1 --> KANAL                                 */
/*      GEAENDERT : 17.07.92                                    */
/****************************************************************/

int FAR PASCAL __export DRV_ReadDI (DWORD ch, LPDWORD wert)
{
   InfoStruct->Error = DRV_ERR_NOHWSUPPORT;

   UNUSED (ch);
   UNUSED (wert);

   return DRV_FUNCTION_FALSE;
}

/****************************************************************/
/*      NAME      : DRV_ReadCT                                  */
/*      FUNKTION  : read counter                                */
/****************************************************************/

int FAR PASCAL __export DRV_ReadCT (DWORD ch, LPDWORD wert)
{
   InfoStruct->Error = DRV_ERR_NOHWSUPPORT;

   UNUSED (ch);
   UNUSED (wert);

   return DRV_FUNCTION_FALSE;
}


/****************************************************************/
/*      NAME      : DRV_ExplainGainCode                         */
/****************************************************************/

static char FAR *ComposeGainString (int Channel, int GainValue)
{
   double range = fabs (InfoStruct->AI_ChInfo[Channel].InputRange_Max);
   static char Result[40];
   int exp = 0;
   int j;

   if (GainValue == 0)
      GainValue = 1;

   if (GainValue > 0)
      range /= GainValue;
   else
      range *= -GainValue;

   while (range > 1000.0)
   {
      range /= 1000.0;
      exp += 3;
   }

   while (range != 0.0 && range < 1.0)
   {
      range *= 1000.0;
      exp -= 3;
   }

   if (InfoStruct->AI_ChInfo[Channel].InputRange_Min == 0.0)
      strcpy (Result, " 0 - ");
   else
      strcpy (Result, " +/- ");
   {
      int decimal, sign;
      char FAR *buffer;
      buffer = _fcvt (range, 3, &decimal, &sign);
      if (decimal > 0)
         strncat (Result, buffer, decimal);
      strcat (Result, ".");
      strcat (Result, buffer + decimal);
   }

   j = strlen (Result);
   while (Result[j - 1] == '0')
   {
      Result[j - 1] = '\0';
      j--;
   }
   if (Result[j - 1] == '.')
   {
      Result[j - 1] = '\0';
      j--;
   }
   strcat (Result, " ");

   switch (exp)
   {
   case 6:
      strcat (Result, "M");
      break;
   case 3:
      strcat (Result, "k");
      break;
   case 0:
      break;
   case -3:
      strcat (Result, "m");
      break;
   case -6:
      strcat (Result, "u");
      break;
   case -9:
      strcat (Result, "n");
      break;
   default:
      strcat (Result, "?");
      break;
   }

   strcat (Result, "V");

   return Result;
}


char FAR *FAR PASCAL __export DRV_ExplainGainCode (SCAN_ENTRY Chan, UINT GainCode)
{
   UINT i;

   if (SCAN_TYPE (Chan) == SCAN_TYPE_AI && SCAN_CHAN (Chan) < 512)
   {
      for (i = 0; i < InfoStruct->NumHardwareComponents; i++)
      {
         if (SCAN_CHAN (Chan) >= HW_Comp[i].AI.FirstChan &&
             SCAN_CHAN (Chan) < HW_Comp[i].AI.FirstChan + HW_Comp[i].AI.NumChannels)
            if (HW_Comp[i].AI.GainInfo != NULL)
               return ComposeGainString (SCAN_CHAN (Chan), HW_Comp[i].AI.GainInfo[GainCode]);
            else
               return ComposeGainString (SCAN_CHAN (Chan), InfoStruct->GainInfo[GainCode]);
      }
   }

   return " ? ? ? ";
}


/****************************************************************/
/*      NAME      : DRV_ShowDialog                              */
/*      FUNKTION  :                                             */
/*        PARAMETER 1 --> WINDOW HANDLE                         */
/*        PARAMETER 2 --> DIALOGBOX NUMBER                      */
/****************************************************************/

int FAR PASCAL __export DRV_ShowDialog (UINT BoxNr, DWORD ExtraPara)
{
   FARPROC lpProc;
   HWND hWnd;

   UNUSED (ExtraPara);

   /* get actual window */
   hWnd = GetActiveWindow ();

   /* check driver */
   if (!InitOk)
   {
      InfoStruct->Error = DRV_ERR_DEVICENOTINIT;
      return DRV_FUNCTION_FALSE;
   }

   /* select Dialog  */
   switch (BoxNr)
   {
   case DLG_CARD_DEF:                            /* card specific dialog */
      /* different hardware -> different window structure */
      lpProc = MakeProcInstance ((FARPROC) DlgCardDef, (HINSTANCE) hInst);
      DialogBox ((HINSTANCE) hInst, (LPCSTR) "CARDDEF", (HWND) hWnd, (DLGPROC) lpProc);
      FreeProcInstance (lpProc);
      break;
   case DLG_ABOUT:                               /* info dialog: who has done what ... */
      lpProc = MakeProcInstance ((FARPROC) DlgAbout, (HINSTANCE) hInst);
      DialogBox ((HINSTANCE) hInst, (LPCSTR) "AboutBox", (HWND) hWnd, (DLGPROC) lpProc);
      FreeProcInstance (lpProc);
      break;
   default:                                      /* dialog does not exist */
      LoadString (hInst, STR_NODLGBOX, ((LPSTR) szString), 80);
      MessageBox (GetActiveWindow (), szString, MESSAGE_HEADER, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
   }

   return DRV_FUNCTION_OK;
}

/****************************************************************/
/* NAME      : Help                                             */
/* FUNKTION  : shows online help                                */
/****************************************************************/
void Help (HWND hWndDlg, int cardtyp, WORD BoxNr)
{
   if (cardtyp & BoxNr)         /* to get no warning */
      return;      
      
   UNUSED(hWndDlg);
   
   MessageBox( GetActiveWindow(), "Keine Hilfe verfügbar", "ELRAD Treiber Simulation", MB_OK|MB_ICONINFORMATION);
}

/****************************************************************/
/*      NAME      : DlgCardDef                                  */
/*      FUNKTION  : administration of dialog                    */
/*      PARAMETER 1 --> WINDOW HANDLE                           */
/*      PARAMETER 2 --> MESSAGE                                 */
/*      PARAMETER 3 --> WORD PARAMETER                          */
/*      PARAMETER 4 --> DWORD PARAMETER                         */
/****************************************************************/

BOOL FAR PASCAL __export DlgCardDef (HWND hWndDlg, WORD message, WORD wParam, DWORD lParam)
{
   lParam = 0;
   switch (message)
   {
   case WM_INITDIALOG:
      return TRUE;
   case WM_COMMAND:
      switch (wParam)
      {
      case IDOK:
         EndDialog (hWndDlg, TRUE);
         return TRUE;
      case IDHELP:
         Help (hWndDlg, 0, 0);
         break;
      }
   }
   return FALSE;
}


/****************************************************************/
/*      NAME      : DlgAbout     (INFO )                        */
/*      FUNKTION  : administration of dialog                    */
/*      PARAMETER 1 --> WINDOW HANDLE                           */
/*      PARAMETER 2 --> MESSAGE                                 */
/*      PARAMETER 3 --> WORD PARAMETER                          */
/*      PARAMETER 4 --> DWORD PARAMETER                         */
/****************************************************************/

BOOL FAR PASCAL __export DlgAbout (HWND hDlg, WORD message, WORD wParam, DWORD lParam)
{
   HWND hCtl;

   lParam = 0;
   switch (message)
   {
   case WM_INITDIALOG:
      LoadString (hInst, STR_VERSION, szString, 32);
      hCtl = GetDlgItem (hDlg, ID_VERSION);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) szString);
      hCtl = GetDlgItem (hDlg, ID_VERSION_DATE);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) __DATE__);
      hCtl = GetDlgItem (hDlg, ID_VERSION_TIME);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) __TIME__);
      hCtl = GetDlgItem (hDlg, ID_VXDVERSION);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) "Author :");
      hCtl = GetDlgItem (hDlg, ID_VXDVERSION_DATE);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) "R. Borghoff");
      hCtl = GetDlgItem (hDlg, ID_VXDVERSION_TIME);
      SendMessage (hCtl, WM_SETTEXT, 0, (DWORD) (LPSTR) "1992");
      return TRUE;
   case WM_COMMAND:
      switch (wParam)
      {
      case IDOK:
         EndDialog (hDlg, TRUE);
         return TRUE;
      case IDCANCEL:
         EndDialog (hDlg, TRUE);
         return TRUE;
      }
   }
   return FALSE;
}


/****************************************************************/
/*      NAME      : ChValue                                     */
/*      FUNKTION  :                                             */
/****************************************************************/

SAMPLE ChValue (UINT channel, double Input_mV, double freq, DWORD x)
{
   double gain, mV;
   SAMPLE value = 0;

   gain = InfoStruct->GainInfo[InfoStruct->AI_ChSetup[channel].GainCode];
   if (gain < 0)
      gain = -1.0 / gain;

   mV = Input_mV * gain;
   freq *= (2L << (2 * ((channel / 4))));

   switch (channel%5)
   {        
   case 0:
      value += (SAMPLE) SineWave (mV, x * freq);
      break;
   case 1:
      value += (SAMPLE) PeriodicStepResponse (mV, x * freq);
      break;
   case 2:
      value += (SAMPLE) TriangleWave (mV, x * freq);
      break;
   case 3:
      value += (SAMPLE) SquareWave (mV, x * freq);
      break;
   case 4:
      value += (SAMPLE) PulsPause (mV, x * freq);
      break;          
   }
   return (SAMPLE) value;
}

/****************************************************************/
/*      NAME      : SineWave                                    */
/*      FUNKTION  :                                             */
/*        PARAMETER 1 -->                                       */
/*        PARAMETER 2 -->                                       */
/****************************************************************/

int SineWave (double mV, double w)
{
   return (int) (mV * sin (w));
}


/****************************************************************/
/*      NAME      : SquareWave                                  */
/*      FUNKTION  :                                             */
/*        PARAMETER 1 -->                                       */
/*        PARAMETER 2 -->                                       */
/****************************************************************/

int SquareWave (double mV, double w)
{
   if (((DWORD) (w / M_PI)) & 1)
      return (int) -mV;
   else
      return (int) mV;
}

int TriangleWave (double mV, double w)
{
   DWORD hilf = ((DWORD) (w / M_PI));

   if (hilf & 1)
      return (int) (mV * (-1.0 + 2.0 * (w / M_PI - hilf)));
   else
      return (int) (mV * (1.0 - 2.0 * (w / M_PI - hilf)));
}

int PulsPause (double mV, double w)
{
   DWORD hilf = ((DWORD) (2.0 * w / M_PI));

   if (hilf & 3)
      return (int) -mV;
   else
      return (int) mV;
}

int PERIOD = 20;

int PeriodicStepResponse(double mV, double w)
{   
	int 	OUTPUT;
	double 	Amplitude;
	
	while (w > PERIOD) w -=PERIOD;
	
	OUTPUT = 0;
	if (w > PERIOD/2)
	{          
		OUTPUT = (int) (mV*(1.-exp(-1.0*(w-PERIOD/2))));
	}
	Amplitude = mV/10.;
	if (w > PERIOD/2) 
	{
		Amplitude = mV/2;
		w -= PERIOD/2;
	}
	
	OUTPUT += (int) (Amplitude*sin( 10.*w)*exp(-0.6*w));
	
	return OUTPUT;
}

/* EOF */
