Sériová komunikace
Pøíloha 2.

program int;

uses dos, crt;

const
{------------------- COM ports in PC -------------------}
COM1= $3f8;
COM2= $2f8;
Intr: Integer = $0b;

{------------------- 8250 registers --------------------}
RBR= 0;						{ received data - read only -  if DLAB=0 }
THR= 0;						{ transmit data - write only - if DLAB=0 }

DLL= 0;						{ baud generator (LSB) - if DLAB=1 }
DLM= 1;						{ baud generator (MSB) - if DLAB=1 }

IER= 1;						{ interrupt enable - r/w }
IIR= 2;						{ interrupt identification - read only }
LCR= 3;						{ line control register - r/w }
MCR= 4;						{ modem control register - r/w }
LSR= 5;						{ line status - read only }
MSR= 6;						{ modem status register - read only }

{------------------- 8250 register bits ----------------}
IER_RX= 1;					{ intr on received data - priority 2 }
IER_TX= 2;					{ intr on data transmitted - priority 3 }
IER_ERR= 4;					{ intr on receive error (see LSR) - priority 1 }
IER_MS= 8;					{ intr on modem sts change (see MSR) - priority 4 }

IIR_PEND= 1;					{ active intr request }
IIR_MASK= 6;					{ source id mask }
IIR_MS= 0;					{ modem sts change }
IIR_TX= 2;					{ data transmitted }
IIR_RX= 4;					{ data received }
IIR_ERR= 6;					{ receive error }

LCR_5BIT= 0;					{ byte length codes }
LCR_6BIT= 1;
LCR_7BIT= 2;
LCR_8BIT= 3;

LCR_2STOP= 4;					{ two stop bits }
LCR_PTYEN= 8;					{ parity enabled }
LCR_EVPTY= $10;					{ even parity }
LCR_FIXPTY= $20;				{ fixed parity }
LCR_INTREN= $40;				{ interrupt enabled }
LCR_DLAB= $80;					{ baud gen. access enabled }

MCR_DTR= 1;					{ DTR modem signal }
MCR_RTS= 2;					{ RTS modem signal }
MCR_OUT1= 4;					{ user signal }
MCR_OUT2= 8;					{ user signal - wired to 3 state IRQ driver }
MCR_LOOP= $10;					{ test loop }

LSR_RX= 1;					{ data received  }
LSR_OR= 2;					{ overrun - read once }
LSR_PR= 4;					{ parity error - read once }
LSR_FR= 8;					{ frame error - read once }
LSR_BT= $10;					{ break error - read once }
LSR_BF= $20;					{ tx buffer empty }
LSR_TX= $40;					{ serializer empty }

MSR_CSR_CH= 1;					{ CSR has changed - read once }
MSR_DSR_CH= 2;					{ DSR has changed - read once }
MSR_RI_END= 4;					{ RI ended - read once }
MSR_RLSD_CH= 8;					{ RLSD changed - read once }
MSR_CSR= $10;
MSR_DSR= $20;
MSR_RI= $40;
MSR_RLSD= $80;

DLM_300= 1;					{ 300 Baud }
DLM_HIGH= 0;					{ more than 300 Baud }

DLL_300= $80;					{ 300 Baud }
DLL_600= $c0;					{ 600 Baud }
DLL_1200= $60;					{ 1200 Baud }
DLL_2400= $30;					{ 2400 Baud }
DLL_4800= $18;					{ 4800 Baud }
DLL_9600= $0c;					{ 9600 Baud }
DLL_19200= $06;					{ 19200 Baud }


{-------------------------------------------------------------------}
type word= 0..65535;

{-------------------------------------------------------------------}
var
	org_int: pointer;
	com: word;
	c: char;
	xp, yp ,xv ,yv: byte;

{-------------------------------------------------------------------}
procedure init_com(com:word);
begin
	port[com + IER] := 0;			{ deny innterupt on com }

	port[com + LCR]:= $80;			{ DLAB=1, for speed settings }
	port[com + DLL]:= DLL_1200;		{ speed to 1200 }
	port[com + IER]:= 0;
	port[com + LCR]:= $03;			{ 8b data, 1b stop, no parity }
	port[com + IIR]:= $07;			{ 1 byte length buffer and its cleaning }
	port[com + MCR]:= $0b;			{ OUT2 to 1, enable int }
	if intr = $0c then			{ mask int }
		port[$21]:= port[$21] and $EF
	else
		port[$21]:= port[$21] and $F7;
	port[com + IER]:= $01;			{ int on received character }
end;

{-------------------------------------------------------------------}
function rx_rdy (portaddr: word): boolean;
begin
	rx_rdy:=((port[portaddr + LSR] and LSR_RX) <> 0);
end;

{-------------------------------------------------------------------}
function tx_rdy (portaddr: word): boolean;
begin
	tx_rdy:=((port[portaddr + LSR] and LSR_BF) <> 0);
end;

{-------------------------------------------------------------------}
function rx_get (portaddr: word): char;
begin
	rx_get:= chr(port[portaddr + RBR]);
end;

{-------------------------------------------------------------------}
procedure tx_put (portaddr: word; c: char);
begin
	port[portaddr + THR]:= ord(c);
end;

{-------------------------------------------------------------------}
procedure rx_int; interrupt;
begin
	if (rx_rdy(com)) then
	begin
		window(1, 13, 80, 25);
		gotoxy(xp,yp);
		c:= rx_get(com);
		write(c);
		if c = chr(13) then
			writeln;
		xp:= wherex;
		yp:= wherey;
	end;
	port[$20]:= 20;
end;

{-------------------------------------------------------------------}
begin
	com:= COM1;

	xp:= 1; yp:= 1; xv:= 1; yv:= 1;
	clrscr;
	writeln('Press Esc to exit');
	writeln('Send:');
	gotoxy(1, 11);
	writeln('----------------------------------------------------------------');
	gotoxy(1, 12);
	writeln('Receive:');
	c:= #59;

	getIntVec($0B, org_int);		{ new int procedure }
	setIntVec($0B, addr(rx_int));
	init_com(com);				{ init }

	while (ord(c) <> 27) do			{ end via Esc key }
	begin
		if keypressed then		{ if key pressed... }
		begin
			if tx_rdy(com) then	{ ...and out buffer is empty... }
			begin
				window(1, 3, 80, 10);
				gotoxy(xv, yv);
				c:= readkey;	{ ...read character from keyboard...}
				tx_put(com, c);	{ ...send it... }
				write(c);	{ ...and copy it also on screen }
				if c = chr(13) then
					writeln;
				xv:= wherex;
				yv:= wherey;
			end;
		end;
	end;
	c:= readkey;
	setIntVec($0B, org_int);
end.