 //////////////////////////////////////////////////////////////////////////////
 // Example of console application to connect to CRW-DAQ pipe.
 //////////////////////////////////////////////////////////////////////////////
program user_task;
{$APPTYPE CONSOLE} // ! Declare application type as CONSOLE.
{$I _sysdef}       // ! By CRW conventions, include _SYSDEF,
uses               // ! ShareMem must to be FIRST USES UNIT,
 ShareMem,         // ! borlndmm.dll should present in path.
 SysUtils,Windows,Math,Classes,
 _alloc,_str,_mime,_rtc,_fio,_fifo,_ascio,_az,_polling,_task,_pio;
 //
 // General variables and constants
 //
const
 Terminated : Boolean = false; // Program should be terminated
 //
 // Request: @help
 // Reply:   help info
 // Comment: Show help.
 //
 procedure DoHelp(const cmnd,args:LongString);
 begin
  StdOut.Put:=Format('%s',[cmnd]);
  StdOut.Put:='>> Command list:';
  StdOut.Put:='>> @help                 This help.';
  StdOut.Put:='>> @exit=n               Exit program with code n.';
  StdOut.Put:='>> @errors               Return error counter.';
  StdOut.Put:='>> @memory               Return memory status.';
  StdOut.Put:='>> @processpriority=n    Set process priority:Idle/Low/Normal/High/RealTime.';
  StdOut.Put:='>> @threadpriority=n     Set thread priority:tpIdle/tpLow/tpNormal/tpHigh/tpTimeCritical.';
  StdOut.Put:='>> @runcount=data        Demo data processing.';
 end;
 //
 // Request: @exit
 // Request: @exit=n
 // Reply:   @exit=n
 // Comment: Terminate program with exit code n.
 //
 procedure DoExit(const cmnd,args:LongString);
 begin
  Sound(2000,100);
  Terminated:=true;
  System.ExitCode:=StrToIntDef(args,0);
  StdOut.Put:=Format('%s=%d',[cmnd,System.ExitCode]);
 end;
 //
 // Request: @errors
 // Request: @errors=n
 // Reply:   @errors=n
 // Comment: Return value n of error counter.
 //
 procedure DoErrors(const cmnd,args:LongString);
 var
  n : LongInt;
 begin
  if Str2Long(args,n)
  then n:=LockedExchange(StdIoErrorCount,n)
  else n:=StdIoErrorCount;
  StdOut.Put:=Format('%s=%d',[cmnd,n]);
 end;
 //
 // Request: @memory
 // Request: @memory=n
 // Comment: Return AllocMemSize.
 //
 procedure DoMemory(const cmnd,args:LongString);
 begin
  StdOut.Put:=Format('%s=%d',[cmnd,GetAllocMemSize]);
 end;
 //
 // Request: @ProcessPriority
 // Request: @ProcessPriority=n
 // Reply:   @ProcessPriority=n
 // Comment: Set process priority class.
 //
 procedure DoProcessPriority(const cmnd,args:LongString);
 var p:DWORD;
 begin
  if not IsEmptyStr(args) then begin
   p:=GetPriorityClassByName(args);
   if p>0 then SetPriorityClass(GetCurrentProcess,p);
  end;
  StdOut.Put:=Format('%s=%s',[cmnd,GetPriorityClassName(GetPriorityClass(GetCurrentProcess))]);
 end;
 //
 // Request: @ThreadPriority
 // Request: @ThreadPriority=n
 // Reply:   @ThreadPriority=n
 // Comment: Set thread priority class.
 //
 procedure DoThreadPriority(const cmnd,args:LongString);
 var p:TThreadPriority;
 begin
  if not IsEmptyStr(args) then begin
   p:=GetPriorityByName(args);
   StdIn.Priority:=p;
   StdOut.Priority:=p;
   case p of
    tpIdle         : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_IDLE);
    tpLowest       : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_LOWEST);
    tpLower        : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_BELOW_NORMAL);
    tpNormal       : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_NORMAL);
    tpHigher       : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_ABOVE_NORMAL);
    tpHighest      : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_HIGHEST);
    tpTimeCritical : SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);
   end;
  end;
  StdOut.Put:=Format('%s=%s',[cmnd,GetPriorityName(StdIn.Priority)]);
 end;
 //
 // Request: @RunCount=data
 // Reply:   @RunCount=data
 // Comment: Demo data processing.
 //
 procedure DoRunCount(const cmnd,args:LongString);
 const
  RunCount   : Double     = 1;
  ErrorCount : Integer    = 0;
 var
  s   : ShortString;
  r,t : Double;
 begin
  s:=mime_decode(args);
  r:=dump2r(Copy(s,1,8));
  t:=dump2r(Copy(s,9,8));
  if r<>RunCount+1 then Inc(ErrorCount);
  RunCount:=r;
  StdOut.Put:=Format('%s=%g'#9'Time=%11.6f'#9'ErrorCount=%d',[cmnd,RunCount,t,ErrorCount]);
 end;
 //
 // This callback handles unrecognized commands.
 //
 procedure DoSpecificCommands(const args:LongString);
 begin
  if Length(args)>0 then
  StdOut.Put:=Format('Could not recognize "%s"',[args]);
 end;
 //
 // Application specific initialization.
 //
 procedure SpecificInitialization;
  procedure ShowEnv(const aName:LongString);
  begin
   StdOut.Put:=Format('%s=%s',[aName,GetEnv(aName)]);
  end;
 begin
  if not iopm_open then RAISE Exception.Create('Could not load IOPM driver!');
  Sound(2000,100);
  ShowEnv('CRW_DAQ_SYS_HOME_DIR');      // Show Crw32.exe home directory
  ShowEnv('CRW_DAQ_SYS_EXE_FILE');      // Show full crw32.exe file path
  ShowEnv('CRW_DAQ_SYS_INI_FILE');      // Show full crw32.ini file path
  ShowEnv('CRW_DAQ_SYS_EXE_PID');       // Show Crw32.exe process ID
  ShowEnv('CRW_DAQ_SYS_EXE_TID');       // Show Crw32.exe main thread ID
  ShowEnv('CRW_DAQ_SYS_MESSAGE');       // Show Crw32.exe unique application message
  ShowEnv('CRW_DAQ_CONFIG_FILE');       // Show DAQ configuration file
  ShowEnv('CRW_DAQ_CONFIG_DATA_PATH');  // Show DAQ data directory path
  ShowEnv('CRW_DAQ_CONFIG_LOAD_TIME');  // Show DAQ config load time
  ShowEnv('CRW_DAQ_CONFIG_START_TIME'); // Show DAQ config start time
  // 
  // Register user commands coming from StdIn.
  //
  SystemEchoProcedure:=StdOutEcho;
  StdIn.SpecHandler:=DoSpecificCommands;
  StdIn.AddCommand('@Help',            DoHelp);
  StdIn.AddCommand('@Exit',            DoExit);
  StdIn.AddCommand('@Errors',          DoErrors);
  StdIn.AddCommand('@Memory',          DoMemory);
  StdIn.AddCommand('@ProcessPriority', DoProcessPriority);
  StdIn.AddCommand('@ThreadPriority',  DoThreadPriority);
  StdIn.AddCommand('@RunCount',        DoRunCount);
 end;
 //
 // Application specific finalization.
 //
 procedure SpecificFinalization;
 begin
 end;
 //
 // Application specific polling.
 //
 procedure SpecificPolling;
 begin
  if BecameZombie(FILE_TYPE_PIPE,1000) then StdIn.Put:='@Exit';
 end;
 //
 // Main program
 //
begin
 try
  try
   SpecificInitialization;
   while not Terminated do begin
    while StdIn.Count>0 do StdIn.Process(StdIn.Get);
    SpecificPolling;
    Sleep(1);
   end;
  finally
   SpecificFinalization;
  end;
 except
  on E:Exception do StdOut.Put:=E.Message;
 end;
 Sleep(100);
 if BecameZombie(FILE_TYPE_PIPE) then ExitProcess(1);
end.
