DataMuseum.dk

Presents historical artifacts from the history of:

RC3500

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC3500

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦b0c00adc3⟧ TextFileVerbose

    Length: 33024 (0x8100)
    Types: TextFileVerbose
    Names: »tsoerjob«

Derivation

└─⟦a41ae585a⟧ Bits:30001842 SW-save af projekt 1000, Alarm-system
    └─⟦72244f0ef⟧ 
        └─⟦this⟧ »tsoerjob« 

TextFileVerbose

job oer 9 200 time 11 0 size 100000 area 10
( mode list.yes
source = copy 25.1
o c
tsoererr = set 1 disc1
tsoerlst=set 1 disc1
if ok.yes
(message lam116 compile
o tsoererr
pascal80 codesize.8000 spacing.12 evaenv alarmenv source;
o c
lookup pass6code
if ok.yes
( tsoerbin=set 1 disc1
tsoerbin= move pass6code
scope user tsoerbin
message lam116 ok
)
liste=indent source lc mark
lst=cross liste
tsoerlst = copy lst tsoererr
scope user tsoerlst
scope user tsoererr
message lam116 liste
)
finis output.no
)
\f


process lam(
opsem: sempointer;
pu: integer;
level:integer;
var mainsem: !ts_pointer
);

(*********************************************************
*                                                        *
*   lam-driver                                           *
*   programmed by oer                                    *
**********************************************************)

(*-------------------------------------------------------
. terms
.
. port     refers to a port on the physical lam
. channel  refers to a channel in the lamdriver
.          where there are two channels for each port
.          i e one for output and one for input
.
.--------------------------------------------------------*)

const

version = "vers  3.16 /";

max_port_no=15;
max_channel_no= 2*max_port_no+1;

(*---  values used when creating high level lam-driver ---*)
mask = 0;
      prio  = 2;
      store = 200;
(*--- number of lambuffers, one is used as channelmessage ---*)
no_of_lambufs = 32;


long_time = 10;
normal_time = 7;
short_time = 4;
no_time = 1;

forever = false;


(*       controlebits to lam *)
requesttosend = 7*32;
readytoread = 5*32;

(*       statuswords from lam *)
write_read_ok = 40;
overrun=41;
parity=44;
overrun_and_parity=45;
readytosend = 24;

(* alc-functions *)

alc_write = write_it;
alc_read = read_it;
write_alc_read = write_read_it;
create_alc_ch = create_it_ch;
op_codes = (. 5, 19, 20, 21, 28, 29 .);
\f


(*---  channelkinds  ---*)

not_created = 0;
at_write_channel = 1;
at_write_wait = 2;
at_read_channel = 3;
at_read_wait = 4;
alc_write_channel = 5;
alc_read_channel = 6;
tty_write_channel = 7;
tty_read_channel = 8;
echo_nl_on_channel = 9;
tty_wait_cr = 10;
tty_wait_nl = 11;
tty_wait_input = 12;


(*---  delays used on at-channels  ---*)

rts_delay_u3 = 10;
rts_delay_u4 = 5;

rtr_delay_u3 = 13;
rtr_delay_u4 = 5;


(*---  byte-compatible values for special characters  ---*)

stx = 2;
etx = 3;
bs = 8;
nl = 10;
cr = 13;
cs = 19;       (*  crtl + small s   *)
esc = 27;
sp = 32;
del = 127;

command = 28;
\f



(*  result codes  *)
(*  specified in u2 overwriting portno *)
(*  other resultcodes are given in alarmenv *)

transient_error = transi_err;
persistent_error = persi_err;
illegal_function = ill_func;
write_error = 2*8 +  transient_error;
write_read_mixed = create_done;
buffer_too_small = illegal_function;
go_on_read = 6▶07◀;
(*-------------------
results modified for
transient errors

2*8 +2 = write-error
3*8 +2 = parity or overrun
4*8 +2 = checksum error
5*8 +2 = read bbl too big
6*8 +2 = etx missing

---------------------*)

(****************************************
*
*  params that should be used in create channel
*
*  +0  odd parity
*      1 stop element
*      5 databits/char
*      110 bps
*  +1  no parity
*  +2  even parity
*  +3  no parity
*  +4  2 stop elements
*  +8  6 databits
*  +16 7 databits
*  +24 8 databits
*  +32 300 bps
*  +64 600 bps
*  +96 1200 bps
*
****************************************)
\f


