(**************************************************************************) (* *) (* Copyright (c) 1988, 1989 *) (* by Stony Brook Software *) (* and *) (* Copyright (c) 1990 *) (* by Brian R. Anderson *) (* All rights reserved. *) (* *) (**************************************************************************) IMPLEMENTATION MODULE CommPort [7]; FROM SYSTEM IMPORT ADR, BYTE, WORD, ADDRESS; FROM Storage IMPORT ALLOCATE, DEALLOCATE; FROM DosCalls IMPORT DosOpen, AttributeSet, DosDevIOCtl, DosClose, DosRead, DosWrite; TYPE CP = POINTER TO CHAR; VAR pn : CARDINAL; Handle : ARRAY [0..3] OF CARDINAL; BufIn : ARRAY [0..3] OF CP; BufOut : ARRAY [0..3] OF CP; BufStart : ARRAY [0..3] OF CP; BufLimit : ARRAY [0..3] OF CP; BufSize : ARRAY [0..3] OF CARDINAL; Temp : ARRAY [1..1024] OF CHAR; (* size of OS/2's serial queue *) PROCEDURE CheckPort (portnum : CARDINAL) : BOOLEAN; (* Check for a valid port number and open the port if it not alredy open *) CONST PortName : ARRAY [0..3] OF ARRAY [0..4] OF CHAR = [['COM1', 0C], ['COM2', 0C], ['COM3', 0C], ['COM4', 0C]]; VAR Action : CARDINAL; BEGIN (* check the port number *) IF portnum > 3 THEN RETURN FALSE; END; (* attempt to open the port if it is not already open *) IF Handle[portnum] = 0 THEN IF DosOpen(ADR(PortName[portnum]), Handle[portnum], Action, 0, AttributeSet{}, 1, 12H, 0) # 0 THEN RETURN FALSE; END; END; RETURN TRUE; END CheckPort; PROCEDURE InitPort (portnum : CARDINAL; speed : BaudRate; data : DataBits; stop : StopBits; check : Parity) : CommStatus; (* Initialize a port *) CONST Rate : ARRAY BaudRate OF CARDINAL = [110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200]; TransParity : ARRAY Parity OF BYTE = [2, 1, 0]; TYPE LineChar = RECORD bDataBits : BYTE; bParity : BYTE; bStopBits : BYTE; END; VAR LC : LineChar; BEGIN (* Check the port number *) IF NOT CheckPort(portnum) THEN RETURN InvalidPort; END; (* Set the baud rate *) IF DosDevIOCtl(0, ADR(Rate[speed]), 41H, 1, Handle[portnum]) # 0 THEN RETURN InvalidParameter; END; (* set the characteristics *) LC.bDataBits := BYTE(data); IF stop = 1 THEN DEC (stop); (* 0x00 = 1 stop bits; 0x02 = 2 stop bits *) END; LC.bStopBits := BYTE(stop); LC.bParity := TransParity[check]; IF DosDevIOCtl(0, ADR(LC), 42H, 1, Handle[portnum]) # 0 THEN RETURN InvalidParameter; END; RETURN Success; END InitPort; PROCEDURE StartReceiving (portnum, bufsize : CARDINAL) : CommStatus; (* Start receiving characters on a port *) BEGIN IF NOT CheckPort(portnum) THEN RETURN InvalidPort; END; IF BufStart[portnum] # NIL THEN RETURN AlreadyReceiving; END; ALLOCATE (BufStart[portnum], bufsize); BufIn[portnum] := BufStart[portnum]; BufOut[portnum] := BufStart[portnum]; BufLimit[portnum] := BufStart[portnum]; INC (BufLimit[portnum]:ADDRESS, bufsize - 1); BufSize[portnum] := bufsize; RETURN Success; END StartReceiving; PROCEDURE StopReceiving (portnum : CARDINAL) : CommStatus; (* Stop receiving characters on a port *) BEGIN IF NOT CheckPort(portnum) THEN RETURN InvalidPort; END; IF BufStart[portnum] # NIL THEN DEALLOCATE (BufStart[portnum], BufSize[portnum]); BufLimit[portnum] := NIL; BufIn[portnum] := NIL; BufOut[portnum] := NIL; BufSize[portnum] := 0; END; DosClose(Handle[portnum]); Handle[portnum] := 0; RETURN Success; END StopReceiving; PROCEDURE GetChar (portnum : CARDINAL; VAR ch : CHAR) : CommStatus; (* Get a character from the comm port *) VAR status : CARDINAL; read : CARDINAL; que : RECORD ct : CARDINAL; sz : CARDINAL; END; i : CARDINAL; BEGIN IF BufStart[portnum] = NIL THEN RETURN NotReceiving; END; IF NOT CheckPort(portnum) THEN RETURN InvalidPort; END; status := DosDevIOCtl (ADR (que), 0, 68H, 1, Handle[portnum]); IF (status = 0) AND (que.ct # 0) THEN status := DosRead (Handle[portnum], ADR (Temp), que.ct, read); IF (status # 0) OR (read = 0) THEN RETURN NotReceiving; END; FOR i := 1 TO read DO BufIn[portnum]^ := Temp[i]; IF BufIn[portnum] = BufLimit[portnum] THEN BufIn[portnum] := BufStart[portnum]; ELSE INC (BufIn[portnum]:ADDRESS); END; IF BufIn[portnum] = BufOut[portnum] THEN RETURN BufferOverflow; END; END; END; IF BufIn[portnum] = BufOut[portnum] THEN RETURN NoCharacter; END; ch := BufOut[portnum]^; IF BufOut[portnum] = BufLimit[portnum] THEN BufOut[portnum] := BufStart[portnum]; ELSE INC (BufOut[portnum]:ADDRESS); END; RETURN Success; END GetChar; PROCEDURE SendChar (portnum : CARDINAL; ch : CHAR; modem : BOOLEAN) : CommStatus; (* send a character to the comm port *) VAR wrote : CARDINAL; status : CARDINAL; commSt : CHAR; BEGIN IF NOT CheckPort(portnum) THEN RETURN InvalidPort; END; status := DosDevIOCtl (ADR (commSt), 0, 64H, 1, Handle[portnum]); IF (status # 0) OR (commSt # 0C) THEN RETURN TimeOut; ELSE status := DosWrite(Handle[portnum], ADR(ch), 1, wrote); IF (status # 0) OR (wrote # 1) THEN RETURN TimeOut; ELSE RETURN Success; END; END; END SendChar; BEGIN (* module initialization *) (* nothing open yet *) FOR pn := 0 TO 3 DO Handle[pn] := 0; BufStart[pn] := NIL; BufLimit[pn] := NIL; BufIn[pn] := NIL; BufOut[pn] := NIL; BufSize[pn] := 0; END; END CommPort.