MODULE V24;
IMPORT Kernel32, KernelLog, Heaps, Kernel, Commands, Serials, Strings;
CONST
MaxPortNo = 32;
TYPE
Port* = OBJECT (Serials.Port)
VAR
handle: Kernel32.HANDLE;
portname: ARRAY 6 OF CHAR;
timer : Kernel.Timer;
PROCEDURE & Init*( port: LONGINT );
VAR fn: Heaps.FinalizerNode;
BEGIN
NEW(timer);
COPY( "COM ", portname );
IF port < 10 THEN
portname[3] := CHR( ORD( "0" ) + port );
portname[4]:= 0X;
ELSE
portname[3] := CHR( ORD( "0" ) + (port DIV 10) );
portname[4] := CHR( ORD( "0" ) + (port MOD 10) );
portname[5] := 0X;
END;
handle := Kernel32.InvalidHandleValue;
NEW( fn ); fn.finalizer := SELF.FinalizePort; Heaps.AddFinalizer( SELF, fn );
END Init;
PROCEDURE Open*( bps, data, parity, stop: LONGINT; VAR res: LONGINT );
BEGIN {EXCLUSIVE}
IF handle = Kernel32.InvalidHandleValue THEN
SetPortState( bps, data, parity, stop, res );
IF res = Serials.Ok THEN
KernelLog.String( portname ); KernelLog.String( " opened" ); KernelLog.Ln
END;
ELSE
res := Serials.PortInUse;
END;
END Open;
PROCEDURE Send*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
VAR written: LONGINT; ret: Kernel32.BOOL;
BEGIN
ASSERT ( LEN( buf ) >= ofs + len );
IF (handle # Kernel32.InvalidHandleValue) THEN
ret := Kernel32.WriteFile( handle, buf[ofs], len, written, NIL );
IF (ret # Kernel32.False) & (written = len) THEN
charactersSent := charactersSent + written;
res := Serials.Ok;
ELSE
res := Serials.TransportError;
END;
ELSE
res := Serials.Closed;
END
END Send;
PROCEDURE SendChar*( ch: CHAR; VAR res: LONGINT );
VAR ret: Kernel32.BOOL; written: LONGINT;
BEGIN
IF handle # Kernel32.InvalidHandleValue THEN
ret := Kernel32.WriteFile( handle, ch, 1, written, NIL );
IF (ret # Kernel32.False) & (written=1) THEN
INC(charactersSent);
res := Serials.Ok;
ELSE
res := Serials.TransportError;
END;
ELSE
res := Serials.Closed;
END
END SendChar;
PROCEDURE Receive*( VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT );
VAR i, l, read, ret: LONGINT;
BEGIN
ASSERT ( LEN( buf ) >= ofs + size );
ASSERT ( LEN( buf ) >= ofs + min );
res := Serials.Ok; len := 0;
i := ofs; l := Available();
WHILE (res = Serials.Ok) & (min > 0) OR ((l > 0) & (size > 0)) DO
IF l > size THEN l := size END;
IF (handle # Kernel32.InvalidHandleValue) THEN
IF (l > 0) THEN
ret := Kernel32.ReadFile( handle, buf[i], l, read, NIL );
IF (ret # Kernel32.False) & (read = l) THEN
charactersReceived := charactersReceived + read;
DEC( min, l ); DEC( size, l ); INC( len, l ); INC( i, l );
ELSE
res := Serials.TransportError;
END;
END;
ELSE
res := Serials.Closed;
END;
l := Available();
IF (res = Serials.Ok) & ( (min > 0) OR ((l > 0) & (size > 0)) ) THEN
Wait;
END;
END;
IF min <= 0 THEN res := Serials.Ok END;
END Receive;
PROCEDURE ReceiveChar*( VAR ch: CHAR; VAR res: LONGINT );
VAR l, ret, read: LONGINT;
BEGIN
IF handle # Kernel32.InvalidHandleValue THEN
REPEAT
l := Available();
IF l = 0 THEN Wait; END;
UNTIL (l > 0) OR (handle = Kernel32.InvalidHandleValue);
ret := Kernel32.ReadFile( handle, ch, 1, read, NIL );
IF (ret # Kernel32.False) & (read = 1) THEN
INC(charactersReceived);
res := Serials.Ok
ELSE
res := Serials.TransportError;
END
ELSE
res := Serials.Closed;
END
END ReceiveChar;
PROCEDURE Available*( ): LONGINT;
VAR errors: SET; stat: Kernel32.ComStat; res: Kernel32.BOOL;
BEGIN
IF handle # Kernel32.InvalidHandleValue THEN
res := Kernel32.ClearCommError( handle, errors, stat );
IF res # Kernel32.False THEN RETURN stat.cbInQue END
END;
RETURN 0
END Available;
PROCEDURE SetPortState( bps, data, parity, stop: LONGINT; VAR res: LONGINT );
VAR
hFile: Kernel32.HANDLE; dcb: Kernel32.DCB;
ret: Kernel32.BOOL; err: LONGINT;
windowsComName: ARRAY 16 OF CHAR;
BEGIN
res := Serials.Ok;
windowsComName := "\\.\";
Strings.Append(windowsComName, portname);
hFile := Kernel32.CreateFile( windowsComName,
{Kernel32.GenericRead, Kernel32.GenericWrite}, {},
NIL , Kernel32.OpenExisting, {}, Kernel32.NULL );
IF hFile # Kernel32.InvalidHandleValue THEN
ret := Kernel32.GetCommState( hFile, dcb );
IF ret # Kernel32.False THEN
dcb.BaudRate := bps;
IF (data >= 4) & (data <= 8) THEN dcb.ByteSize := CHR( data )
ELSE res := Serials.WrongData
END;
CASE stop OF
| Serials.Stop1:
dcb.StopBits := Kernel32.OneStopBit
| Serials.Stop1dot5:
dcb.StopBits := Kernel32.One5StopBits
| Serials.Stop2:
dcb.StopBits := Kernel32.TwoStopBits
ELSE
res := Serials.WrongStop
END;
CASE parity OF
| Serials.ParNo:
dcb.Parity := Kernel32.NoParity
| Serials.ParOdd:
dcb.Parity := Kernel32.OddParity
| Serials.ParEven:
dcb.Parity := Kernel32.EvenParity
| Serials.ParMark:
dcb.Parity := Kernel32.MarkParity
| Serials.ParSpace:
dcb.Parity := Kernel32.SpaceParity
ELSE
res := Serials.WrongParity
END;
IF res = Serials.Ok THEN
ret := Kernel32.SetCommState( hFile, dcb );
IF ret # Kernel32.False THEN
ret := Kernel32.PurgeComm( hFile, {Kernel32.PurgeTXClear, Kernel32.PurgeRXClear} );
ret := Kernel32.SetupComm( hFile, 800H, 800H );
handle := hFile;
RETURN
END
END
END;
ret := Kernel32.CloseHandle( hFile )
END;
IF res = Serials.Ok THEN
err := Kernel32.GetLastError();
CASE err OF
Kernel32.ErrorFileNotFound:
res := Serials.NoSuchPort
| Kernel32.ErrorAccessDenied:
res := Serials.PortInUse
| Kernel32.ErrorInvalidParameter:
res := Serials.WrongBPS
ELSE res := Serials.TransportError
END
END
END SetPortState;
PROCEDURE FinalizePort( ptr: ANY );
BEGIN
Close();
END FinalizePort;
PROCEDURE GetPortState*( VAR openstat: BOOLEAN; VAR bps, data, parity, stop: LONGINT );
VAR dcb: Kernel32.DCB; ret: Kernel32.BOOL;
BEGIN {EXCLUSIVE}
openstat := FALSE;
IF handle # Kernel32.InvalidHandleValue THEN
ret := Kernel32.GetCommState(handle, dcb );
IF ret # Kernel32.False THEN
openstat := TRUE;
bps := dcb.BaudRate;
data := ORD(dcb.ByteSize);
CASE dcb.StopBits OF
|Kernel32.OneStopBit: stop := Serials.Stop1;
|Kernel32.One5StopBits: stop := Serials.Stop1dot5;
|Kernel32.TwoStopBits: stop := Serials.Stop2;
ELSE
KernelLog.String("Win32.V24.GetPortState: Wrong stops bits"); KernelLog.Ln;
END;
CASE dcb.Parity OF
|Kernel32.NoParity: parity := Serials.ParNo;
|Kernel32.OddParity: parity := Serials.ParOdd;
|Kernel32.EvenParity: parity := Serials.ParEven;
|Kernel32.MarkParity: parity := Serials.ParMark;
|Kernel32.SpaceParity: parity := Serials.ParSpace;
ELSE
KernelLog.String("Win32.V24.GetPortState: Wrong parity mode"); KernelLog.Ln;
END;
END;
END;
END GetPortState;
PROCEDURE ClearMC*( s: SET );
BEGIN {EXCLUSIVE}
IF (handle # Kernel32.InvalidHandleValue) THEN
IF Serials.Break IN s THEN Kernel32.ClearCommBreak( handle ) END;
IF Serials.DTR IN s THEN Kernel32.EscapeCommFunction( handle, Kernel32.CLRDTR ) END;
IF Serials.RTS IN s THEN Kernel32.EscapeCommFunction( handle, Kernel32.CLRRTS ) END
END
END ClearMC;
PROCEDURE SetMC*( s: SET );
VAR res: LONGINT;
BEGIN {EXCLUSIVE}
IF handle # Kernel32.InvalidHandleValue THEN
IF Serials.Break IN s THEN res := Kernel32.SetCommBreak( handle ) END;
IF Serials.DTR IN s THEN
res := Kernel32.EscapeCommFunction( handle, Kernel32.SETDTR )
END;
IF Serials.RTS IN s THEN
res := Kernel32.EscapeCommFunction( handle, Kernel32.SETRTS )
END
END
END SetMC;
PROCEDURE GetMC*( VAR s: SET );
VAR state: SET; res: LONGINT;
BEGIN {EXCLUSIVE}
s := {};
IF handle # Kernel32.InvalidHandleValue THEN
res := Kernel32.GetCommModemStatus( handle, state );
IF Kernel32.MSCTSOn IN state THEN INCL( s, Serials.CTS ) END;
IF Kernel32.MSDSROn IN state THEN INCL( s, Serials.DSR ) END;
IF Kernel32.MSRingOn IN state THEN INCL( s, Serials.RI ) END;
IF Kernel32.MSRLSDOn IN state THEN INCL( s, Serials.DCD ) END
END
END GetMC;
PROCEDURE Wait;
BEGIN {EXCLUSIVE}
timer.Sleep(1);
END Wait;
PROCEDURE Close*;
BEGIN {EXCLUSIVE}
IF handle # Kernel32.InvalidHandleValue THEN
Kernel32.CloseHandle( handle ); handle := Kernel32.InvalidHandleValue
END
END Close;
END Port;
PROCEDURE Scan*(context : Commands.Context);
VAR i, ret: LONGINT; name,winname: ARRAY 256 OF CHAR;
strNumber: ARRAY 4 OF CHAR; found: BOOLEAN;
BEGIN
context.out.String( "Serial port detection and inspection (WinAos):" ); context.out.Ln;
found := FALSE;
FOR i := 1 TO MaxPortNo DO
COPY( "COM", name );
Strings.IntToStr(i, strNumber);
Strings.Append(name, strNumber);
ret := Kernel32.QueryDosDevice( name, winname, LEN( name ) );
IF ret # Kernel32.False THEN
found := TRUE;
context.out.String( name ); context.out.String( ":" );
context.out.String( winname ); context.out.String( "." );
context.out.Ln
END;
END;
IF ~found THEN context.out.String("no ports found"); context.out.Ln END;
END Scan;
PROCEDURE Install*;
END Install;
PROCEDURE Init*;
VAR
i, ret: LONGINT;
name : ARRAY 8 OF CHAR;
winname: ARRAY 256 OF CHAR;
port: Port;
strNumber: ARRAY 4 OF CHAR;
serialsPort: Serials.Port;
BEGIN
FOR i := 1 TO MaxPortNo DO
COPY( "COM", name );
Strings.IntToStr(i, strNumber);
Strings.Append(name, strNumber);
ret := Kernel32.QueryDosDevice(name, winname, LEN( winname ) );
IF ret # 0 THEN
serialsPort := Serials.GetPort(i);
IF (serialsPort = NIL) OR (serialsPort.description # winname) THEN
IF serialsPort # NIL THEN Serials.UnRegisterPort(serialsPort) END;
NEW(port, i);
Serials.RegisterOnboardPort( i , port, name, winname );
END;
END;
END;
END Init;
BEGIN
Init();
END V24.
V24.Install ~
V24.Scan ~
SystemTools.Free V24 ~
Serials.Show ~
SystemTools.Free Serials ~