type
(*      no of input+output devices on one lam-driver *)
channelset   = 0..max_channel_no;

portset = 0..max_port_no;

(*      format of a buffer send to/from a vcit *)
drvbuffer
= record
first, last, next : integer;
end;

(*      format of a buffer send to/from a vcat or at *)
atbuffer
= array(0..1)   of byte;


(*      one word to write in writeword *)

lamword
= packed record
data : byte;
std : 0..7;
port_and_bit15 : channelset;
end;

(*      one description for each device *)

channelrecord
= record
request:reference;           (*  current message     *)
channel_kind : 0..15;
old_result : byte;
interruptable : boolean;
reading_tty : boolean;
checksum: integer;
timeout,
next,
top: integer;
status : integer;
end;
\f


var
(*        ref for channelmsg *)
  channelmessage,ref:   reference;
(*        shadow for lam at high level *)
      driver:    shadow;

lamsem : semaphore;
(*---  pools  ---*)

delaypool : pool 16;
      timerpool: pool 1;
(*        buffers for handling interrupts *) 
      lampool:   pool no_of_lambufs;

(*        devicenumber *)
      channel_no:     integer;
(*        zone used by testopen and testout *)
      z:    zone;
(*        all devicedescriptors in one array *)

      channel_descriptor:  array(channelset) of channelrecord;

queue : array(channelset) of semaphore;

(*        timeoutperiode and controlword for each device *)
      time,controle_byte: array(portset)of byte;

i,j,k : integer;
test_b : boolean;
read_checksum : integer;
tst : integer := 0;
dummy_byte : byte := 0;
\f


(***************   externals   ***********************************)

function  copychm(var x,y: reference): integer; external;
(* makes a copy of a channelmessage *)

procedure testopen(var x:zone; y:alfa; z:^semaphore); external; 
(* opens testmode *)

 procedure testout(var x:zone; y:alfa; z:integer); external; 
(* writes text for test *)

procedure control( x: integer; var y: reference); external;
(* writes one controlword *)

procedure outword( x: lamword; var y: reference); external;
(* writes one word *)


procedure sense(var x:integer; y:integer; var z:reference); external;


(***************   procedures  ***********************************)

procedure stop_actual_request
 ( result: byte;  channel_no: channelset );
forward;


\f


procedure start_rts_delay(channel_no : integer);
(*********************************************
*   rts-delay                                *
**********************************************)

var ref:reference;
begin
alloc(ref, delaypool, mainsem.s^);
ref^.u3 := rts_delay_u3;
ref^.u4 := rts_delay_u4;
ref^.u1 := channel_no*2;
(*q if test_b then
testout( z, "rts-delay   ", ref^.u1); q*)
sendtimer(ref);
end;





procedure start_rtr_delay(channel_no : integer);
(*********************************************
*   rtr-delay                                *
**********************************************)

var ref:reference;
begin
alloc(ref, delaypool, mainsem.s^);
ref^.u3:=rtr_delay_u3;
ref^.u4:=rtr_delay_u4;
ref^.u1 :=channel_no*2+1;
(*q if test_b then
testout( z, "rtr-delay   ", ref^.u1); q*)
sendtimer(ref);
end;

\f


procedure createchannel( w_kind, r_kind: 0..15 );
(***********************************************
*   createchannel                              *
************************************************)

var i: integer;
begin
i:=ref^.u2;
channel_descriptor(i*2).channel_kind:=w_kind;
channel_descriptor(i*2+1).channel_kind:=r_kind;

channel_descriptor(i*2).status := write_read_ok;
channel_descriptor(i*2+1).status := write_read_ok;

lock ref as buf:atbuffer do
begin
controle_byte(i):=buf(0) mod 128;
time(i):=buf(1);
end;

ref^.u2:=ok_result;
return(ref);

(*q if test_b then
begin
testout( z, "chn created ", i);
testout( z, "controlebyte", controle_byte(i));
end; q*)
end;
\f



(*******************************************************
*   start_next_request                                        *

*   initializes   next,  top,  and  timeout  in        *
*                 channeldescriptor(channel_no)             *
*           and   channel if it is used for output     *
*                                                      *
*   called when - not finished with write/read         *
*               - more requests after stop_actual_request
*               - timeout on write                     *
*               - no requests when a new userbuffer    *
*                 is comming                           *
********************************************************)


