[comp.sys.mac.programmer] Serial I/O problem w/THINK Pascal 2.0

KPURCELL@LIVERPOOL.AC.UK (09/21/90)

Below is the text of a program that we wrote to find out why a piece of code
written by a consultant wouldn't correctly control the serial port. We have
since written some code to do the same stuff (that works :-) using the serial
manager.

Firstly, the

  open(Q1, 'modem:');

THINK Pascal considers the printer port as write-only and the modem port as
read-write (this is mentioned in the Language Reference 9.5 on page 321-322).

But when you open the modem: port for I/O, the I/O actually
happens on the PRINTER port for I/O. Opening the printer: won't allow reading
that port (hey, the printer is a write-only device, right) but the written
output comes out of the physical MODEM port.

The upshot of this is:

1. We can't use Appletalk, if we want to do serial I/O.
2. We are very confused why the ports in the program don't correspond to
   the right miniDINs on the mac.

A secondary problem is that when you send a CR (CHAR(ORD(13))) out of the port
the device actually sends a CR/LF pair. On reading a CR/LF the port returns
a space for the CR character and a ORD(13) for the LF.

Final problem. We tried a loopback (output of a port goes to input of a
port) and write and read almost simultaneously then it seems to drop
characters, whereas a routine using the Serial Drivers and FSRead/FSWrite
has no problems.

So the final question is: is this a known bug or, perhaps more likely, are we
doing something really stupid? Take a look at the code below. I have RTFM but
couldn't find anything relevant.

Does it have anything to do with mixing Pascal TEXT I/O and the Serial Driver
routines? (sinking feeling :-)

This started as a quick "oh we'll do it this way to save some time" hack,
but we've ended up doing it properly (with the drivers and the File Manager) in
the end after wasting a couple of days chasing the problem.

Thanks for any assistance,
Kevin

Kevin Purcell          | kpurcell@liverpool.ac.uk
Surface Science,       |
Liverpool University   | Programming the Macintosh is easy if you understand
Liverpool L69 3BX      | how the Mac works and hard if you don't. -- Dan Allen

------------------------ program follows ------------------------------

{Lest it destroy my credibility I *didn't* write this! -kgp}

program bull;
	var
		Event, h, i: integer;
		q1: text;
		p: char;
		l: longint;
		SerAshk: SerShk;
		SerASta: SerStaRec;
		evnt: eventrecord;
		Done: boolean;
		GrowLimit, DragLimit: rect;
		FirstClick: longint;
		window, txw, drw: WindowPtr;
		pnt: point;
		stn: str255;

	procedure HandleKey;
		var
			ch: char;
			j: integer;
	begin
		Evnt.Message := BitAnd(Evnt.Message, $FF);
		ch := Chr(Evnt.Message);
		setport(drw);
		GetPen(pnt);
		write(q1, ch);
		writedraw(ch);
	end;


	procedure HandleMouse;
		var
			part: integer;
			newSize: longint;

	begin
		part := FindWindow(Evnt.Where, window);
		if window = nil then
			exit(handleMouse);
		if window <> FrontWindow then
			SelectWindow(window);
		case part of
			InGrow:
				begin
					newSize := GrowWindow(Window, Evnt.Where, GrowLimit);
					if newSize <> 0 then
						SizeWindow(Window, LoWord(newsize), HiWord(newsize), TRUE);
				end;
			indrag:
				if TickCount > (FirstClick + GetDblTime) then
					begin
						FirstClick := TickCount;
						DragWindow(window, Evnt.where, DragLimit);
					end;
			ingoaway:
				done := true;
			otherwise
		end
	end;



begin
	Done := false;
	SetRect(GrowLimit, 80, 80, 512, 322);
	SetRect(DragLimit, 50, 20, 512, 250);
	FirstClick := 0;
	showdrawing;
	getport(drw);
	showtext;
	getport(txw);
	moveto(0, 12);
	open(Q1, 'modem:');
	for i := -20 to 0 do
		if SerGetBuf(i, l) = 0 then
			leave;
	if i >= 0 then
		Writeln('find failed');
	if SerReset(i, $4c0a) <> 0 then
		writeln('speed failed');
	with SerAshk do
		begin
			fxon := 0;
			finx := 0;
			errs := $70;
			fcts := 1;
		end;
	writeln(SerHshake(i, SerAshk));
	writeln(SerStatus(i, SerASta));
	writeln(SerASta.ctshold);
	writeln('ref:=', i : 4, '   ', l : 4, '  bytes in buffer');

	WRITE(Q1, 'CD/0/', CHR(13), 'X');
	WRITE(Q1, 'AB/', CHR(13), 'X');


	repeat
		systemtask;
		if GetNextEvent(EveryEvent, Evnt) then
			case Evnt.What of
				KeyDown, AutoKey:
					HandleKey;
				MouseDown:
					HandleMouse;
				otherwise
			end;
		if SerGetBuf(i, l) = 0 then
			if l > 0 then
				begin
					read(q1, p);
					setport(txw);
					selectwindow(txw);
					GetPen(pnt);
					if ORD(P) = 10 then
						WRITELN
					else
						WRITE(P);
				end;
	until done;
	close(q1);
end.