{**************************************************************************}
{**                                                                      **}
{**                  SVEN SWOPPING LIBRARY                               **}
{**                                                                      **}
{**                  IAN R GEBBIE  (IRG)                                 **}
{**                                                                      **}
{**************************************************************************}

%include 'SVEN:LAPBINC.PAS'

TYPE            
mode_type = (Disconnected,info_trans,busy);            {Status of library}
frame_type = (information,supervisory,unnumbered,frmr);
frame_info_type = record
   pf_bit : boolean;
   case frame : frame_type of
      information : (n_s : sequence_type;
                     info : information_type);
      supervisory : (sf_function : sf_function_type;
                     address : address_type);
      unnumbered : (uf_function : uf_function_type);
      frmr : (v_r : sequence_type;
              v_s : sequence_type;
              bad_control : frmr_control_octet;
              bad_address : address_type;
              error : frmr_error_type);
   end;
                              
VAR
if_ptr,                                           {points to IF buffer}
last_value_of_nr,                                 {last value of N(R) received}
timer_t1,                                            {internal timer_t1}
buff_first_ptr,                                   {Frame buffer pointer}
buff_last_ptr : [static] integer;                 {  "     "       "   }
current_mode : [static] mode_type;                {current mode of library}
ack_rec,                                          {Has frame been ack ?}
text_halted,                                      {Is it possible to trans text?}
timer_t1_running,                                    {Is timer_t1 running?}
frame_was_info : [static] boolean;                {Was last frame an IF?}
n_sent,n_rec,v_sent,v_rec : [static] sequence_type;  
buffer : [static] array[0..7] of frame_info_type;    {frame buffer}
if_buff : [static] array[0..7] of information_type;  {I-Frame buffer}
{--------------------------------------------------------------------}
{       Increments by mod 8                                          }
{--------------------------------------------------------------------}

FUNCTION succmod8 (i : integer) : integer;      
begin
  succmod8 := succ(i) mod 8 ;
end;

{--------------------------------------------------------------------}
{       Decrements by mod 8                                          }
{--------------------------------------------------------------------}

FUNCTION predmod8 (i : integer) : integer;      
begin
  predmod8 := pred(i) mod 8 ;
end;

{--------------------------------------------------------------------}
{       Initialises the variables .                                  }
{--------------------------------------------------------------------}

PROCEDURE initialise_vars;                     
begin                                          
                                               
  timer_t1 := 0;
  n_sent := 0;
  n_rec := 0;
  v_sent := 0;
  v_rec := 0;
  if_ptr:=0;
  buff_first_ptr := 0;
  buff_last_ptr := 0;
  ack_rec := true;
  frame_was_info := false;
  last_value_of_nr := 0;
  text_halted := false;
end;

{--------------------------------------------------------------------}
{       Start timer running if not already running.                  }
{--------------------------------------------------------------------}

PROCEDURE start_timer_t1;                      
begin                                          
  if timer_t1_running = false then
  begin
    timer_t1 := 0;
    timer_t1_running := true;
  end;
end;

{--------------------------------------------------------------------}
{       Stop timer running                                           }
{--------------------------------------------------------------------}

PROCEDURE stop_timer_t1;                             {Stop the timer_t1}
begin
  timer_t1_running := false;
end;

{--------------------------------------------------------------------}
{       Attempt to transmit an unnumbered frame                      }
{--------------------------------------------------------------------}

PROCEDURE try_to_trans_UF(fnction : uf_function_type ;
                          pf_bt : boolean);
begin
    transmit_uf(fnction,pf_bt);
end;

{--------------------------------------------------------------------}
{       Attempt to transmit I-frame if previous one acknowledged     }
{--------------------------------------------------------------------}

PROCEDURE try_to_trans_IF(pf_bt : boolean;
                          ns : sequence_type;
                          infomtn : information_type) ;
begin
    if ack_rec then begin
      transmit_if(pf_bt,v_rec,ns,infomtn);
      frame_was_info := true;
      ack_rec := false;
    end;
end;

{--------------------------------------------------------------------}
{       Try to transmit a supervisory frame                          }
{--------------------------------------------------------------------}

PROCEDURE try_to_trans_SF(fnction : sf_function_type;
                          addrss : address_type;
                          pf_bt : boolean;
                          nr : sequence_type) ;
begin
    transmit_sf(fnction,addrss,pf_bt,nr);
end;

{--------------------------------------------------------------------}
{       Try to transmit a frame reject.                              }
{--------------------------------------------------------------------}

PROCEDURE try_to_trans_FRMR(pf_bit : boolean;
                            vr : sequence_type;
                            vs : sequence_type;
                            bad_control : frmr_control_octet;
                            bad_address : address_type;
                            error : frmr_error_type);
begin
    transmit_frmr(pf_bit,vr,vs,bad_control,bad_address,error);
end;

{--------------------------------------------------------------------}
{         Start link up.                                             }
{--------------------------------------------------------------------}

PROCEDURE reset_link;   
begin
  initialise_vars;
  link_status(link_down);
  current_mode := disconnected;
  start_timer_t1;
  try_to_trans_UF(SABM,true);
end;

{--------------------------------------------------------------------}
{         Used to acknowlede the transmission of a frame.            }
{         Also prevents more frames than the sliding window allows   }
{--------------------------------------------------------------------}

PROCEDURE frame_transmitted;
GLOBAL;
begin
  stop_timer_t1;
  if frame_was_info and (current_mode=info_trans)then
  begin
    ack_rec := true;
    if ((last_value_of_nr+lapb_k)mod 8)=v_sent then
    begin
      text_halted := true;
    end;
    information_output;
  end;
end;

{--------------------------------------------------------------------}
{         Output information to the text level. Frame is buffered    }
{         should it neeed to be retransmitted.                       }
{--------------------------------------------------------------------}

PROCEDURE output_information(information : information_type);
GLOBAL;
begin
  if_buff[if_ptr] := information;               {Buffer i-frame}
  if_ptr := succmod8(if_ptr);
  if text_halted = false then begin
    try_to_trans_IF(false,v_sent,information);
    v_sent := succmod8(v_sent);
  end;
end;

{--------------------------------------------------------------------}

PROCEDURE information_input;
GLOBAL;
begin
end;

{--------------------------------------------------------------------}

PROCEDURE receive_bad(control : frmr_control_octet ;
                      address : address_type;
                      error : frmr_error_type) ;
GLOBAL;
begin
end;

{--------------------------------------------------------------------}
{         Receive an unumbered frame from the physical level.        }
{         Used to set up link and .                                  }
{--------------------------------------------------------------------}

PROCEDURE receive_uf(uf_function : uf_function_type;
                     pf_bit : boolean) ;
GLOBAL;
begin
  case current_mode of
  disconnected :
    case uf_function of
      DISC : begin                                     {Ack disconnection}
               if pf_bit then try_to_trans_uf(dm,true);
             end;
      DM : begin                                       {Reset link request}
             link_status(link_down);
             reset_link;
           end;
      SABM : begin                                     {Acknowledge link set up}
                 initialise_vars;                      {request }
                 try_to_trans_UF(ua,pf_bit);
                 link_status(link_up);
                 current_mode := info_trans;
             end;
      UA : begin                                       {Receive ack of link set up}
             stop_timer_t1;
             initialise_vars;
             link_status(link_up);
             current_mode := info_trans;
           end;
    end;
  info_trans : 
    case uf_function of
      DISC : begin                                           
             end;
      DM : begin
             reset_link;
             link_status(link_down);
           end;
      SABM : begin
             end;
      UA : begin
           end; 
    end;
  busy :
   begin
   end;
  end;
  frame_received;
end;

{--------------------------------------------------------------------}

PROCEDURE receive_frmr(pf_bit : boolean;
                       vr : sequence_type;
                       vs : sequence_type;
                       bad_control : frmr_control_octet;
                       bad_address : address_type;
                       error : frmr_error_type);
GLOBAL;
begin
  frame_received;
end;

{--------------------------------------------------------------------}
{        Receives a sf_frame from the physical level. If an RR is    }
{        received then releases text if halted.                      }
{--------------------------------------------------------------------}

PROCEDURE receive_sf(sf_funtion : sf_function_type;
                     address : address_type;
                     pf_bit : boolean;
                     nr : sequence_type;
                     control : frmr_control_octet);
GLOBAL;
begin
  case sf_funtion of
    RR : begin
           text_halted := false;
           last_value_of_nr := nr;
         end;
    RNR : begin
          end;
    REJ : begin
          end;
  end;
  frame_received;
end;

{--------------------------------------------------------------------}
{        Receives a frame from the physical level. Releases the      }
{        transmission if text was halted (since window full)         }
{--------------------------------------------------------------------}

PROCEDURE receive_if(pf_bit : boolean;
                     nr : sequence_type;
                     ns : sequence_type;
                     control : frmr_control_octet;
                     information : information_type);
GLOBAL;
begin
  case current_mode of
    disconnected : if pf_bit then try_to_trans_UF(dm,pf_bit);
    info_trans : begin
                   stop_timer_t1;
                   if text_halted then
                   begin
                     frame_was_info := false;
                     text_halted := false;
                     try_to_trans_SF(RR,response,pf_bit,nr);
                   end;
                   input_information(information);
                   last_value_of_nr := nr;
                   v_rec := succmod8(v_rec);
                 end;
     busy : begin
            end;
  end;
  frame_received;
end;

{--------------------------------------------------------------------}
{        Increments the timer once a second.                         }
{        Should also be used to see if any part is timed out.        }
{--------------------------------------------------------------------}

PROCEDURE clock_tick;
GLOBAL;
begin
  if timer_t1_running then timer_t1 := succ(timer_t1);
  if timer_t1 = lapb_t2 then begin
    try_to_trans_SF(RR,response,false,last_value_of_nr);
    timer_t1:=0;
    timer_t1_running:=true;
  end;
  if timer_t1 = lapb_t1 then begin
  case current_mode of
    disconnected:begin
                   start_timer_t1;
                   try_to_trans_UF(sabm,true);
                 end;
    info_trans:begin
              end;
    busy:begin
         end;  
  end;
  end;
end;

{--------------------------------------------------------------------}
{        This routine is only ever called once, at the very beginning}
{        of any transaction.This routine is then used to set up the  }
{        variables.                                                  }
{--------------------------------------------------------------------}

PROCEDURE text_status(status : text_status_type) ;
GLOBAL;
begin
    reset_link;
end;