procedure start_next_request( channel_no:channelset);
var c : integer;
begin
with channel_descriptor(channel_no) do
begin

timeout:= time(channel_no div 2);

(*q if test_b then
begin
testout( z,"sta-nxt-req ", channel_no);
testout( z,"chn-kind    ",channel_kind);
end; q*)

if channel_kind = at_write_channel then
begin
(*                set up for output  *)
c:=controle_byte(channel_no div 2)*256+requesttosend+channel_no;
control(c,channelmessage);
(*q if test_b then
testout(z,"rts-init    ",c); q*)
start_rts_delay(channel_no);
channel_kind := at_write_wait;
end
\f


else
begin
if channel_kind = tty_read_channel then
channel_descriptor(channel_no-1).reading_tty:=true;
interruptable:=true;
end;

if request^.u1 > write_alc_read then
begin
lock request as buf: drvbuffer do
begin
next:= buf.next;
top:= buf.last+1;
end;
end

else
if request^.u1 <= write_read_at then 
begin
next := 0;
top := 2;
end
else
begin
if request^.u3 >= command then
lock request as buf : drvbuffer do
begin
buf.next := buf.first;
top := buf.last -buf.first + 6;
end
else
top := 4;
next := 1;
if channel_kind = alc_read_channel then
timeout := timeout * 10;
end;
end;
end;
\f


(*******************************************************
*   stop_actual_request
                                             *
*   sends answer back to user
*   if we shall go on read the request is send to      *
*   queue at channel_no+1                                  *
********************************************************)

procedure stop_actual_request
( result:byte; channel_no:channelset);

var c : integer;


begin

with channel_descriptor(channel_no) do

case channel_kind of

at_write_channel:
begin
start_rtr_delay(channel_no);
channel_kind := at_read_wait;
old_result := result;
end;

at_read_wait:
begin
c:=controle_byte(channel_no div 2)*256+readytoread+channel_no;
control(c,channelmessage);
channel_kind := at_write_channel;
result:= old_result;
(*q if test_b then
testout( z,"rtr-answer  ", c); q*)
end
otherwise;
end;
\f


if channel_descriptor(channel_no).channel_kind <> at_read_wait then
begin

if result = go_on_read then
begin

(*q if test_b then
testout( z,"go on read  ", channel_no); q*)

while not nil( channel_descriptor(channel_no+1).request) do
with channel_descriptor(channel_no+1) do
begin
request^.u2:=write_read_mixed;
return(request);
sensesem( request, queue(channel_no+1));
end;
channel_descriptor(channel_no+1).request:=:channel_descriptor(channel_no).request;
start_next_request(channel_no+1);
end
else
begin
with channel_descriptor( channel_no) do
if (( channel_kind=alc_read_channel) or (channel_kind=alc_write_channel)) then
begin
<*t
if result <> 0 then
begin
if channel_kind=alc_read_channel then
testout(z,"ui-r        ", result)
else
testout(z,"uo-r        ", result);
testout(z,"opc         ", request^.u3);
end;
t*>

request^.u4 := status mod 256;
end;
channel_descriptor(channel_no).request^.u2:=result;

(*q if test_b then
testout( z, "returning   ", channel_no); q*)
return(channel_descriptor(channel_no).request);
end;
\f


with channel_descriptor(channel_no) do
begin
timeout:=0;
       sensesem(request,queue(channel_no));
if channel_kind = tty_read_channel then
begin
if nil(channel_descriptor(channel_no-1).request) then
begin      (*   no writes are waiting  *)
if nil(request) then
channel_descriptor(channel_no-1).reading_tty := false
else
start_next_request( channel_no)
end
else
begin      (*   writes are waiting   *)
channel_descriptor(channel_no-1).reading_tty:=false;
start_next_request(channel_no-1);
end
end
else
if channel_kind = tty_write_channel then
begin
if nil( request) then
begin      (*   no more writes look for reads  *)
if not nil(channel_descriptor(channel_no+1).request) then
start_next_request(channel_no+1)
end
else
start_next_request(channel_no);
end
else
if nil(request) then interruptable:=false
else start_next_request(channel_no);
end;
end;
end;
\f



function packed_word ( databits: byte; channel_no: channelset): lamword;
(********************************************************
*   makes a word ready for outword                      *
*********************************************************)
var   w: lamword;
begin
w.data:= databits;
w.std := 0;
w.port_and_bit15:=channel_no;
 packed_word:= w
