home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR16 / SPOOLAQ.ZIP / SPOOLER.PAS < prev   
Pascal/Delphi Source File  |  1993-06-12  |  26KB  |  599 lines

  1. (* █▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█ *)
  2. (* █                                                                █ *)
  3. (* █     S P O O L E R - Object                                     █ *)
  4. (* █                                                                █ *)
  5. (* ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ *)
  6.  
  7. unit Spooler;
  8. { F+}
  9. {$O+}                                  (* can be put in an overlay    *)
  10.  
  11. interface
  12.  
  13. uses
  14.   DOS, Printer,
  15.   Objects, Views, Drivers, App;
  16.  
  17.  
  18. (* ╔════════════════════════════════════════════════════════════════╗ *)
  19. (* ║                                                                ║ *)
  20. (* ║     definition of exported constants                           ║ *)
  21. (* ║                                                                ║ *)
  22. (* ╚════════════════════════════════════════════════════════════════╝ *)
  23. const
  24.   Spool_LPT1 = 1;
  25.   Spool_LPT2 = 2;
  26.   Spool_COM1 = 1;
  27.   Spool_COM2 = 2;
  28.   Spool_COM3 = 3;
  29.   Spool_COM4 = 4;
  30.  
  31.   Spool_300  = 0;
  32.   Spool_600  = 1;
  33.   Spool_1200 = 2;
  34.   Spool_2400 = 3;
  35.   Spool_4800 = 4;
  36.   Spool_9600 = 5;
  37.  
  38.   Spool_Odd  = 0;
  39.   Spool_Even = 1;
  40.  
  41.   Spool_1Stop = 0;
  42.   Spool_2Stop = 1;
  43.  
  44.   Spool_8Bit  = 0;
  45.   Spool_7Bit  = 1;
  46.  
  47.   Spool_FlowXONXOFF = 0;
  48.   Spool_FlowDTR     = 1;
  49.  
  50.  
  51. (* ╔════════════════════════════════════════════════════════════════╗ *)
  52. (* ║                                                                ║ *)
  53. (* ║     definition of object                                       ║ *)
  54. (* ║                                                                ║ *)
  55. (* ╚════════════════════════════════════════════════════════════════╝ *)
  56. type
  57.    PSpooler = ^TSpooler;
  58.    TSpooler = object (TView )
  59.          constructor Init( Rect : TRect; NameOfFile : String );
  60.          destructor  Done;                           virtual;
  61.          procedure   SetParallel( PortNo : word );   virtual;
  62.          procedure   SetSerial(  PortNo,
  63.                                  BaudRate,
  64.                                  DataBits,
  65.                                  StopBits,
  66.                                  Parity,
  67.                                  FlowControl  : word ); virtual;
  68.          procedure   StartSpooling;                  virtual;
  69.          procedure   StopSpooling;                   virtual;
  70.          procedure   CancelSpooling;                 virtual;
  71.          procedure   SpoolOneChar;                   virtual;
  72.          procedure   Draw;                           virtual;
  73.          procedure   Update;                         virtual;
  74.          procedure   UseDOS( Flag : boolean );       virtual;
  75.       private
  76.          Active    : boolean;          (* spool-process is active     *)
  77.          FileName  : PString;          (* name of file to output      *)
  78.          SizeOfFile  : longint;        (* end-marker                  *)
  79.          Remainder   : longint;        (* no. of bytes to handle      *)
  80.          NextChar    : byte;           (* the next char. for output   *)
  81.          NextCharPtr : longint;        (* Ptr. into file              *)
  82.          IsParallel  : boolean;        (* to parallel/serial port ?   *)
  83.          PortAddress : word;           (* address of the port         *)
  84.          SpoolFile   : file;           (* file for reading            *)
  85.          lastTimerTicks : longint;     (* needed for update of no.    *)
  86.          FlowOfControl  : word;        (* which type of control ?     *)
  87.          XOFF_Flag      : boolean;     (* XOFF sent ?                 *)
  88.          DirectHWAccess : boolean;     (* use OUT-instr. or DOS-calls *)
  89.  
  90.          procedure   DeQueue;
  91.          function    StatusLPT : boolean;
  92.          function    COMGetc( COMx : word) : word;
  93.          function    COMPutc(COMx:word; CommandChar:byte) : word;
  94.          function    COMPutC_DTR(COMx:word; CommandChar:byte) : word;
  95.    end;
  96.  
  97.  
  98. implementation
  99. (* ╔════════════════════════════════════════════════════════════════╗ *)
  100. (* ║                                                                ║ *)
  101. (* ║     definition of private constants                            ║ *)
  102. (* ║                                                                ║ *)
  103. (* ╚════════════════════════════════════════════════════════════════╝ *)
  104. const 
  105.     XON  = #$11;
  106.     XOFF = #$13;
  107.  
  108. (* ╔════════════════════════════════════════════════════════════════╗ *)
  109. (* ║                                                                ║ *)
  110. (* ║     the Spooler-object                                         ║ *)
  111. (* ║                                                                ║ *)
  112. (* ╚════════════════════════════════════════════════════════════════╝ *)
  113. (* ┌────────────────────────────────────────────────────────────────┐ *)
  114. (* │                                                                │ *)
  115. (* │     construct the Spool-object                                 │ *)
  116. (* │                                                                │ *)
  117. (* └────────────────────────────────────────────────────────────────┘ *)
  118. constructor TSpooler.Init( Rect : TRect; NameOfFile : String );
  119. begin
  120.     TView.Init( Rect );
  121.     FileName := NewStr( NameOfFile );
  122.     Active   := false;
  123.     NextCharPtr := 0;
  124.     NextChar    := 0;
  125.     SizeOfFile  := 0;
  126.     lastTimerTicks := 0;
  127.     IsParallel  := true;               (* default: parallel           *)
  128.     PortAddress := MemW[$40:8];        (*          = LPT1             *)
  129.     DirectHWAccess := true;
  130. end;
  131.  
  132. (* ┌────────────────────────────────────────────────────────────────┐ *)
  133. (* │                                                                │ *)
  134. (* │     remove Spool-object                                        │ *)
  135. (* │                                                                │ *)
  136. (* └────────────────────────────────────────────────────────────────┘ *)
  137. destructor TSpooler.Done;
  138. var
  139.     f : file;
  140. begin
  141.     if Active then
  142.         CancelSpooling;
  143.     DisposeStr( FileName );
  144.     TView.Done;
  145. end;
  146.  
  147. (* ┌────────────────────────────────────────────────────────────────┐ *)
  148. (* │                                                                │ *)
  149. (* │     init of parallel interface                                 │ *)
  150. (* │                                                                │ *)
  151. (* └────────────────────────────────────────────────────────────────┘ *)
  152. procedure TSpooler.SetParallel( PortNo : word );
  153. begin
  154.     IsParallel  := true;
  155.     PortAddress := MemW[$40:(3+PortNo) shl 1];
  156. end;
  157.  
  158. (* ┌────────────────────────────────────────────────────────────────┐ *)
  159. (* │                                                                │ *)
  160. (* │     init of serial interface                                   │ *)
  161. (* │                                                                │ *)
  162. (* └────────────────────────────────────────────────────────────────┘ *)
  163. procedure TSpooler.SetSerial( PortNo,
  164.                               BaudRate,
  165.                               DataBits,
  166.                               StopBits,
  167.                               Parity,
  168.                               FlowControl  : word );
  169. var
  170.     CommRegs : Registers;
  171. begin
  172.     IsParallel    := false;
  173.     PortAddress   := MemW[$40:(PortNo-Spool_COM1) shl 1];
  174.     FlowOfControl := FlowControl;
  175.     XOFF_Flag     := false;            (* status = XON                *)
  176.     with CommRegs do
  177.     begin
  178. (*  interpretation: look at BIOS, INT 14H, function 0 = init          *)
  179.         AH := 0;
  180.         case BaudRate of
  181.         { Spool_110  :  AL := $00; }
  182.         { Spool_150  :  AL := $20; }
  183.           Spool_300  :  AL := $40;
  184.           Spool_600  :  AL := $60;
  185.           Spool_1200 :  AL := $80;
  186.           Spool_2400 :  AL := $A0;
  187.           Spool_4800 :  AL := $C0;
  188.           Spool_9600 :  AL := $E0;
  189.         end;
  190.         case Parity of
  191.           Spool_Odd  :  AL := AL or $08;
  192.           Spool_Even :  AL := AL or $18;
  193.         end;
  194.         case StopBits of
  195.           Spool_1Stop :  AL := AL or $00;
  196.           Spool_2Stop :  AL := AL or $04;
  197.         end;
  198.         case DataBits of
  199.           Spool_8Bit  :  AL := AL or $03;
  200.           Spool_7Bit  :  AL := AL or $02;
  201.         end;
  202.         DX := PortNo-Spool_COM1;  (* no. of port: 0=COM1, 1=COM2 etc. *)
  203.     end;
  204.     Intr($14,CommRegs);
  205. end; (* ---------------------------------------------- SetSerial *)
  206.  
  207. (* ┌────────────────────────────────────────────────────────────────┐ *)
  208. (* │                                                                │ *)
  209. (* │     start the spooling-process                                 │ *)
  210. (* │                                                                │ *)
  211. (* └────────────────────────────────────────────────────────────────┘ *)
  212. procedure TSpooler.StartSpooling;
  213. begin
  214.     if not Active then
  215.     begin
  216.         assign( SpoolFile, FileName^);
  217.         reset( SpoolFile, 1 );
  218.         SizeOfFile := FileSize( SpoolFile );
  219.         if SizeOfFile>0 then
  220.         begin
  221.             seek( SpoolFile, NextCharPtr );
  222.             blockread( SpoolFile, NextChar, 1 );
  223.             Active := true;
  224.         end
  225.         else
  226.             close( SpoolFile );
  227.     end;
  228. end;
  229.  
  230. (* ┌────────────────────────────────────────────────────────────────┐ *)
  231. (* │                                                                │ *)
  232. (* │     stop (or pause) the spooling-process                       │ *)
  233. (* │                                                                │ *)
  234. (* └────────────────────────────────────────────────────────────────┘ *)
  235. procedure TSpooler.StopSpooling;
  236. begin
  237.     if Active then
  238.     begin
  239.         close( SpoolFile );
  240.         Active := false;
  241.     end;
  242. end;
  243.  
  244. (* ┌────────────────────────────────────────────────────────────────┐ *)
  245. (* │                                                                │ *)
  246. (* │     final work: stop spooling-process                          │ *)
  247. (* │                                                                │ *)
  248. (* └────────────────────────────────────────────────────────────────┘ *)
  249. procedure TSpooler.CancelSpooling;
  250. begin
  251.     if Active then
  252.         StopSpooling;
  253.     assign( SpoolFile, FileName^);
  254.     reset( SpoolFile, 1);
  255. (*   do not truncate in development-process, remove comments later !  *)
  256. {   truncate( SpoolFile ); }           (* !!!!! look here ! !!!!!!!!! *)
  257. (*  ^^^^^^^^^^^^^^^^^^^^^^ *)
  258.     close( SpoolFile );
  259. end;
  260.  
  261. (* ┌────────────────────────────────────────────────────────────────┐ *)
  262. (* │                                                                │ *)
  263. (* │     output one character                                       │ *)
  264. (* │                                                                │ *)
  265. (* └────────────────────────────────────────────────────────────────┘ *)
  266. procedure TSpooler.SpoolOneChar;
  267. var
  268.     CommResult : word;
  269. begin
  270.     if Active then
  271.     begin
  272.         if DirectHWAccess then
  273.         begin
  274. (* ------------------------------------------------------------------ *)
  275. (*                                                                    *)
  276. (*       use the parallel interface                                   *)
  277. (*                                                                    *)
  278. (* ------------------------------------------------------------------ *)
  279.             if IsParallel then
  280.             begin
  281.                 if StatusLPT then 
  282.                 begin
  283.                     PORT[PortAddress]:=NextChar;
  284.                     DeQueue;
  285.                     PORT[PortAddress+2]:=$0d;    (* set strobe-bit    *)
  286.                     PORT[PortAddress+2]:=$0c;    (* reset strobe-bit  *)
  287.                 end;
  288.             end
  289.             else
  290. (* ------------------------------------------------------------------ *)
  291. (*                                                                    *)
  292. (*       use serial interface                                         *)
  293. (*                                                                    *)
  294. (* ------------------------------------------------------------------ *)
  295.             begin
  296.                 if FlowOfControl=Spool_FlowXONXOFF then
  297.                 begin
  298. (*                                                                    *)
  299. (*                  flow of control is XON/XOFF                       *)
  300. (*                                                                    *)
  301.                     if not XOFF_Flag then
  302.                         if COMPutC( PortAddress, NextChar )=word(NextChar) then
  303.                             DeQueue;
  304.                     CommResult := COMGetC( PortAddress );
  305.                     if CommResult <= $FF then
  306.                         XOFF_Flag := (CommResult=word(XOFF));
  307.                 end
  308.                 else
  309.                 begin
  310. (*                                                                    *)
  311. (*                  flow of control is DTR                            *)
  312. (*                                                                    *)
  313.                     if COMPutC_DTR( PortAddress, NextChar)=word(NextChar) then
  314.                         Dequeue;
  315.                 end;
  316.             end;
  317.         end
  318.         else
  319.         begin
  320. (* ------------------------------------------------------------------ *)
  321. (*                                                                    *)
  322. (*       output a byte using DOS                                      *)
  323. (*                                                                    *)
  324. (* ------------------------------------------------------------------ *)
  325.             write(Lst, char(NextChar));
  326.             DeQueue;
  327.         end;
  328.     end;
  329.     Remainder := SizeOfFile - NextCharPtr;
  330.     Update;
  331. end;
  332.  
  333. (* ┌────────────────────────────────────────────────────────────────┐ *)
  334. (* │                                                                │ *)
  335. (* │     show the number of remaining bytes in the given rectangle  │ *)
  336. (* │                                                                │ *)
  337. (* └────────────────────────────────────────────────────────────────┘ *)
  338. procedure TSpooler.Draw;
  339. var
  340.     Buf    : TDrawBuffer;
  341.     Value  : string;
  342.     Params : array [0..0] of longint;
  343. begin
  344.     if Remainder>0 then
  345.     begin
  346.         Params[0] := Remainder;
  347.         FormatStr( Value, '%8d', Params);
  348.         MoveStr( Buf, Value, GetColor(2));
  349.     end
  350.     else
  351.         MoveChar(Buf, ' ', GetColor(2), 8);
  352.     WriteLine(0, 0, size.x, 1, Buf);
  353. end;
  354.  
  355. (* ┌────────────────────────────────────────────────────────────────┐ *)
  356. (* │                                                                │ *)
  357. (* │     must we update the contents of the View ?                  │ *)
  358. (* │                                                                │ *)
  359. (* └────────────────────────────────────────────────────────────────┘ *)
  360. procedure TSpooler.Update;
  361. var   BIOSTimerTicks : longint absolute $40:$6c;
  362. begin
  363.     if BIOSTimerTicks>=lastTimerTicks then
  364.     begin
  365.         TSpooler.DrawView;
  366. (*      it's enough to show it 6 times a second, so add 2             *)
  367.         lastTimerTicks := BIOSTimerTicks+2;
  368.     end;
  369. end;
  370.  
  371.  
  372. (* ┌────────────────────────────────────────────────────────────────┐ *)
  373. (* │                                                                │ *)
  374. (* │     OK, we will not directly access the hardware               │ *)
  375. (* │                                                                │ *)
  376. (* └────────────────────────────────────────────────────────────────┘ *)
  377. procedure TSpooler.UseDOS( Flag : boolean );
  378. begin
  379.     DirectHWAccess := not Flag;
  380. end; (* ---------------------------------------------- UseDOS *)
  381.  
  382. (* ╔════════════════════════════════════════════════════════════════╗ *)
  383. (* ║                                                                ║ *)
  384. (* ║     the private methods                                        ║ *)
  385. (* ║                                                                ║ *)
  386. (* ╚════════════════════════════════════════════════════════════════╝ *)
  387. (* ┌────────────────────────────────────────────────────────────────┐ *)
  388. (* │                                                                │ *)
  389. (* │     take the next character from queue-file                    │ *)
  390. (* │                                                                │ *)
  391. (* └────────────────────────────────────────────────────────────────┘ *)
  392. procedure TSpooler.DeQueue;
  393. begin
  394.     inc(NextCharPtr);
  395.     if NextCharPtr<SizeOfFile then
  396.         blockread( SpoolFile, NextChar, 1)
  397.     else
  398. (*      End of File-condition:                                        *)
  399.         CancelSpooling;
  400. end;
  401.  
  402. (* ┌────────────────────────────────────────────────────────────────┐ *)
  403. (* │                                                                │ *)
  404. (* │     status of parallel interface                               │ *)
  405. (* │                                                                │ *)
  406. (* └────────────────────────────────────────────────────────────────┘ *)
  407. function TSpooler.StatusLPT : boolean;
  408. var
  409.     Status : byte;
  410. begin
  411.     Status := PORT[PortAddress+1];
  412.     if (Status and $90)=$80 then       (* test bit #7 & #4            *)
  413.         StatusLPT := false             (* turned off or offline       *)
  414.     else if (Status and $20)=$20 then  (* test bit #5                 *)
  415.         StatusLPT := false             (* Out of paper                *)
  416.     else if (Status and $B8)=$98 then  (* test Bit #7, #5, #4 & #3    *)
  417.         StatusLPT := true 
  418.     else
  419.         StatusLPT := false;            (* offline                     *)
  420. end;
  421.  
  422. (* ┌────────────────────────────────────────────────────────────────┐ *)
  423. (* │                                                                │ *)
  424. (* │     fetch character from the serial interface                  │ *)
  425. (* │                                                                │ *)
  426. (* └────────────────────────────────────────────────────────────────┘ *)
  427. function TSpooler.COMGetc( COMx : word) : word;
  428. var
  429.     V24_ErrNo   : byte;                { error-no.                    }
  430. begin
  431.     asm
  432.            { read 1 byte from SIO
  433.            ; returns:        AL contains char. 
  434.            ;                 AH error            
  435.                              $0000 = no character read                }    
  436.            MOV         DX,COMx    { DX contains the port-no. of SIO   }
  437.            PUSH        DX
  438.            PUSH        CX
  439.            PUSH        BX
  440.            MOV         V24_ErrNo,0     { init: no error occured  }
  441.            ADD         DX,5            { DX (new) = DX(old)+5 } 
  442.  
  443. @READ00:   { printer will send char    
  444.              check: char. available    }
  445. @READ01:   IN          AL,DX           { DX = Line Status Register }
  446.            TEST        AL,00011110B    { error occured ?    }
  447.                        {     ^^^^^---->  data received        }
  448.                        {     IIII----->  overrun error        }
  449.                        {     III------>  parity error         }
  450.                        {     II------->  framing error        }
  451.                        {     I-------->  break received       }
  452.            JZ          @READ02
  453.  
  454.            MOV         V24_ErrNo,AL    { store error }
  455. @READ01A:  MOV         AL,0            { return: no char. }  
  456.            OR          V24_ErrNo, $80
  457.            JMP         @READERR
  458.  
  459. @READ02:   TEST        AL,1            { Char ready ? }
  460.            JZ          @READ01A        { No: return $0000 } 
  461.  
  462. @READ03:   MOV         AX,5            { fetch character }
  463.            SUB         DX,AX
  464.            IN          AL,DX           { DX = Receiver Buffer }
  465.            { AL: character received }
  466.  
  467. @READERR:  MOV         AH,V24_ErrNo
  468.            MOV         @Result,AX      { return char. + error-code }
  469.            POP         BX
  470.            POP         CX
  471.            POP         DX
  472.    end;
  473. end;
  474.  
  475. (* ┌────────────────────────────────────────────────────────────────┐ *)
  476. (* │                                                                │ *)
  477. (* │     send character to printer if possible                      │ *)
  478. (* │                                                                │ *)
  479. (* └────────────────────────────────────────────────────────────────┘ *)
  480. function  TSpooler.COMPutc(COMx:word; CommandChar:byte) : word;
  481. var
  482.     V24_ErrNo   : byte;                { error-no.                    }
  483. begin
  484.     asm
  485.            { write 1 char. in SIO                                     }
  486.            { returns:        AL  CommandChar / $00                    }
  487.            {                 AH  error-no.                            }
  488.            {                      $00 = OK                            }
  489.            {                      else: error                         }
  490.            MOV         DX,COMx         { DX contains port-no. of SIO  }
  491.            PUSH        DX
  492.            MOV         V24_ErrNo,0     { init: no error occured  }
  493.  
  494. @WRITE02:
  495.            ADD         DX,5            { DX = COMx + 5                }
  496.            {; SIO erlaubt Übergabe }
  497. @WRITE03:  IN          AL,DX           { DX = Line Status Register }
  498.            TEST        AL,00011110B    { error occured ? }
  499.                        {     ^^^^^---->  data received        }
  500.                        {     IIII----->  overrun error        }
  501.                        {     III------>  parity error         }
  502.                        {     II------->  framing error        }
  503.                        {     I-------->  break received       }
  504.            JZ          @WRITE04        { no --> go on         }
  505.            {  error occured: }
  506.            MOV         V24_ErrNo,AL { store error }
  507. @WRITE01A:
  508.            MOV         AL,0            { return: no char }   
  509.            OR          V24_ErrNo, $80
  510.            JMP         @WRITE06
  511.  
  512.  
  513. @WRITE04:  TEST        AL,20H          { Transmitter Holding Reg. empty ? }
  514.            JZ          @WRITE01A       { cannot write: return } 
  515.  
  516. @WRITE05:  { can write: }
  517.            MOV         AX,5
  518.            SUB         DX,AX
  519.            MOV         AL,CommandChar  { AL contains char.         }
  520.            OUT         DX,AL           { DX = Transmitter Register }
  521.            { AL still contains char --> return }
  522.  
  523. @WRITE06:  {  return: finishing work }
  524.            MOV         AH,V24_ErrNo
  525.            MOV         @Result,AX
  526.            POP         DX
  527.     end;
  528. end;
  529.  
  530. (* ┌────────────────────────────────────────────────────────────────┐ *)
  531. (* │                                                                │ *)
  532. (* │     send char. to printer, check status of DTR                 │ *)
  533. (* │                                                                │ *)
  534. (* └────────────────────────────────────────────────────────────────┘ *)
  535. function  TSpooler.COMPutC_DTR(COMx:word; CommandChar:byte) : word;
  536. var
  537.     V24_ErrNo   : byte;                { error-no.                    }
  538. begin
  539.     asm
  540.            { write 1 char into SIO                                    }
  541.            { Rückgabe:       AL  CommandChar / $00                    }
  542.            {                 AH  error                                }
  543.            {                 $8000 = no char. transmitted             }    
  544.            MOV         DX,COMx         { DX contains port-no. of SIO  }
  545.            PUSH        DX
  546.            MOV         V24_ErrNo,0     { init: no error occured  }
  547.  
  548.            ADD         DX,6            { DX = COMx + 6                }
  549. @WRITE01:  IN          AL,DX           { DX = Modem Status Register   }
  550.            TEST        AL,00100000B    { DSR=True: allowed to write   }
  551.            JNZ         @WRITE02
  552.  
  553. @WRITE01A:
  554.            MOV         AL,0            { Rückgabe: kein Zeichen }   
  555.            OR          V24_ErrNo, $80
  556.            JMP         @WRITE06
  557.  
  558. @WRITE02:
  559.            DEC         DX              { DX (neu) = DX(alt)+5 }
  560.            {; transmit allowed }
  561. @WRITE03:  IN          AL,DX           { DX = Line Status Register }
  562.            TEST        AL,00011110B    { error occured ? }
  563.                        {     ^^^^^---->  data received        }
  564.                        {     IIII----->  overrun error        }
  565.                        {     III------>  parity error         }
  566.                        {     II------->  framing error        }
  567.                        {     I-------->  break received       }
  568.            JZ          @WRITE04        { no --> continue      }
  569.            {  eror occured: }
  570.            MOV         V24_ErrNo,AL { store error  }
  571.            JMP  @WRITE01A
  572.  
  573. @WRITE04:  TEST        AL,20H          { Transmitter Holding Reg. empty ? }
  574.            JZ          @WRITE01A       { cannot write --> return } 
  575.  
  576. @WRITE05:  { can write:  }
  577.            MOV         AX,5
  578.            SUB         DX,AX
  579.            MOV         AL,CommandChar  { AL contians char.         }
  580.            OUT         DX,AL           { DX = Transmitter Register }
  581.            { AL still contains char --> return }
  582.  
  583. @WRITE06:  {  return: finishing work }
  584.            MOV         AH,V24_ErrNo
  585.            MOV         @Result,AX
  586.            POP         DX
  587.     end;
  588. end;
  589.  
  590.  
  591. (* ╔════════════════════════════════════════════════════════════════╗ *)
  592. (* ║                                                                ║ *)
  593. (* ║     Init of this Unit                                          ║ *)
  594. (* ║                                                                ║ *)
  595. (* ╚════════════════════════════════════════════════════════════════╝ *)
  596. begin
  597.                                        (* nothing to do !             *)
  598. end.
  599.