!iso4
! Uni-process implementation of ISO-TL

include  "inc:util.imp"
include  "ether:iso4.inc"
include  "ether:iso.inc"
include  "ether:iso4sum"

recordformat  list f (record (listf)name  next,prev,record (*)name  rec)
ownrecord (listf)name  tc list == nil
owninteger  clock phase=0

recordformat  i tc f (record (tcf)userpart,
   half  lref,rref,integer  state,nextin,inlimit,nextout,outlimit,
   record (listf)name  inpend,outpend)

constinteger  max tc = 20
ownrecord (i tc f)namearray  tc refs(1:maxtc) == nil(*)

constinteger -
 clock bit    =   1, {clock phase indicator
 cr sent      =   2, {TCRQ received from user, CR TPDU sent
 cr received  =   4, {CR TPDU received
 cr indicated =   8, {TCI sent to user
 ca sent      =  16, {TCRE received from user, CA TPDU sent
 ca received  =  32, {CA TPDU received
 ca confirmed =  64, {TCC sent to user
 dr sent      = 128, {TDR received from user, DR TPDU sent
 dr received  = 256, {DR TPDU received
 dr indicated = 512  {TDI sent to user

externalstring (*)map  heapstring(string (255)s)
string (*)name  t
  result  == nil if  s=""
  t == string(heapget(length(s)+1))
  t = s
  result  == t
end 

halffn  new tc ref
integer  i
  for  i = 1,1,maxtc cycle 
    result  = i if  tcrefs(i)==nil
  repeat 
  signal  3,4,,"Too many transport connections"
end 

externalrecord (tc f)map  T ALLOCATE TC REF (string (63) LSAP, RSAP)
! Returns a reference to a (new) connection record.
record (itcf)name  tc
record (listf)name  cell
half  lref
  lref = new tc ref
  tc == new(tc)
  tc = 0
  tc_lref = lref
  tc_userpart_lsap == heapstring(lsap)
  tc_userpart_rsap == heapstring(rsap)
  cell == new(cell)
  cell_rec == tc
  cell_prev == nil
  cell_next == tc list
  tc list == cell
  result  == tc_userpart
end 

record (listf)map  validate tc(record (tcf)name  tc)
record (listf)name  c
  c == tc list
  cycle 
    signal  3,4,,"Invalid TC reference supplied" if  c==nil
    result  == c if  c_rec==tc
    c == c_next
  repeat 
end 

routine  move(integer  bytes,bytename  from,to)
label  nothing
  *subq.w #1,bytes
  *bmi nothing
loop: *move.b (a0)+,(a1)+
      *dbra d0,loop
nothing:
end 
 
routine  add parm(byte  code,record (parmf)name  p,record (tpduf)name  t)
bytename  source,dest
integer  size
  source == p_code; source = code
  dest == t_byte(t_li+2)
  size = length(p_string)+2
  move(size,source,dest)
  t_li = t_li+size
end 

externalroutine  T CONNECT REQUEST -
   (record (tc f)name  REF, string (32) DATA)
! Attempt to make a connection to the remote entity indicated by REF_RSAP,
! with the QOS parameters in REF, and with optional DATA as provided.
record (itcf)name  tc
record (tpduf)name  tpdu
record (parmf)parm
integer  sumpos
  tc == validate tc(ref)_rec
  signal  3,4,,"TC already connected" unless  tc_state=0
  tc refs(tc_lref) == tc
  tpdu == new(tpdu)
  tpdu_li = fhp cr
  tpdu_code = cr tpdu
  tpdu_sref = tc_lref
  tpdu_classopt = class4+extendedformats
  unless  tc_userpart_lsap==nil start 
    parm_string = tc_userpart_lsap; add parm(pc cgid,parm,tpdu)
  finish 
  unless  tc_userpart_rsap==nil start 
    parm_string = tc_userpart_rsap; add parm(pc cdid,parm,tpdu)
  finish 
  parm_byte(0) = 1; parm_byte(1) = lmt; add parm(pc size,parm,tpdu)
  parm_byte(0) = 1; parm_byte(1) = 1; add parm(pc ver,parm,tpdu)
  parm_byte(0) = 2; add parm(pc sum,parm,tpdu); sumpos = tpdu_li
  move(length(data),charno(data,1),tpdu_byte(tpdu_li+1)) unless  data=""
  generate sum(tpdu_li,tpdu_li+1+length(data),sumpos)
  tc_state = tc_state!crsent
{now schedule the TPDU for transmission}
end 

externalrecord (tc f)map  T CONNECT INDICATED -
   (string (63) LSAP, integer  WAIT)
! If some other end has attempted to establish a connection with the
! caller, identified as LSAP, a reference to a connection record is
! returned.  If not, NIL is returned if WAIT=0; otherwise the called
! is suspended.
end 

externalroutine  T CONNECT RESPONSE -
   (record (tc f)name  REF, string (32) DATA)
! Either this or T DISCONNECT REQUEST should be called by someone who
! has received a non-NIL result from T CONNECT INDICATED.
end 

externalroutine  T DISCONNECT REQUEST -
   (record (tc f)name  REF, string (43) REASON, string (64) DATA)
! Shut down the connection identified by REF, optionally supplying
! an explanatory reason and data.
end 

externalintegerfn  T CONNECTED -
   (record (tc f)name  REF, string (*)name  REASON, DATA, integer  WAIT)
! If the connection is still being negotiated (the other end has not
! yet responded), then the result is 0 (if WAIT=0, otherwise caller
! is suspended) and REASON and DATA are unaffected.
! If the connection has been established, the result is >0, and DATA
! receives the message supplied at the other end via T CONNECT RESPONSE.
! Otherwise the connection has been shut down, the result is <0, and DATA
! and REASON receive information provided by T DISCONNECT REQUEST.
end 

externalroutine  T EXPEDITED DATA REQUEST -
   (record (tc f)name  REF, string (16) DATA)
! Sends a quickie (if enabled by negotiation).
end 

externalroutine  T DATA REQUEST-
   (record (tc f)name  REF, name  WHERE, integer  SIZE, byte  EOF)
! Passes a TIDU across the interface.  SIZE bytes of data, in store at
! WHERE, are transmitted.  If EOF#0, this constitutes the last TIDU
! making up a TSDU.
end 

externalintegerfn  T DATA INDICATED (record (tc f)name  REF, integer  WAIT)
! If no TSDU has arrived on the connection, the result is 0 (unless
! WAIT#0, in which case the caller is suspended).
! If a DATA unit is available, the result is >0.
! If an EXPEDITED DATA unit is available, or the connection has been
! broken, the result is <0.
end 

externalroutine  T ACCEPT DATA (record (tc f)name  REF, -
   name  WHERE, integername  SIZE, bytename  EOF, integer  WAIT)
! A pending data unit is copied into store at WHERE.  SIZE on entry
! indicates the maximum size of the TIDU the caller is prepared to accept.
! SIZE will be set to the number of bytes actually copied.  This will
! be negative if the connection is broken or an EXPEDITED DATA unit
! is pending, or no data is available and WAIT=0.  EOF is set if this
! was the last TIDU of a TSDU.
end 

externalroutine  T ACCEPT EXPEDITED DATA -
   (record (tc f)name  REF, string (16)name  DATA)
! Should only be called when an expedited data unit is known to be there.
end