end;
\f


procedure set_lam_control( channe{_no : channelset);
var c : integer;
begin
channel_no := channel_no - channel_no mod 2;
c := controle_byte( channel_no div 2) *256 + channel_no;
if channel_descriptor(channel_no).channel_kind = at_write_channel then
c := c+readytoread
else
c:= c+ requesttosend;

control( c, channelmessage);
end;
\f


procedure start_new_channel(channel_no: channelset);
(********************************************************
*   start_new_channel                                               *
*   called when - channel is created                    *
*               - persistent status error               *
*               - timeout on write or write/read        *
*********************************************************)

begin
set_lam_control( channel_no);

with channel_descriptor(channel_no) do
while not nil(request) do
stop_actual_request
(create_done, channel_no);

channel_no:= channel_no+1;
with channel_descriptor(channel_no) do
while not nil(request) do
stop_actual_request
(create_done, channel_no);
end;
\f


function ready_to_send( channel_no:channelset):boolean;
(********************************************************
*   ready-to-send                                         *
*********************************************************)

begin
with channel_descriptor(channel_no) do
begin
sense( status, channel_no, channelmessage);

if status mod 32 div 8 = 3 then
ready_to_send := true
else
ready_to_send:=false
end;
end;
\f


procedure handle_ok_lam_int(var data_byte: byte; channel_no: channelset);
(********************************************************
*   handle_ok_lam_int                                             *
*   handles the buffer pointed to by request                *
*                                                       *
*   if it is a writebuffer the byte pointed to by next  *
*   is output                                           *
*                                                       *
*   if it is a readbuffer the data_byte is put into       *
*   the buffer at the byte pointed to by next           *
*                                                       *
*********************************************************)


begin
(*q if test_b then
testout(z, "hndl-o-l-int", channel_no); q*)

with channel_descriptor(channel_no) do

case channel_kind of
\f


at_write_channel :

if next >= top then
begin
(*q if test_b then
testout( z, "next = top  ", 0); q*)
if request^.u1 = write_read_at then
stop_actual_request
( go_on_read, channel_no)
else stop_actual_request
( ok_result, channel_no);
end
else
begin
<*rif ready_to_send(channel_no) then
r*>
lock request as buf:atbuffer do
begin

(*q if test_b then
begin
testout( z, "at-w-next   ", next);
testout( z, "at-w-ch     ", buf(next)); 
end; q*)

outword( packed_word( buf(next), channel_no), channelmessage);
next:=next+1;
end
<*r
else
stop_actual_request
( write_error, channel_no)
r*>
end;
\f


at_read_channel :

begin
lock request as buf:atbuffer do
buf(next):=data_byte;
(*q if test_b then
begin
testout( z, "at-r-next   ", next);
testout( z,"at-r-ch     ", data_byte); 
end; q*)
next:=next+1;
if next >= top then
stop_actual_request
( ok_result, channel_no);
end;
\f


alc_read_channel :

begin
if next < top then
case next of

1 :
begin
if data_byte <> stx then
next := 0;
checksum := 0;
end;


2 : (* stx should be read *)

if data_byte <> stx then
next := 0;

3 : (* opcode should be read *)
begin
old_result := data_byte;
if not (data_byte in op_codes) then
next := 0
else
if data_byte < command then
top := 4;
end;

4 : (* bbl should be read *)
begin


if top < data_byte + 6 then
begin  (* read bbl too big *)
stop_actual_request
( 5*8 + transient_error, channel_no);
(*qtestout(z,"reci-bbl    ", data_byte);q*)
end
else
begin
top := data_byte + 6;  (* top points at etx *)

(*qtestout(z,"reci-bbl    ", data_byte);q*)
end


end;

otherwise

begin  (* info is read *)

i := request^.size;

lock request as buf : record
first, last, next : integer;
info : array (6..i-1+i) of byte;
end do
begin
buf.info(buf.next) := data_byte;
buf.next := buf.next +1;
end;

(*qtestout(z,"reci-info   ", data_byte);q*)


end
end (* case *)
\f


else
if next = top then
(*---  etx should be read *)

begin
if data_byte <> etx then
begin (* start again *)
next := 0;
if request^.u3 >= command then
lock request as buf : drvbuffer do
begin
buf.next := buf.first;
top := buf.last - buf.first +6;
end
else
top := 4;
end;

end

else
begin (* next >= top + 1 *)
       (* chs should be read *)

if data_byte <> checksum then
begin
stop_actual_request
( 4*8 + transient_error, channel_no);
end
else
begin

request^.u3 := old_result;

stop_actual_request
( ok_result, channel_no);

(*qtestout(z,"release-ui  ", 0);q*)
end;
end;
next := next +1;
checksum := (checksum + data_byte) mod 256;
end;
\f


alc_write_channel :
begin

<*r
if ready_to_send ( channel_no) then
r*>
begin

if next < top then

case next of

1 :
begin
data_byte := stx;
checksum := 0;
end;

2 : (* stx is send *)

data_byte := stx;

3 : (* opcode is send *)
begin
data_byte := request^.u3;
end;

4 : (* bbl is send *)

lock request as buf : drvbuffer do
begin  (* bbl *)
data_byte := buf.last - buf.first;
(*qtestout(z,"send-bbl    ", data_byte);q*)
end;
otherwise

begin
i:= request^.size;

lock request as buf : record
first, last, next : integer;
info : array (6..i-1+i) of byte;
end do
begin
data_byte := buf.info( buf.next);
buf.next := buf.next +1;
(*qtestout(z,"send-info   ", buf.info(buf.next));q*)
end;
end
end (* case *)
\f


else
if next = top then
begin
data_byte := etx;
(*qtestout(z,"send-etx    ", checksum);q*)
end

else
if next = top + 1 then

(* chs is send *)

begin
data_byte := checksum;
(*qtestout(z,"send-chs    ", etx);q*)

end
else
(*  next >= top + 2 *)
(*  user buffer is released *)

begin
stop_actual_request
( ok_result, channel_no);

(*qtestout(z,"release uo  ",next);q*)
end;

end;
<*r
else
stop_actual_request
(write_error, channel_no);
r*>
outword( packed_word( data_byte, channel_no), channelmessage);
checksum := (checksum + data_byte) mod 256;
next := next + 1;
end;
\f


tty_read_channel :

begin

(*q if test_b then
begin
testout( z,"tty-r-next  ", next);
testout( z,"tty-r-ch    ", data_byte);
end; q*)


case data_byte of

esc :
begin
with channel_descriptor( channel_no-1) do
if not reading_tty then
begin
timeout:=0;
channel_kind:=tty_wait_cr;
lock request as buf:drvbuffer do
if next > 1 then
buf.next:=next-1
else
buf.next:=next;
end
else
channel_kind := tty_wait_nl;
outword( packed_word( cr, channel_no), channelmessage);
start_next_request( channel_no);
(*ttestout(z,"esc         ",timeout);t*)
end;

cs :
with channel_descriptor(channel_no-1) do
if not reading_tty then
begin
while not nil(request) do
begin
request^.u2:=create_done;
return(request);
sensesem(request,queue(channel_no-1))
end;
timeout:=0;
if not nil(channel_descriptor(channel_no).request) then
start_next_request(channel_no);
end
else  (*  reading tty  *)
begin
with channel_descriptor( channel_no) do
begin
i:= request^.size;

lock request as buf : record
first, last, next : integer;
text : array (1..i-6+i) of byte;
end do
begin
if next > (i-6+i) then next := (i-6+i);
buf.text(next):=cs;
next:=next+1;
if next>=top then
buf.next:=next;
end;
if next>=top then
stop_actual_request
( ok_result, channel_no);
end;
outword(packed_word(cr,channel_no), channelmessage);
(*ttestout(z,"cs          ",timeout);t*)
channel_kind:=echo_nl_on_channel;
end;

del,bs :
if channel_descriptor(channel_no-1).reading_tty then
begin
lock request as buf:drvbuffer do
if next > buf.first then       (*  erase  *)
next:=next-1;
outword( packed_word( bs, channel_no), channelmessage);
end;
cr:          (*  return   works as line-end    *)
if channel_descriptor(channel_no-1).reading_tty then
begin
i := request^.size;

lock request as buf : record
first, last, next : integer;
text : array (1..i-6+i) of byte;
end do
begin
channel_descriptor(channel_no-1).channel_kind:=echo_nl_on_channel;
buf.text(next):=data_byte;
if next<top-1 then
begin
buf.text(next+1):=nl;
buf.next:=next+2
end
else
buf.next:=next+1;
outword( packed_word( cr, channel_no), channelmessage);
(*ttestout(z,"cr          ",timeout);t*)
end
end
\f


otherwise      (*  packed_word character   *)

if channel_descriptor(channel_no-1).reading_tty then
begin
i := request^.size;

lock request as buf : record
first, last, next : integer;
text : array (1..i-6+i) of byte;
end do
begin
            (*  index error has been seen here,  next=81    *)
if next > (i-6+i) then next := (i-6+i);
buf.text(next):=data_byte;
next:=next+1;
if next >= top then
buf.next:=next;
end;
if next>=top then
stop_actual_request
( ok_result, channel_no);
outword( packed_word( data_byte, channel_no), channelmessage);
end
end;
if channel_descriptor(channel_no-1).reading_tty then
if timeout<normal_time then
timeout:=normal_time;
end;    (*  case read_tty  *)
\f


tty_write_channel :

if not reading_tty then
<*r
if ready_to_send(channel_no) then
r*>
begin
i:= request^.size;

lock request as buf : record
first, last, next : integer;
text : array (1..i-6+i) of byte;
end do
begin

(*q if test_b then
begin
testout( z, "tty-w-next  ", next);
testout( z, "tty-w-ch    ", buf.text(next));
end; q*)

outword ( packed_word( buf.text(next), channel_no), channelmessage);
next:= next+1;
if next>= top then    (*  terminate  *)
buf.next:= next;
end;
if next>=top then
stop_actual_request
 ( ok_result, channel_no)
end;
<*r
else
stop_actual_request
( write_error, channel_no);
r*>

\f


echo_nl_on_channel :
begin
(*ttestout(z,"nl          ",timeout);t*)
outword( packed_word( nl, channel_no), channelmessage);
if reading_tty then
stop_actual_request( ok_result, channel_no+1);
channel_kind:=tty_write_channel;
end;

tty_wait_cr :
begin
outword(packed_word(cr,channel_no),channelmessage);
channel_kind:=tty_wait_nl;
(*ttestout(z,"esc cr      ",timeout);t*)
end;

tty_wait_nl :
begin
outword(packed_word(nl,channel_no),channelmessage);
channel_kind:=tty_wait_input;
(*ttestout(z,"esc nl      ",timeout);t*)
end;

tty_wait_input :
begin
end;
otherwise
begin
end
        end;
end;
\f


(***********************************************************
*                                                          *
*   high level lam-driver                                  *
*                                                          *
*  converts an interrupt to a signal to the level-0-driver *
*                                                          *
*   handles input only                                     *
************************************************************)

process highlevellamdriver( var lamsem: semaphore);

const
readytosend= 24;
startscanner = -1;
interrupt_ok=40;
no_input=255;

type
dataword
= packed record
data:byte;
unused:0..3;
error:boolean;
port_and_bit15: 0..31;
end;

var
 channelmessage,ref:  reference;
     indata:   dataword;
     status:   integer;

procedure controlclr(x:integer; var y:reference); external;
(*        writes controle and clears interrupt *)

procedure inword( var x: dataword; var y: reference); external;
(*         reads one word *)

procedure sense( var x:integer; y:integer; var z:reference); external;
(*         gets status *)
\f


begin

wait(channelmessage,lamsem);
(*            wait for a channelmessage to arrive *)

channel channelmessage do
while true do
begin
controlclr(startscanner,channelmessage);
(*            write control and clear interrupt *)
        inword(indata,channelmessage);
(*            read one word of input *)
        wait(ref,lamsem);
(*            wait for inputbuffer at lamsem *)
        with indata,ref^ do
begin
u2:=interrupt_ok;
if (port_and_bit15 mod 2) = 0 then
(*          it is an outputinterrupt *)
u3:=no_input
else
if error then
begin
sense(status, port_and_bit15, channelmessage);
u2 := status mod 64;
end
else
u3:=data;
u4:=port_and_bit15;

(*******************************
*                      +1 overrun
*                      +2 framing error
*  status = 0          +4 parity error
*                      +8 data set ready
*                     +16 ready for sending
*                     +32 data carrier detector
********************************)

        end;
        return(ref);
  end
end;
\f


(********************************************************
*   initialization                                      *
*********************************************************)

begin

  testopen(z, own.incname, opsem); 

testout( z, version, al_env_version);

(*             create and start high level lamdriver *)
  if create( "highlevellam", highlevellamdriver(lamsem), driver, store ) = 0
     then start(driver,prio)
(*q else
if test_b then
 testout(z,"create error",0) q*) ;

(*             first buffer from lampool is used as a copy of channelmess *)
(*q if test_b then
testout(z, "lam-h start ", 0); q*)

  alloc(ref,lampool,mainsem.s^);

  if (reservech(channelmessage, level,mask) + copychm(ref,channelmessage) <> 1) and test_b then
(*q      testout(z,"res.ch error",reservech(channelmessage, level,mask)) q*) ; 
(*             if reservation of channel went well, send copy of channelmess to lamdriver *)
  signal(ref,lamsem);

(*             get one timeoutbuffer *)
  alloc(ref,timerpool,mainsem.s^);
(*             delay is set to u3*2**u4 = 1 sec   *)
ref^.u1 := 6;
  ref^.u3:=250; ref^.u4:=2;
(*             send to systemtimer *)
  sendtimer(ref);
\f


(*             get rest of inputbuffers and send them to lamdriver *)

  for channel_no:=2 to no_of_lambufs do
begin
alloc(ref, lampool, mainsem.s^);
ref^.u1 := 6;
signal(ref,lamsem);
end;

(*             all devicedescriptors are initialized *)

for channel_no:=0 to max_channel_no do
with channel_descriptor( channel_no) do
begin
timeout := 0;
channel_kind := not_created;
interruptable := false;
reading_tty := false;
end;
\f


(********************************************************
*   level-0-lam                                         *
*                                                       *
*    sends output directly to the channel               *
*    handles inputbuffers from highlevel lamdriver      *
*                                                       *
*********************************************************)

 repeat     (*  main loop  *)
(*                  wait for buffer on inputsemaphore *)

  wait(ref,mainsem.w^);
\f


  if ownertest(lampool,ref) then
begin
(*q if test_b then
testout( z, "interrupt on", ref^.u4); q*)

with channel_descriptor(ref^.u4) do

if interruptable then
if (not nil(request)) or (channel_kind>=echo_nl_on_channel) then
begin
status := ref^.u2;
if status = write_read_ok then
handle_ok_lam_int(ref^.u3, ref^.u4)
else
begin
stop_actual_request
(3*8 + transient_error,ref^.u4);
set_lam_control( ref^.u4);
<*
end
otherwise
begin
stop_actual_request
(persistent_error, ref^.u4);
status := ref^.u2;
start_new_channel(ref^.u4);
(*q if test_b then
          testout(z,"hwstatus= 8.",((ref^.u2 div 8)*10+(ref^.u2 mod 8))*100+ref^.u4); q*)
*>
               end;
    end;

    signal(ref,lamsem);
  end
\f


  else
(*          it is a timeoutbuffer from systemtimer *)
  if ownertest(timerpool,ref) then
  begin
    ref^.u3:=250; ref^.u4:=2;
    sendtimer(ref);
    for channel_no:=0 to 31 do with channel_descriptor(channel_no) do
    if timeout>0 then 
begin
timeout:=timeout-1;
if timeout=0 then
if request^.u1=read_tty then
if not nil(channel_descriptor(channel_no-1).request) then
begin
channel_descriptor(channel_no-1).reading_tty := false;
start_next_request(channel_no-1);

lock request as buf:drvbuffer do
begin
if channel_descriptor(channel_no).next>buf.first then
outword( packed_word( 60, channel_no), channelmessage)
else
outword( packed_word(del, channel_no), channelmessage);
end
end
else
stop_actual_request
( timeout_err, channel_no)
else
begin
stop_actual_request
 ( timeout_err, channel_no);
if channel_no mod 2 = 0 then start_new_channel ( channel_no)
end;
    end;
   end
\f


else
(*                   it is a delaybuffer from systemtimer *)
if ownertest( delaypool, ref) then
begin
channel_no:=ref^.u1 div 2;
with channel_descriptor(channel_no) do
begin

case (ref^.u1 mod 2) of
0:
begin
(*q if test_b then
testout( z, "end-rts-dlay", channel_no); q*)
channel_kind:=at_write_channel;
interruptable := true;
handle_ok_lam_int( dummy_byte,channel_no);
end;
1:
begin
(*q if test_b then
testout( z, "end-rtr-dlay", channel_no); q*)
if request^.u1 = write_at then stop_actual_request
( ok_result, channel_no)
else stop_actual_request
( go_on_read, channel_no);
end;
otherwise (*q testout( z, "timer fault ", channel_no) q*);
end;

release(ref);
end
end

else
if ref^.u3 = dummy_route then  return ( ref)
\f


  else
(*       it is a userbuffer *)

  begin
(*       devicenumber is equal to portno *2  *)
    channel_no:=ref^.u2 * 2;

(*       if command is pure read the devicenumber is uneven *)
    if ref^.u1 mod 4 = 1 then channel_no:=channel_no+1;

    case ref^.u1 of

create_at_ch:
begin
createchannel(at_write_channel, at_read_channel);
start_new_channel(channel_no);
end;

create_alc_ch:
begin
createchannel(alc_write_channel, alc_read_channel);
start_new_channel(channel_no);
end;

create_tty_ch:
begin
createchannel(tty_write_channel, tty_read_channel);
channel_descriptor(channel_no).interruptable:=true;
channel_descriptor(channel_no+1).interruptable:=true;
start_new_channel(channel_no);
end;


\f


read_at, write_at, write_read_at :

with channel_descriptor(channel_no) do
if (channel_kind<at_write_channel) or (channel_kind > at_read_wait) then
begin
ref^.u2 := illegal_function;
return( ref)
end
else
     if not nil(request) then signal(ref,queue(channel_no))
else
begin
request:=:ref;
start_next_request(channel_no);
     end;
\f


alc_read, alc_write, write_alc_read :

begin
if ref^.u3 >= command then
begin
lock ref as buf : drvbuffer do
begin
i := buf.first;
j := buf.last;
end;

if (j < i )
or (j-i >= (2*ref^.size -6)) then
begin
(*q if test_b then
testout( z,"buffer small", ref^.size); q*)
ref^.u2:=buffer_too_small;
return( ref);
end;
end;


if not nil( ref) then
with channel_descriptor(channel_no) do
if (channel_kind<alc_write_channel) or (channel_kind>alc_read_channel) then
begin
ref^.u2:=illegal_function;
return( ref);
end
else
begin

if not nil(request) then signal( ref, queue(channel_no))
else
begin
request :=: ref;
start_next_request(channel_no);
if channel_kind=alc_write_channel then handle_ok_lam_int(dummy_byte,channel_no);
end;
end
end;
\f


read_tty:

with channel_descriptor(channel_no) do
if channel_kind < tty_write_channel then
begin
ref^.u2:=illegal_function;
return(ref);
end
else
begin
lock ref as buf : drvbuffer do
begin
i:= buf.first;
j:= buf.last;
end;
if (j<i)
or (i<1)
or (j-i >= 2*ref^.size-6) then
begin
ref^.u2 := illegal_function;
return( ref);
end;

if not nil( ref) then
if not nil ( request) then signal ( ref, queue(channel_no)) 
else
begin   (*  start now  *)
request :=: ref;
(*   look if write_tty is going on  *)
if nil(channel_descriptor(channel_no-1).request) then
start_next_request(channel_no)
end;
end;
\f


write_tty:

with channel_descriptor(channel_no) do
if channel_kind<tty_write_channel then
begin
ref^.u2:=illegal_function;
return(ref);
end
else
begin
lock ref as buf : drvbuffer do
begin
i := buf.first;
j := buf.last;
buf.next:=buf.first;
end;
if (j<i)
or (i<1)
or (j-i >= 2*ref^.size-6) then
begin
ref^.u2 := illegal_function;
return( ref);
end;
if not nil( ref) then
if not nil (request) then
signal ( ref, queue(channel_no))
else
begin
request :=: ref;
(*   look if read_tty is going on   *)

if channel_kind <> tty_wait_input then
if reading_tty then
with channel_descriptor(channel_no+1) do
lock request as buf:drvbuffer do
begin
if next>buf.first then
timeout:=normal_time
else
timeout:=no_time
end
else
begin
start_next_request(channel_no);
if not nil( request) then
handle_ok_lam_int ( dummy_byte, channel_no);
end;
end;
end
\f


otherwise
begin
(*q if test_b then
testout ( z, "unknown     ", ref^.u1); q*)
ref^.u2:=illegal_function;
return(ref);
end
  end;

end   (*  user request  *)

 until  forever

end.     (*  lam driver   *)   
«eof»