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

⟦15a76871b⟧ TextFileVerbose

    Length: 108288 (0x1a700)
    Types: TextFileVerbose
    Names: »sncp«

Derivation

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

TextFileVerbose

process ncp(
var sys_vector: system_vector; (* pointers to input semaphores of system processes *)
var ncp_sem: ! tap_pointer;    (* ncp input semaphores *)
var sc_sem: ! tap_pointer;     (* sc input semaphore *)
var timeout_sem: ! tap_pointer;(* timeout input semaphore *)
ncp_ident: ! integer);         (* ident of the ncp in supervsor message *)

(*******************************************************************)
(*                                                                 *)
(*                             ncp                                 *)
(*                                                                 *)
(* description:                                                    *)
(* the ncp (network control probe) performs the routing of         *)
(* supervisor messages from the ncc (network control center) to    *)
(* the lcp (local control probe).                                  *)
(*                                                                 *)
(*   date    init   changes                                        *)
(*  -------------------------------------------------------------  *)
(*  810218   chh    first released version                         *)
(*  810302   chh    sp_head_lgt = 17                               *)
(*  810423   chh    lcp function: set time inserted.               *)
(*                  timeout's date and time used.                  *)
(*  810602   chh    changes according to the sc interface.         *)
(*                                                                 *)
(*******************************************************************)

const

(**********************************)
(****   configuration values   ****)
(**********************************)

version = "vers.810602/";

ncc_port = 1;            (* sc port number for ncc *)
ncp_port = 2;            (* sc port number for ncp *)

max_lcp = 15;            (* max. no. of connected lcp's *)

max_repeat = 4;          (* max. no. of repeatable functions *)

nr_event_buf = 3;        (* no. of event buffers *)

nr_sup_buf = 5;          (* no of supervisor message buffers *)

sc_buf_size = 100;       (* no of bytes in a sc buffer *)

rep_buf_size = 100;      (* no of bytes in a repeat buffer *)

sc_multi_buf = 2;        (* max no of input buffers hanging in sc *)


(****************************)
(****   default values   ****)
(****************************)


(***************************)
(****   common values   ****)
(***************************)

no_wait = 0;
wait_forever = -1;
first_index = 6 + alfalength;
last_index = first_index + (80 - 1);


(***********************)
(****   u1 values   ****)
(***********************)

sc_in = 8 + 1;           (* input buffer to sc *)
sc_out = 8 + 2;          (* output buffer to sc *)

get_date_time = 8 + 1;   (* get date and time from timeout *)
set_date_time = 8 + 2;   (* set date and time in timeout *)


(***********************)
(****   u2 values   ****)
(***********************)

timeout_ok = 1;



(*********************************)
(****   u4 values (streams)   ****)
(*********************************)

event_str = 1;           (* event message stream *)
lcp_msg_str = 2;         (* lcp message stream *)
sc_input_str = 3;        (* sc input stream *)
sc_output_str = 4;       (* sc output stream *)
sc_ev_out_str = 5;       (* sc output stream for events *)
time_out_str = 6;        (* time out stream *)
int_lcp_str = 7;         (* internal lcp stream *)


(***********************)
(****   sc values   ****)
(***********************)

sc_stack = 1;                            (* sc stack depth *)
nuid_lgt = 15;                           (* max. length of nuid *)
ack_req_fac = 1;                         (* ack req facility *)
sc_type_lgt = 4 + nuid_lgt;              (* length of sc_type *)
sc_in_last = 7;                          (* last in sc input *)
sc_out_last = sc_in_last + sc_type_lgt;  (* last in sc output *)


(***************************************)
(****   supervisor message values   ****)
(***************************************)

sp_data_size = sup_buf_size - sp_head_lgt - 6;   (* max length of supervisor data *)
rep_data_size = rep_buf_size - sp_head_lgt - 6;  (* max length of repeat data *)
ind_addr_size = 6;               (* length of indirect address field - sc_id_lgt *)
rep_time_lgt = 8;                (* no. of significant digits in repeat start time *)
rep_data_lgt = rep_time_lgt div 2 + 2; (* length of repeat data field *)
rep_func_lgt = 4;                (* length of repeatable function record *)


(**************************)
(****   event values   ****)
(**************************)

ev_connect = 20 + 3;     (* event type = lcp connected *)
ev_conn_lgt = 2;         (* record length for lcp connected *)

ev_disconnect = 24 + 3;  (* event type = lcp disconnected *)
ev_disc_lgt = 4;         (* record length for lcp disconnected *)
ev_disc_cause = 1;       (* disconnect cause = lcp disconnect message *)

ev_collision = 44 + 3;   (* event type = lcp connection collision *)
ev_coll_lgt = 2;         (* record length for lcp connection collision *)

ev_lack_res = 8 + 3;     (* event type = lack of resources *)
ev_lack_lgt = 2;         (* record length for lack of resources *)

ev_lost = 252 + 3;       (* event type = events lost *)
ev_lost_lgt = 2;         (* record length for events lost *)


(******************************)
(****   lcp table values   ****)
(******************************)

free_entry = -1;         (* specifies that an entry in lcp table is free *)
ncp_index = 0;           (* ncp index in lcp table *)
entry_not_found = -1;    (* return parameter from the procedure search_table *)


(**********************************)
(****   lcp operation values   ****)
(**********************************)

(* modification in lcp_oper, control *)
set_event_mask = 1;      (* set event mask for the ncp *)
set_time = 61;           (* set date and time *)
set_event_addr = 62;     (* set event address for a specified lcp *)
set_except_addr = 63;    (* set exception return address for all supervisor messages *)

(* modification in lcp_oper, sense *)
get_event_mask = 1;      (* get event mask for the ncp *)
get_conn_lcp = 2;        (* get all connected lcp's *)
get_event_addr = 62;     (* get event address for a specified lcp *)
get_except_addr = 63;    (* get exception return address for all supervisor messages *)
get_rep_func = 5;        (* get repeatable functions *)

(* modification in lcp_oper, get statistics *)
get_lcp_stat = 1;        (* get lcp statistics for specified lcp's *)

(* other values *)
reclgt_ev_addr = 4 + sc_type_lgt;   (* length of event address record *)
lcp_stat_lgt = 14;       (* length of an lcp statistical record *)
ncp_stat_lgt = 12;       (* length of an ncp statistical record *)


type

(***************************)
(****   general types   ****)
(***************************)

alfa20 = array(1..20) of char;


(************************************)
(****   sc communication types   ****)
(************************************)

nuid_type = packed array(1..nuid_lgt) of byte;

sc_comm_type = record
port_no: integer;
ack_req: boolean;
nuid_signf: byte;
nuid: nuid_type;
end;

sc_in_type = record
first, last, next: integer;
local_port: integer;
sen_sc: sc_comm_type;
end;

sc_out_type = record
first, last, next: integer;
local_port: integer;
rec_sc: sc_comm_type;
end;


(**************************************)
(****   supervisor message types   ****)
(**************************************)

sup_mess_type = packed record
first, last, next: integer;
sp_head: sp_head_type;
end;


(***********************************)
(****   supervisor data types   ****)
(***********************************)

sc_data_type = packed record
port_no: integer;
facility: byte;
nuid_signf: byte;
nuid: nuid_type;
end;

ind_addr_data = packed record
head: sup_mess_type;
sc_addr: sc_data_type;
lcp_ident: lcp_ident_type;
end;

rep_time_type = packed array(1..rep_time_lgt) of time_digit;

rep_data_type = packed array(1..rep_data_size) of byte;

repeat_data = packed record
head: sup_mess_type;
ticks: integer;
start_time: rep_time_type;
sp_data: rep_data_type;
end;

sup_data = packed record
head: sup_mess_type;
sp_data: packed array(1..sp_data_size) of byte;
end;

rep_sup_data = packed record
head: sup_mess_type;
sp_data: rep_data_type;
end;

ev_common_data = packed record
head: sup_mess_type;
ev_type: byte;
bytecount: byte;
end;

ev_conn_data = packed record
common: ev_common_data;
lcp_ident: lcp_ident_type;
end;

ev_lack_data = ev_conn_data;

ev_coll_data = ev_conn_data;

ev_disc_data = packed record
common: ev_common_data;
lcp_ident: lcp_ident_type;
cause: integer;
end;

event_data_type = array(1..5) of integer;

ev_lost_data = packed record
common: ev_common_data;
lost_events: integer;
ev_type: byte;
bytecount: byte;
event_data: event_data_type;
end;


(*************************)
(****   event types   ****)
(*************************)

ev_bit_mask = (prod_stat,
?, ?, ?, ?, ?,
lack_of_res, ?, ?, ?, ?,
connection,
disconnection,
collision, ?, ?);

state_type = (unused, used);

wait_ev_type = record
state: state_type;
lost_events: integer;
ev_type: byte;
bytecount: byte;
event_data: event_data_type;
end;


(*****************************)
(****   lcp table types   ****)
(*****************************)

ext_sc_type = record
sc_addr: sc_comm_type;
rec_ident: integer;
end;

connect_type = (disconn, conn);

msg_pend_type = (pending, not_pending);

lcp_state = packed record
connect: connect_type;
msg_pending: msg_pend_type;
end;

lcp_stat_type = record
messages: integer;
events: integer;
pending_msg: integer;
lost_msg: integer;
end;

rep_stat_type = record
repeat_opers: integer;
lost_repeat: integer;
end;

lcp_table_elem = record
lcp_ident: integer;
wait_msg_sem: semaphore;
pending_sem: semaphore;
event_sc_addr: ext_sc_type;
state: lcp_state;
lcp_stat: lcp_stat_type;
repeat_stat: rep_stat_type;
end;

lcp_table_type = array(0..max_lcp) of lcp_table_elem;

lcp_index_elem = record
key: integer;
index: integer;
end;

lcp_index_type = array(0..max_lcp) of lcp_index_elem;


(********************************)
(****   repeat table types   ****)
(********************************)

repeat_elem = record
state: state_type;
msg: reference;
timeout_ref: reference;
ticks: integer;
end;

rep_table_type = array(1..max_repeat) of repeat_elem;


(*********************************)
(****   lcp operation types   ****)
(*********************************)

ext_sc_data_type = packed record
sc_addr: sc_data_type;
rec_ident: lcp_ident_type;
end;

ev_mask_data = packed record
head: sup_mess_type;
update_mask: set of ev_bit_mask;
ev_mask: set of ev_bit_mask;
end;

ev_addr_record = packed record
lcp_ident: lcp_ident_type;
ev_sc_addr: ext_sc_data_type;
end;

exc_addr_data = packed record
head: sup_mess_type;
exc_sc_addr: ext_sc_data_type;
end;

conn_lcp_data = packed record
head: sup_mess_type;
lcp_ident: array(0..max_lcp) of integer;
end;

rep_func_elem = packed record
lcp_ident: integer;
seq_no: byte;
lcp_oper: lcp_oper_type;
end;

rep_func_data = packed record
head: sup_mess_type;
rep_data: array(1..max_repeat) of rep_func_elem;
end;

lcp_stat_data = conn_lcp_data;

ncp_stat_type = packed record
lcp_stat: lcp_stat_type;
repeat_stat: rep_stat_type;
end;

lcp_stat_elem = packed record
lcp_ident: integer;
lcp_stat: lcp_stat_type;
repeat_stat: rep_stat_type;
end;

stat_data = packed record
head: sup_mess_type;
ncp_stat: ncp_stat_type;
lcp_statis: array(0..max_lcp) of lcp_stat_elem;
end;


(*************************)
(****   other types   ****)
(*************************)

oper_type = record
first, last, next: integer;
name: alfa;
data: array(first_index..last_index) of char;
end;


timeout_type = record
index,
count,
object: integer;
end;

object_type = record
object: integer;
end;

date_time_type = record
first, last, next: integer;
year: array(1..2) of byte;
dummy1: byte;
month: array(1..2) of byte;
dummy2: byte;
day: array(1..2) of byte;
dummy3: array(1..2) of byte;
hour: array(1..2) of byte;
dummy4: byte;
minute: array(1..2) of byte;
dummy5: byte;
second: array(1..2) of byte;
end;


const

(****************************)
(****   default values   ****)
(****************************)

event_addr = ext_sc_type(
sc_comm_type(
ncc_port,    (* event port number *)
true,        (* event facilities *)
15,          (* event nuid length *)
nuid_type(
15 *** 0)),  (* event nuid *)
0);          (* event receiver_id *)

exception_addr = event_addr;


(**************************)
(****   other values   ****)
(**************************)

time_0 = rep_time_type(rep_time_lgt *** 0);
sp_type_0 = sp_type_type(req, mess, no_ncp_cntr, start_rep, no_reject, no_reset_stat, ?, ?);


var

(************************)
(****   semaphores   ****)
(************************)

wait_ev_buf_sem: semaphore;
oper_sem: semaphore;
help_sem: semaphore;


(************************)
(****   references   ****)
(************************)

msg: reference;
event_ref: reference;
msg_ref: reference;
sc_msg: reference;
oper_ref: reference;
work_ref: reference;


(*******************)
(****   pools   ****)
(*******************)

event_buf_pool: pool nr_event_buf of packed array(1..event_buf_size) of byte;
sup_mess_pool: pool nr_sup_buf of sup_data;
sc_mess_pool: pool nr_sup_buf + nr_event_buf + max_repeat of packed array(1..sc_buf_size) of byte;
repeat_pool: pool max_repeat of packed array(1..rep_buf_size) of byte;
timeout_pool: pool 2 * max_repeat + 1 of timeout_type;
oper_pool: pool 1 of oper_type;
work_pool: pool 1 of sup_data;


(****************************)
(****   pool variables   ****)
(****************************)

act_nr_event_buf: integer:= nr_event_buf;
act_nr_sup_buf: integer:= nr_sup_buf;


(****************************************)
(****   sc communication variables   ****)
(****************************************)

act_sc_input: integer:= 0;     (* actual no of input buffers in sc *)

except_addr: ext_sc_type:= exception_addr;


(******************************************)
(****   supervisor message variables   ****)
(******************************************)

act_seq_no: integer:= 0;
ncp_contr: ncp_cntr_type;
repeat_func: rep_func_type;
stat_control: stat_cntr_type;
basic_oper: basic_type;
modif_oper: integer;
sup_status: set of sp_status_bit;
sc_data_var: sc_data_type;
ind_addr_lgt: integer;
ind_rec: boolean;
ind_sen: boolean;


(*****************************)
(****   event variables   ****)
(*****************************)

waiting_event: wait_ev_type:= wait_ev_type(unused, 0, 0, 0, event_data_type(5 *** 0));
event_mask: set of ev_bit_mask:= (.prod_stat, lack_of_res, connection, disconnection, collision.);
full_mask: set of ev_bit_mask:= (.prod_stat, lack_of_res, connection, disconnection, collision.);


(*********************************)
(****   lcp table variables   ****)
(*********************************)

lcp_table: lcp_table_type:=
lcp_table_type(
lcp_table_elem(
?,                     (* ident of the lcp in the ncp *)
?,                     (* semaphore for wait message *)
?,                     (* semaphore for pending messages *)
event_addr,            (* address of event reporting *)
lcp_state(             (* actual state of the lcp *)
conn,                  (* ncp connected *)
not_pending),          (* no message pending *)
lcp_stat_type(         (* lcp statistics *)
0,                     (* messages *)
0,                     (* events *)
0,                     (* pending messages *)
0),                    (* lost messages *)
rep_stat_type(         (* repeat statistics *)
0,                     (* repeat operations *)
0)),                   (* lost repeat operations *)
max_lcp ***            (* initialize rest of lcp table *)
lcp_table_elem(
free_entry,            (* specifies that the entry is free *)
?,                     (* semaphore for wait message *)
?,                     (* semaphore for pending messages *)
event_addr,            (* address of event reporting *)
lcp_state(             (* actual state of the lcp *)
disconn,               (* disconnected *)
not_pending),          (* no message pending *)
lcp_stat_type(         (* lcp statistics *)
0,                     (* messages *)
0,                     (* events *)
0,                     (* pending messages *)
0),                    (* lost messages *)
rep_stat_type(         (* repeat statistics *)
0,                     (* repeat operations *)
0)));                  (* lost repeat operations *)

lcp_index_table: lcp_index_type:=
lcp_index_type(
lcp_index_elem(
?,0),                  (* first entry is ncp *)
max_lcp ***            (* initialize rest of table *)
lcp_index_elem(
free_entry, ?));       (* free entries *)

index: integer;           (* actual index in lcp_table *)
act_lcp_ident: integer;   (* actual lcp ident *)
first_free: integer:= 1;  (* points to the first free entry in lcp_table *)
act_nr_lcp: integer:= 0;  (* actual number of connected lcp's *)


(************************************)
(****   repeat table variables   ****)
(************************************)

repeat_table: rep_table_type:=
rep_table_type(max_repeat *** repeat_elem(unused, ?, ?, ?));

rep_index: integer;
first_free_rep: integer:= 1;


(*****************************)
(****   other variables   ****)
(*****************************)

name: alfa;
z: zone;
continue: boolean;
count: integer;
index_to, index_from: integer;
help_int: integer;
ncp_stat: ncp_stat_type:= ncp_stat_type(
lcp_stat_type(0, 0, 0, 0),
rep_stat_type(0, 0));



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

procedure timerbook(var local_msg: reference;
var local_timer_msg: reference;
local_ticks: ! integer;
local_obj: ! integer;
var local_timeout_sem: semaphore;
var local_answer: semaphore);
external;


procedure timerupdate(var local_msg: reference;
local_ticks: ! integer;
var local_timeout_sem: semaphore;
var local_answer: semaphore);
external;


procedure outchar(ch: char);

(*********************************************************************)
(*                                                                   *)
(*                            outchar                                *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   ch: the character that is to be put into the operator output    *)
(*     buffer (call parameter).                                      *)
(* call of other procedures: none.                                   *)
(* use of global variables: oper_ref                                 *)
(* waiting points: none.                                             *)
(* function: the procedure puts the character in ch into the         *)
(*   operator output buffer.                                         *)
(*                                                                   *)
(*********************************************************************)

begin
lock oper_ref as opdata: oper_type do
with opdata do
begin
last:= last + 1;
data(last):= ch;
end;     (* with opdata and lock oper_ref *)
end;     (* outchar *)


procedure outstring20(local_text: alfa20; local_lgt: ! integer);

(*******************************************************************)
(*                                                                 *)
(*                             outstring20                         *)
(*                                                                 *)
(* internal ncp procedure.                                         *)
(* parameters:                                                     *)
(*   local_text: contains the text string that is to be put into   *)
(*     the operator output buffer (call parameter).                *)
(*   local_lgt: the number of characters that is put into the      *)
(*     operator output buffer (call parameter).                    *)
(* call of other procedures: outchar.                              *)
(* use of global variables: none.                                  *)
(* waiting points: none.                                           *)
(* function: the procedure puts the specified number of characters *)
(*   into the operator output buffer.                              *)
(*                                                                 *)
(*******************************************************************)

var
i: integer;

begin
for i:= 1 to local_lgt do
outchar(local_text(i));
end;     (* outstring20 *)


procedure outinteger(int: integer);

(*******************************************************************)
(*                                                                 *)
(*                             outinteger                          *)
(*                                                                 *)
(* internal ncp procedure.                                         *)
(* parameters:                                                     *)
(*   int: an integer that is converted to a decimal ascii string.  *)
(*     at return it is undefined (call parameter).                 *)
(* call of other procedures: outchar.                              *)
(* use of global variables: none.                                  *)
(* waiting points: none.                                           *)
(* function: the procedure converts an integer to a decimal ascii  *)
(*   string of length 6.                                           *)
(*                                                                 *)
(*******************************************************************)

const
maxpos = 6;

var
i: integer;
digits: array(1..maxpos) of char;

begin
for i:= 1 to maxpos do
digits(i):= sp;
i:= maxpos;
repeat
digits(i):= chr(abs(int mod 10) + ord("0"));
int:= int div 10;
i:= i - 1;
until (i = 1) or (int = 0);
for i:= 1 to maxpos do
outchar(digits(i));
end;     (* outinteger *)


procedure ncp_error(local_index, local_error: integer);

(********************************************************************)
(*                                                                  *)
(*                           ncp_error                              *)
(*                                                                  *)
(* internal ncp procedure.                                          *)
(* parameters:                                                      *)
(*   local_index: index in the lcp_table (call parameter).          *)
(*   local_error: an error number that indicates, where in the ncp  *)
(*     module the error has occured (call parameter).               *)
(* call of other procedures: outchar, outinteger, outstring20.      *)
(* use of global variables: oper_ref, oper_sem.                     *)
(* waiting points: yes.                                             *)
(* function: the procedure writes a short error message on the      *)
(*   operator console.                                              *)
(*                                                                  *)
(********************************************************************)

const
text1 = "*** ncp error  lcp =";
textlgt1 = 20;
text2 = " none               ";
textlgt2 = 6;
text3 = "    error no. =     ";
textlgt3 = 16;
text4 = " ncp                ";
textlgt4 = 6;
ncp_name = "ncp         ";

var
i: integer;
text: alfa20;

begin
wait(oper_ref, oper_sem);
oper_ref^.u1:= 2;
oper_ref^.u2:= 7;
lock oper_ref as opdata: oper_type do
with opdata do
begin
first:= first_index;
name:= ncp_name;
last:= first_index - 1;
end;     (* with opdata and lock oper_ref *)
outstring20(text1, textlgt1);
case local_index of
ncp_index:
outstring20(text4, textlgt4);
entry_not_found:
outstring20(text2, textlgt2);
otherwise     (* not ncp_index or entry_not_found *)
if local_index <= max_lcp then
outinteger(lcp_table(local_index).lcp_ident)
else     (* local_index > max_lcp *)
outstring20(text2, textlgt2);
end;     (* case local_index *)
outstring20(text3, textlgt3);
outinteger(local_error);
outchar(nl);
signal(oper_ref, sys_vector(operatorsem)^);
end;     (* ncp_error *)


procedure get_event_buf(rec_ident, waittime: integer;
var event_buf: reference);

(*******************************************************************)
(*                                                                 *)
(*                       get_event_buf                             *)
(*                                                                 *)
(* internal ncp procedure                                          *)
(* parameters:                                                     *)
(*   rec_ident: will be placed in the receiver_id field in the     *)
(*     supervisor head in the event buffer (call parameter).       *)
(*   waittime: specifies if a buffer should be waited for or not   *)
(*     if there are no free buffers (call parameter).              *)
(*   event_buf: if there is a free event buffer, then this         *)
(*     parameter will contain the reference to the buffer (return  *)
(*     parameter).                                                 *)
(* call of other procedures: none.                                 *)
(* use of global variables: act_nr_event_buf, event_buf_pool,      *)
(*   ncp_sem, act_seq_no, msg, wait_ev_buf_sem.                    *)
(* waiting points: none.                                           *)
(* function: if there are any free event buffers, then event_buf   *)
(*   will point to this buffer. the event buffer, including the    *)
(*   u-fields, are fully initialized.                              *)
(*   if there are no free buffers then the action depends on       *)
(*   waittime.                                                     *)
(*   if waittime = no_wait then the procedure returns with         *)
(*   event_buf = nil.                                              *)
(*   if waittime = wait_forever then msg will be signalled to      *)
(*   the semaphore: wait_ev_buf_sem, and the procedure returns     *)
(*   with event_buf = nil.                                         *)
(*                                                                 *)
(*******************************************************************)

begin
if act_nr_event_buf > 0 then

(*---------------------------*)
(*     free event buffer     *)
(*---------------------------*)
begin
act_nr_event_buf:= act_nr_event_buf - 1;
alloc(event_buf, event_buf_pool, ncp_sem.s^);
lock event_buf as data: sup_mess_type do
with data do
begin     (* initialize the event buffer *)
first:= 6;
last:= event_buf_size - 1;
next:= 6;
with sp_head do
begin
receiver_id.i:= 0;
receiver_id.id:= rec_ident;
sender_id.i:= 0;
seq_no:= act_seq_no;
act_seq_no:= (act_seq_no + 1) mod 256;
sp_type:= sp_type_0;
sp_type.mess_ev:= event;
lcp_oper.modif:= 0;
lcp_oper.basic:= lcp_event;
status:= (..);
bytecount:= 0;
end;     (* with sp_head *)
end;     (* with data and lock *)
event_buf^.u4:= event_str;
if rec_ident = ncp_ident then
begin
event_buf^.u1:= req_event_buf + 3;
event_buf^.u2:= ok;
event_buf^.u3:= ncp_index;
end     (* if rec_ident = ncp_ident *)
else     (* rec_ident <> ncp_ident *)
begin
event_buf^.u1:= msg^.u1 + 3;
event_buf^.u2:= message;
event_buf^.u3:= msg^.u3;
end;     (* else rec_ident <> ncp_ident *)
end      (* if act_nr_event_buf *)
else     (* act_nr_event_buf <= 0 *)

(*------------------------------*)
(*     no free event buffer     *)
(*------------------------------*)
begin
case waittime of
no_wait:     (* do not wait for a free buffer *)
if rec_ident <> ncp_ident then
begin
msg^.u2:= busy;
return(msg);
end;     (* if rec_ident <> ncp_ident *)
wait_forever:     (* wait for a free buffer *)
if rec_ident <> ncp_ident then
signal(msg, wait_ev_buf_sem);
otherwise
end;     (* case waittime *)
end;     (* else act_nr_event_buf *)
end;     (* get_event_buf *)


procedure send_event( event_type: integer);

(**********************************************************************)
(*                                                                    *)
(*                         send_event                                 *)
(*                                                                    *)
(* internal ncp procedure                                             *)
(* parameters:                                                        *)
(*   event_type: specifies the event type and thereby the record      *)
(*               format (call parameter).                             *)
(* call of other procedures: get_event_buf.                           *)
(* use of global variables: event_ref, msg, waiting_event,            *)
(*   act_lcp_ident.                                                   *)
(* waiting points: none.                                              *)
(* function: if there are any free event buffers, then this procedure *)
(*   will create an event report and signal this to the ncp_sem       *)
(*   if there are no free event buffers, then it will either save the *)
(*   event report in the variable: waiting_event or, if there is      *)
(*   already one saved, then it will increase the variable:           *)
(*   waiting_event.lost_events.                                       *)
(*                                                                    *)
(**********************************************************************)

begin
get_event_buf(ncp_ident, no_wait, event_ref);
if not nil(event_ref) then

(*---------------------------*)
(*     free event buffer     *)
(*---------------------------*)
begin
case event_type of
ev_lack_res, ev_connect, ev_collision:
lock event_ref as data: ev_conn_data do
with data do
begin
common.head.sp_head.bytecount:= 2 + ev_conn_lgt;
common.bytecount:= ev_conn_lgt;
lcp_ident.i:= 0;
lcp_ident.id:= act_lcp_ident;
end;     (* with data and lock event_ref *)
ev_disconnect:
lock event_ref as data: ev_disc_data do
with data do
begin
common.head.sp_head.bytecount:= 2 + ev_disc_lgt;
common.bytecount:= ev_disc_lgt;
lcp_ident.i:= 0;
lcp_ident.id:= act_lcp_ident;
cause:= ev_disc_cause;
end;     (* with data and lock event_ref *)
ev_lost:
begin
lock event_ref as data: ev_lost_data do
with data do
begin
common.bytecount:= ev_lost_lgt;
lost_events:= waiting_event.lost_events;
ev_type:= waiting_event.ev_type;
bytecount:= waiting_event.bytecount;
event_data:= waiting_event.event_data;
common.head.sp_head.bytecount:= 4 + common.bytecount + bytecount;
end;     (* with data and lock event_ref *)
waiting_event.state:= unused;
end;     (* ev_lost *)
otherwise
end;     (* case event_type *)
lock event_ref as data: ev_common_data do
with data do
begin
head.last:= 5 + sp_head_lgt + head.sp_head.bytecount;
ev_type:= event_type;
end;     (* with data and lock event_ref *)
return(event_ref);
end     (* if not nil(event_ref) *)
else     (* nil(event_ref) *)

(*------------------------------*)
(*     no free event buffer     *)
(*------------------------------*)
begin
case waiting_event.state of
unused:
with waiting_event do
begin
state:= used;
lost_events:= 0;
ev_type:= event_type;
case event_type of
ev_lack_res, ev_connect, ev_collision:
begin
bytecount:= ev_conn_lgt;
event_data(1):= act_lcp_ident;
end;     (* ev_connect, ev_regret *)
ev_disconnect:
begin
bytecount:= ev_disc_lgt;
event_data(1):= act_lcp_ident;
event_data(2):= ev_disc_cause;
end;     (* ev_disconnect *)
otherwise
end;     (* case event_type *)
end;     (* with waiting_event *)
used:
waiting_event.lost_events:=waiting_event.lost_events + 1;
end;     (* case waiting_event.state *)
end;     (* else nil(event_ref) *)
end;     (* send_event *)


function check_index(local_index: ! integer): boolean;

(**********************************************************************)
(*                                                                    *)
(*                           check_index                              *)
(*                                                                    *)
(* internal ncp function.                                             *)
(* parameters:                                                        *)
(*   local_index: index in the lcp_table (call parameter).            *)
(* call of other procedures: none.                                    *)
(* use of global variables: lcp_table.                                *)
(* waiting points: none.                                              *)
(* function: the procedure checks if the index is legal. i.e. that    *)
(*   the index is within the limits of the table and that the index   *)
(*   points to an element that is in use (the lcp is connected).      *)
(*                                                                    *)
(**********************************************************************)

begin
if local_index <= max_lcp then
if lcp_table(local_index).state.connect = conn then
check_index:= true
else
check_index:= false
else     (* local_index > max_lcp *)
check_index:= false;
end;     (* check_index *)


procedure update_sp_head(var local_msg: ! reference);

(***********************************************************************)
(*                                                                     *)
(*                           update_sp_head                            *)
(*                                                                     *)
(* internal ncp procedure                                              *)
(* parameters:                                                         *)
(*   local_msg: reference to the supervisor message that should be     *)
(*     updated (call parameter).                                       *)
(* call of other procedures: none.                                     *)
(* use of global variables: help_sem, work_ref.                        *)
(* waiting points: yes, one                                            *)
(* function: the procedure swappes sender_id and receiver_id, sets the *)
(*   time in the supervisor head, and updates last.                    *)
(*                                                                     *)
(***********************************************************************)

var
local_ident: lcp_ident_type;

begin
lock local_msg as data: sup_mess_type do
begin
data.last:= 5 + sp_head_lgt + data.sp_head.bytecount;
with data.sp_head do
begin
(* swap sender_id and receiver_id *)
local_ident:= receiver_id;
receiver_id:= sender_id;
sender_id:= local_ident;
sp_type.req_ans:= ans;
lock work_ref as workdata: sup_data do
with workdata.head do
begin
first:= 6;
last:= first + 17;
next:= last + 1;
end;     (* with workdata.head and lock work_ref *)
work_ref^.u1:= get_date_time;
work_ref^.u2:= message;
signal(work_ref, timeout_sem.s^);
wait(work_ref, help_sem);
lock work_ref as workdata: date_time_type do
with workdata do
begin
time(1):= second(1) mod 16;
time(2):= second(2) mod 16;
time(3):= minute(1) mod 16;
time(4):= minute(2) mod 16;
time(5):= hour(1) mod 16;
time(6):= hour(2) mod 16;
time(7):= day(1) mod 16;
time(8):= day(2) mod 16;
time(9):= month(1) mod 16;
time(10):= month(2) mod 16;
time(11):= year(1) mod 16;
time(12):= year(2) mod 16;
end;     (* with workdata and lock work_ref *)
end;     (* with data.sp_head *)
end;     (* lock local_msg *)
end;     (* update_sp_head *)


procedure exchange_stack(var local_msg: reference);

(************************************************************************)
(*                                                                      *)
(*                            exchange_stack                            *)
(*                                                                      *)
(* internal ncp procedure.                                              *)
(* parameters:                                                          *)
(*   local_msg: reference to top message of a stack. at return it is a  *)
(*     reference to the new top message or nil if not a stack (call     *)
(*     and return parameter).                                           *)
(* call of other procedures: none.                                      *)
(* call of global variables: none.                                      *)
(* waiting points: none.                                                *)
(* function: the procedure exchanges the first (top message) and the    *)
(*   second messages in the stack. if no second stack element exist,    *)
(*   then the top message is released, and local_msg is nil at return.  *)
(*                                                                      *)
(************************************************************************)

var
local_ref: reference;

begin
pop(local_ref, local_msg);
if not nil(local_msg) then
push(local_msg, local_ref)
else
release(local_ref);
local_msg:=: local_ref;
end;     (* exchange_stack *)


procedure release_event(var local_msg: reference;
local_index: ! integer);

(********************************************************************)
(*                                                                  *)
(*                           release_event                          *)
(*                                                                  *)
(* internal ncp procedure.                                          *)
(* parameters:                                                      *)
(*   local_msg: reference to an event buffer that is released.      *)
(*     (call parameter).                                            *)
(*   local_index: index in the lcp_table (call parameter).          *)
(* call of other procedures: get_event_buf.                         *)
(* use of global variables: act_nr_event_buf.                       *)
(* waiting points: none.                                            *)
(* function: releases an event buffer. if any 'request event        *)
(*   buffer' messages, then the first of these is answered.         *)
(*   act_nr_event_buf is updated.                                   *)
(*                                                                  *)
(********************************************************************)

var
local_event_ref: reference;
local_inx: integer;
local_lcp_ident: integer;

begin
if not ownertest(event_buf_pool, local_msg) then
ncp_error(local_index, 1101);     (****   error 1101   ****)
release(local_msg);
act_nr_event_buf:= act_nr_event_buf + 1;
sensesem(local_msg, wait_ev_buf_sem);
if not nil(local_msg) then
begin    (* a 'request event buf' message is hanging *)
local_inx:= local_msg^.u3;
local_lcp_ident:= lcp_table(local_inx).lcp_ident;
get_event_buf(local_lcp_ident, wait_forever, local_event_ref);
if not nil(local_event_ref) then
begin     (* a free buffer is available *)
push(local_msg, local_event_ref);
local_event_ref^.u2:= ok;
return(local_event_ref);
end;     (* if not nil(local_event_ref) *)
end      (* if not nil(local_msg) *)
else     (* not nil(local_msg) *)
if waiting_event.state = used then
if lack_of_res in event_mask then
send_event(ev_lost)
else     (* not(lack_of_res in event_mask) *)
waiting_event.state:= unused;
end;     (* release_event *)


procedure send_sc(var local_msg: reference;
local_event: ! boolean);

(*********************************************************************)
(*                                                                   *)
(*                           send_sc                                 *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_msg: reference to a message that is signalled to sc.      *)
(*     nil at return (call parameter).                               *)
(*   local_event: specifies if the buffer is an event buffer (true)  *)
(*     or a supervisor buffer (false) (call parameter).              *)
(* call of other procedures: none.                                   *)
(* use of global variables: sc_sem.                                  *)
(* waiting points: none.                                             *)
(* function: the u-fields in the message are updated, and the        *)
(*   message is signalled to sc.                                     *)
(*                                                                   *)
(*********************************************************************)

begin
with local_msg^ do
begin
u1:= sc_out;
u2:= message;
u3:= sc_stack;
if local_event then
u4:= sc_ev_out_str
else
u4:= sc_output_str;
end;     (* with local_msg *)
signal(local_msg, sc_sem.s^);
end;     (* send_sc *)


procedure receive_sc;

(*********************************************************************)
(*                                                                   *)
(*                            receive_sc                             *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters: none                                                  *)
(* call of other procedures: none.                                   *)
(* use of global variables: act_nr_sup_buf, act_sc_input.            *)
(* waiting points: none.                                             *)
(* function: sends as many input buffers to sc as allowed. updates   *)
(*   act_nr_sup_buf and act_sc_input.                                *)
(*                                                                   *)
(*********************************************************************)

var
local_msg: reference;
local_sc_msg: reference;

begin
while (act_sc_input < sc_multi_buf) and (act_nr_sup_buf >= 1) do
begin
alloc(local_sc_msg, sc_mess_pool, ncp_sem.s^);
lock local_sc_msg as scdata: sc_in_type do
with scdata do
begin
first:= 6;
last:= sc_buf_size - 1;
next:= 6;
local_port:= ncp_port;
end;     (* with scdata and lock local_sc_msg *)
with local_sc_msg^ do
begin
u1:= sc_in;
u2:= message;
u3:= sc_stack;
u4:= sc_input_str;
end;     (* with local_sc_msg^ *)
alloc(local_msg, sup_mess_pool, ncp_sem.s^);
act_nr_sup_buf:= act_nr_sup_buf - 1;
lock local_msg as data: sup_mess_type do
with data do
begin
first:= 6;
last:= sup_buf_size - 1;
next:= 6;
end;     (* with data and lock local_msg *)
push(local_sc_msg, local_msg);
signal(local_msg, sc_sem.s^);
act_sc_input:= act_sc_input + 1;
end;     (* while (act_sc_input < sc_multi_buf) and .... *)
end;     (* receive_sc *)


procedure release_sup(var local_msg: reference;
local_index: ! integer);

(*********************************************************************)
(*                                                                   *)
(*                              release_sup                          *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_msg: reference to a supervisor message buffer that is     *)
(*     released. it is nil at return (call parameter).               *)
(*   local_index: index in the lcp_table (call parameter).           *)
(* call of other procedures: receive_sc, ncp_error.                  *)
(* use of global variables: act_nr_sup_buf .                         *)
(* waiting points: none.                                             *)
(* function: releases a supervisor message buffer and a sc message   *)
(*   buffer, if any. it updates act_nr_sup_buf and sends input       *)
(*   buffers to sc if allowed.                                       *)
(*                                                                   *)
(*********************************************************************)

var
local_ref: reference;

begin
pop(local_ref, local_msg);
if not nil(local_msg) then
begin
if not ownertest(sc_mess_pool, local_msg) then
ncp_error(local_index, 1131);     (****   error 1131   ****)
release(local_msg);     (* release sc message buffer *)
end;
if not ownertest(sup_mess_pool, local_ref) then
ncp_error(local_index, 1132);     (****   error 1132   ****)
release(local_ref);     (* release supervisor message buffer *)
act_nr_sup_buf:= act_nr_sup_buf + 1;
receive_sc;
end;     (* release_sup *)


procedure release_sc(var local_msg: reference;
local_index: ! integer;
local_event: ! boolean);

(*********************************************************************)
(*                                                                   *)
(*                          release_sc                               *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_msg: reference to an sc message buffer that is to be      *)
(*     released. it is nil at return (call parameter).               *)
(*   local_index: index in the lcp_table (call parameter).           *)
(*   local_event: specifies if the buffer is an event buffer (true)  *)
(*     or a supervisor buffer (false) (call parameter).              *)
(* call of other procedures: release_event, release_sup, ncp_error.  *)
(* use of global variables: none.                                    *)
(* waiting points: none.                                             *)
(* function: releases an sc message buffer and a supervisor or an    *)
(*   event buffer, if any. dependent on local_event, then it         *)
(*   calls release_event or release_sup.                             *)
(*                                                                   *)
(*********************************************************************)

var
local_ref: reference;

begin
pop(local_ref, local_msg);
if not ownertest(sc_mess_pool, local_ref) then
ncp_error(local_index, 1141);     (****   error 1141   ****)
release(local_ref);     (* release sc message buffer *)
if not nil(local_msg) then
if local_event then
release_event(local_msg, local_index)
else     (* not local__event *)
release_sup(local_msg, local_index);
end;     (* release_sc *)


procedure release_rep(local_rep_index: ! integer;
local_index: ! integer);

(*********************************************************************)
(*                                                                   *)
(*                          release_rep                              *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_rep_index: index in the repeat_table (call parameter).    *)
(*   local_index: index in the lcp_table (call parameter).           *)
(* call of other procedures: timerupdate.                            *)
(* use of global variables: repeat_table, timeout_sem, lcp_table,    *)
(*   ncp_stat, help_sem.                                             *)
(* waiting points: yes, one in timerupdate.                          *)
(* function: releases the messages that is used by repeatable        *)
(*   functions. it updates the statistical records, concerning       *)
(*   repeatable functions.                                           *)
(*                                                                   *)
(*********************************************************************)

var
local_ref: reference;

begin
pop(local_ref, repeat_table(local_rep_index).msg);
release(local_ref);
release(repeat_table(local_rep_index).msg);
timerupdate(repeat_table(local_rep_index).timeout_ref, 0, timeout_sem.s^, help_sem);
release(repeat_table(local_rep_index).timeout_ref);
lcp_table(local_index).repeat_stat.repeat_opers:=
lcp_table(local_index).repeat_stat.repeat_opers - 1;
ncp_stat.repeat_stat.repeat_opers:=
ncp_stat.repeat_stat.repeat_opers - 1;
end;     (* release_rep *)


procedure return_sup(var local_msg: reference;
local_status: ! set of sp_status_bit;
local_index: ! integer);

(**********************************************************************)
(*                                                                    *)
(*                            return_sup                              *)
(*                                                                    *)
(* internal ncp procedure.                                            *)
(* parameters:                                                        *)
(*   local_msg: reference to top message of a stack. the stack        *)
(*     consists of a supervisor message (top) and an sc message. it   *)
(*     is nil at return (call and return parameter).                  *)
(*   local_status: the status mask that is to be inserted into the    *)
(*     status field of the supervisor head (call parameter).          *)
(*   local_index: index in the lcp_table (call parameter).            *)
(* call of other procedures: update_sp_head, exchange_stack, send_sc, *)
(*   release_sup.                                                     *)
(* use of global variables: none.                                     *)
(* waiting points: none.                                              *)
(* function: the procedure inserts local_status into the status field *)
(*   of the supervisor head. dependent on the reject parameter in the *)
(*   type field of the supervisor head the procedure sends the        *)
(*   supervisor message to the sc or the buffers are released.        *)
(*                                                                    *)
(**********************************************************************)

var
local_rej_func: rej_func_type;

begin
lock local_msg as data: sup_mess_type do
begin
data.sp_head.status:= data.sp_head.status + local_status;
local_rej_func:= data.sp_head.sp_type.rej_func;
end;     (* lock local_msg *)
case local_rej_func of
no_reject:
begin
update_sp_head(local_msg);
exchange_stack(local_msg);
if not nil(local_msg) then
begin     (* stack ok *)
lock local_msg as scdata: sc_out_type do
scdata.first:= 6;
send_sc(local_msg, false);
end     (* if not nil(local_msg) *)
else     (* nil(local_msg) *)
ncp_error(local_index, 1151);     (****   error 1151   ****)
end;     (* no_reject *)
reject:
release_sup(local_msg, local_index);
end;     (* case local_rej_func *)
end;     (* return_sup *)


procedure send_lcp_sup(var local_lcp_msg: reference;
var local_msg: reference;
local_index: ! integer);

(**********************************************************************)
(*                                                                    *)
(*                           send_lcp_sup                             *)
(*                                                                    *)
(* internal ncp procedure.                                            *)
(* parameters:                                                        *)
(*   local_lcp_msg: reference to a 'wait message' message from the    *)
(*     lcp. it is nil at return (call parameter).                     *)
(*   local_msg: reference to a supervisor message buffer that is      *)
(*     updated. it is nil at return (call parameter).                 *)
(*   local_index: index in the lcp_table (call parameter).            *)
(* call of other procedures: none.                                    *)
(* use of global variables: lcp_table.                                *)
(* waiting points: none.                                              *)
(* function: updates the u-fields in the messages referred by         *)
(*   local_msg and local_lcp_msg. stacks these messages and returns   *)
(*   the resulting message to lcp. both references are nil at return. *)
(*   it updates lcp statistics.                                       *)
(*                                                                    *)
(**********************************************************************)

begin
with local_msg^ do
begin
u1:= sup_mess_buf;
u2:= message;
u3:= local_index;
u4:= lcp_msg_str;
end;     (* with local_msg *)
local_lcp_msg^.u2:= ok;
push(local_lcp_msg, local_msg);
return(local_msg);
if prod_stat in event_mask then
begin
inc15(lcp_table(local_index).lcp_stat.messages);
inc15(ncp_stat.lcp_stat.messages);
end;     (* if prod_stat in event_mask *)
end;     (* send_lcp_sup *)


procedure send_int_lcp(var local_msg: reference);

(*********************************************************************)
(*                                                                   *)
(*                           send_int_lcp                            *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_msg: reference to a supervisor message that is sent to    *)
(*     the internal lcp in ncp. it is nil at return (call parameter).*)
(* call of other procedures: inc15.                                  *)
(* use of global variables: lcp_table.                               *)
(* waiting points: none.                                             *)
(* function: the procedure updates the u-fields in the message,      *)
(*   referred by local_msg and returns the message.                  *)
(*   it updates ncp statistics.                                      *)
(*                                                                   *) 
(*********************************************************************)

begin
with local_msg^ do
begin
u2:= ok;
u3:= ncp_index;
u4:= int_lcp_str;
end;     (* with local_msg^ *)
return(local_msg);
if prod_stat in event_mask then
begin
inc15(lcp_table(ncp_index).lcp_stat.messages);
inc15(ncp_stat.lcp_stat.messages);
end;     (* if prod_stat in event_mask *)
end;     (* send_int_lcp *)


function search_table(local_key: ! integer;
var local_index: integer;
local_top: ! integer;
local_bottom: ! integer;
var local_table: lcp_index_type): boolean;

(***********************************************************************)
(*                                                                     *)
(*                           search_table                              *)
(*                                                                     *)
(* internal ncp function .                                             *)
(* parameters:                                                         *)
(*   local_key: the key that is searched for (call parameter).         *)
(*   local_index: the index in the local_table, where local_key        *)
(*     is found. it is unchanged, if local_key is not found (return    *)
(*     parameter).                                                     *)
(*   local_top: first element in local_table (call parameter).         *)
(*   local_bottom: last element in local_table (call parameter).       *)
(*   local_table: specifies the actual index table that is used (call  *)
(*     parameter).                                                     *)
(* call of other procedures: none.                                     *)
(* use of global variables: none.                                      *)
(* waiting points: none.                                               *)
(* function: search the local_table for an element with                *)
(*   local_key as key. local_index returns with the index in           *)
(*   local_table, if the element is found, else it is unchanged.       *)
(*   search_table is true if the element is found else false.          *)
(*                                                                     *)
(***********************************************************************)

var
top, bottom, middle: integer;

begin
if local_bottom >= local_top then
begin     (* local_table is not empty *)
top:= local_top;
bottom:= local_bottom;
repeat
middle:= (top + bottom) div 2;
if local_key > local_table(middle).key then
top:= middle + 1
else
bottom:= middle - 1;
until (local_key = local_table(middle).key) or (top > bottom);
if local_key = local_table(middle).key then
begin
local_index:= middle;
search_table:= true;
end     (* if local_key = local_table(middle).key *)
else     (* local_key <> local_table(middle).key *)
search_table:= false;
end     (* if local_bottom >= local_top *)
else     (* local_bottom < local_top *)
search_table:= false;
end;     (* search_table *)


function insert_table(local_key: ! integer;
var local_index: integer;
local_top: ! integer;
var local_bottom: integer;
var local_table: lcp_index_type): boolean;

(*********************************************************************)
(*                                                                   *)
(*                            insert_table                           *)
(*                                                                   *)
(* internal ncp function.                                            *)
(* parameters:                                                       *)
(*   local_key: the key of the element that is to be inserted in     *)
(*     the ordered local_table (call parameter).                     *)
(*   local_index: second part of the element that is to be inserted  *)
(*     in the local_table. if the element is inserted, then          *)
(*     local_index is unchanged at return. if the element is not     *)
(*     inserted, then local_index returns with the index in the      *)
(*     local_table, where the element already exist (call and return *)
(*     parameter).                                                   *)
(*   local_top: first element in local_table (call parameter).       *)
(*   local_bottom: last element in local_table. if element is        *)
(*     inserted, then local_bottom is incremented (call and return   *)
(*     parameter).                                                   *)
(*   local_table: specifies the actual index table that is used      *)
(*     (call and return parameter).                                  *)
(* call of other procedures: search_table.                           *)
(* use of global variables: none.                                    *)
(* waiting points: none.                                             *)
(* function: the function inserts the element that consists of       *)
(*   local_key and local_index in the ordered local_table.           *)
(*   local_key is the key. if the element is not already present     *)
(*   in the table then insert_table is true, else it is false, and   *)
(*   the element is not inserted.                                    *)
(*                                                                   *)
(*********************************************************************)

var
destination, source: integer;
local_inx: integer;
local_cont: boolean:= true;

begin
if not search_table(local_key, local_inx, local_top, local_bottom, local_table) then
begin     (* element is not already in the table *)
source:= local_bottom;
local_bottom:= local_bottom + 1;
destination:= local_bottom;
if local_bottom > local_top then
while local_cont do
if source < local_top then
local_cont:= false
else     (* source >= local_top *)
if local_table(source).key > local_key then
begin
local_table(destination):=local_table(source);
destination:= destination - 1;
source:= source - 1;
end     (* if local_table(source).key > local_key *)
else     (* local_table(source).key <= local_key *)
local_cont:= false;
local_table(destination).key:= local_key;
local_table(destination).index:= local_index;
insert_table:= true;
end     (* if not search_table(local_key, .... ) *)
else     (* search_table(local_key, .... ) *)
begin     (* element is already in the table *)
local_index:= local_inx;
insert_table:= false;
end;     (* else search_table(local_key, .... ) *)
end;     (* insert_table *)


function remove_table(local_key: ! integer;
var local_index: integer;
local_top: ! integer;
var local_bottom: integer;
var local_table: lcp_index_type): boolean;

(********************************************************************)
(*                                                                  *)
(*                          remove_table                            *)
(*                                                                  *)
(* internal ncp function.                                           *)
(* parameters:                                                      *)
(*   local_key: the key of the element that is to be removed from   *)
(*     the ordered local_table (call parameter).                    *)
(*   local_index: second part of the element that is removed from   *)
(*     local_table. it is unchanged, if the element is not found    *)
(*     (return parameter).                                          *)
(*   local_top: first element in local_table (call parameter).      *)
(*   local_bottom: last element in local_table. if the specified    *)
(*     element is removed, then local_bottom is decremented (call   *)
(*     and return parameter).                                       *)
(*   local_table: specifies the actual index table that is used     *)
(*     (call and return parameter).                                 *)
(* call of other procedures: search_table.                          *)
(* use of global variables: none.                                   *)
(* waiting points: none.                                            *)
(* function: the function removes the element pointed out by        *)
(*   local_key from the local_table. if the element is found        *)
(*   then remove_table is true else remove_table is false at        *)
(*   return.                                                        *)
(*                                                                  *)
(********************************************************************)

var
destination, source: integer;

begin
if search_table(local_key, destination, local_top, local_bottom, local_table) then
begin     (* element is in the table *)
local_index:= local_table(destination).index;
source:= destination + 1;
while source <= local_bottom do
begin
local_table(destination):= local_table(source);
destination:= destination + 1;
source:= source + 1;
end;     (* while source <= local_bottom *)
local_bottom:= local_bottom - 1;
remove_table:= true;
end     (* if search_table(local_key, .... ) *)
else     (* not search_table(local_key, .... ) *)
remove_table:= false;
end;     (* remove_table *)


procedure sc_data_to_comm(var local_from: ! sc_data_type;
var local_to: sc_comm_type);

(*********************************************************************)
(*                                                                   *)
(*                        sc_data_to_comm                            *)
(*                                                                   *)
(* internal ncp procedure.                                           *)
(* parameters:                                                       *)
(*   local_from: specifies the data that is to be copied (call       *)
(*     parameter).                                                   *)
(*   local_to: specifies the data area that data is copied into      *)
(*     (return parameter).                                           *)
(* call of other procedures: none.                                   *)
(* use of global variables: none.                                    *)
(* waiting points: none.                                             *)
(* function: converts the sc address (in supervisor data) specified  *)
(*   by local_from into the sc address (in sc communication format)  *)
(*   specified by local_to.                                          *)
(*                                                                   *)
(*********************************************************************)

begin
local_to.port_no:= local_from.port_no;
if (local_from.facility mod 2) = ack_req_fac then
local_to.ack_req:= true
else
local_to.ack_req:= false;
local_to.nuid_signf:= local_from.nuid_signf;
local_to.nuid:= local_from.nuid;
end;     (* sc_data_to_comm *)


procedure sc_comm_to_data(var local_from: ! sc_comm_type;
var local_to: sc_data_type);

(**********************************************************************)
(*                                                                    *)
(*                           sc_comm_to_data                          *)
(*                                                                    *)
(* internal ncp procedure.                                            *)
(* parameters:                                                        *)
(*   local_from: specifies the data that is to be copied (call        *)
(*     parameter).                                                    *)
(*   local_to: specifies the data area that data is copied into       *)
(*     (return parameter).                                            *)
(* call of other procedures: none.                                    *)
(* use of global variables: none.                                     *)
(* waiting points: none.                                              *)
(* function: converts the sc address (sc communication format),       *)
(*   specified by local_from into the sc address (supervisor data),   *)
(*   specified by local_to.                                           *)
(*                                                                    *)
(**********************************************************************)

begin
local_to.port_no:= local_from.port_no;
if local_from.ack_req then
local_to.facility:= ack_req_fac
else
local_to.facility:= 0;;
local_to.nuid_signf:= local_from.nuid_signf;
local_to.nuid:= local_from.nuid;
end;     (* sc_comm_to_data *)


function set_ev_ans(var local_msg: reference;
local_rec_no: ! integer): boolean;

(**********************************************************************)
(*                                                                    *)
(*                            set_ev_ans                              *)
(*                                                                    *)
(* internal ncp function.                                             *)
(* parameters:                                                        *)
(*   local_msg: reference to a supervisor message that contains the   *)
(*     relevant record (call parameter).                              *)
(*   local_rec_no: number of the record that is to be accesssed       *)
(*     (call parameter).                                              *)
(* call of other procedures: search_table, sc_data_to_comm.           *)
(* use of global variables: lcp_table.                                *)
(* waiting points: none.                                              *)
(* function: the function updates the event address of the specified  *)
(*   lcp according to the accessed record in the supervisor message.  *)
(*   if the lcp is not connected then set_ev_ans is false else true.  *)
(*                                                                    *)
(**********************************************************************)

type
local_sup_data = packed record
dummy: array(1..6 + sp_head_lgt + (local_rec_no - 1) * reclgt_ev_addr) of byte;
rec_data: ev_addr_record;
end;

var
local_index: integer;
local_sc_data: sc_data_type;

begin
lock local_msg as data: local_sup_data do
begin
if search_table(data.rec_data.lcp_ident.id, local_index,
ncp_index, act_nr_lcp, lcp_index_table) then
begin     (* the lcp is connected *)
local_index:= lcp_index_table(local_index).index;
local_sc_data:= data.rec_data.ev_sc_addr.sc_addr;
sc_data_to_comm(local_sc_data, lcp_table(local_index).event_sc_addr.sc_addr);
lcp_table(local_index).event_sc_addr.rec_ident:=
data.rec_data.ev_sc_addr.rec_ident.id;
set_ev_ans:= true;
end     (* if search_table(data.rec_data.lcp_ident.id, .... ) *)
else     (* not search_table(data.rec_data.lcp_ident.id, .... ) *)
set_ev_ans:= false;     (* the lcp is not connected *)
end;     (* lock local_msg *)
end;     (* set_ev_ans *)


function get_ev_ans(var local_msg: reference;
local_rec_no: ! integer): boolean;

(**********************************************************************)
(*                                                                    *)
(*                            get_ev_ans                              *)
(*                                                                    *)
(* parameters:                                                        *)
(*   local_msg: reference to the supervisor message that after call   *)
(*     should contain the relevant event answer record (return        *)
(*     parameter).                                                    *)
(*   local_rec_no: no of the record that is to be accessed (call      *)
(*     parameter).                                                    *)
(* call of other procedures: search_table, sc_comm_to_data.           *)
(* use of global variables: work_ref.                                 *)
(* waiting points: none.                                              *)
(* function: the function gets the event address of the specified     *)
(*   lcp, and puts it into the supervisor message. if the lcp is      *)
(*   not connected, then get_ev_ans is false, else true.              *)
(*                                                                    *)
(**********************************************************************)

type
local_sup_data = packed record
dummy: array(1..6 + sp_head_lgt + (local_rec_no - 1) * reclgt_ev_addr) of byte;
rec_data: ev_addr_record;
end;

local_work_data = packed record
dummy: array(1..6 + sp_head_lgt + (local_rec_no - 1) * 2) of byte;
lcp_ident: lcp_ident_type;
end;

var
local_index: integer;
local_sc_data: sc_data_type;
local_continue: boolean;

begin
lock work_ref as workdata: local_work_data do
local_continue:= search_table(workdata.lcp_ident.id, local_index,
ncp_index, act_nr_lcp, lcp_index_table);
if local_continue then
begin     (* the lcp is connected *)
local_index:= lcp_index_table(local_index).index;
lock local_msg as data: local_sup_data do
with data.rec_data do
begin
lcp_ident.i:= 0;
lcp_ident.id:= lcp_table(local_index).lcp_ident;
sc_comm_to_data(lcp_table(local_index).event_sc_addr.sc_addr, local_sc_data);
ev_sc_addr.sc_addr:= local_sc_data;
ev_sc_addr.rec_ident.i:= 0;
ev_sc_addr.rec_ident.id:=
lcp_table(local_index).event_sc_addr.rec_ident;
end;     (* with data.rec_data and lock local_msg *)
get_ev_ans:= true;
end     (* if local_index <> entry_not_found *)
else     (* local_index = entry_not_found *)
get_ev_ans:= false;     (* the lcp is not connected *)
end;     (* get_ev_ans *)


function check_datalgt(var local_msg: reference;
local_datalgt: ! integer): boolean;

(***********************************************************************)
(*                                                                     *)
(*                             check_datalgt                           *)
(*                                                                     *)
(* internal ncp function.                                              *)
(* parameters:                                                         *)
(*   local_msg: reference to the supervisor message, where data length *)
(*     is to be checked (call parameter).                              *)
(*   local_datalgt: the minimum length of data length in supervisor    *)
(*     message (call parameter).                                       *)
(* call of other procedures: none.                                     *)
(* use of global variables: sup_status, count.                         *)
(* waiting points: none.                                               *)
(* function: the function checks, if the bytecount in the supervisor   *)
(*   head matches with the size of the data area in the buffer         *)
(*   (last - first), and if bytecount is greater than local_datalgt.   *)
(*   check_datalgt is true if ok else false.                           *)
(*                                                                     *)
(***********************************************************************)

var
local_check: boolean:= true;

begin
lock local_msg as data: sup_mess_type do
with data do
begin
if (sp_head_lgt + sp_head.bytecount) > (last - first + 1) then
local_check:= false;
if sp_head.bytecount < local_datalgt then
local_check:= false;
if local_check = false then
begin
sup_status:= (.data_error.);
count:= sp_head.bytecount;
end;     (* if local_check = false *)
end;     (* with data and lock local_msg *)
check_datalgt:= local_check;
end;     (* check_datalgt *)


procedure reset_lcp_stat(local_index: ! integer);

(*********************************************************************)
(*                                                                   *)
(*                        reset_lcp_stat                             *)
(*                                                                   *)
(* parameters:                                                       *)
(*   local_index: index in the lcp_table, where the statistical      *)
(*     record is to be reset (call parameter).                       *)
(* call of other procedures: none.                                   *)
(* use of global variables: lcp_table.                               *)
(* waiting points: none.                                             *)
(* function: this procedure reset all statistic counters that        *)
(*   concern the specified index in the lcp_table.                   *)
(*                                                                   *)
(*********************************************************************)

begin
with lcp_table(local_index) do
begin
with lcp_stat do
begin
messages:= 0;
events:= 0;
pending_msg:= 0;
lost_msg:= 0;
end;     (* with lcp_stat *)
with repeat_stat do
begin
repeat_opers:= 0;
lost_repeat:= 0;
end;     (* with repeat_stat *)
end;     (* with lcp_table(local_index) *)
end;     (* reset_stat *)






(*********************************************************************)
(*                                                                   *)
(*                         ncp program start                         *)
(*                                                                   *)
(*********************************************************************)

begin

(*----------------------*)
(*     initializing     *)
(*----------------------*)
name:= own.incname;
testopen(z, name, sys_vector(operatorsem));
testout(z, version, 0);
lcp_table(ncp_index).lcp_ident:= ncp_ident;
lcp_index_table(ncp_index).key:= ncp_ident;
receive_sc;
alloc(oper_ref, oper_pool, oper_sem);
return(oper_ref);
alloc(work_ref, work_pool, help_sem);

repeat

(*-------------------------------*)
(*     central waiting point     *)
(*-------------------------------*)
wait(msg, ncp_sem.w^);
index:= entry_not_found;
case msg^.u2 of

(*-----------------*)
(*     message     *)
(*-----------------*)
message:
begin
if empty(msg) then
case msg^.u1 of

(*---------------------*)
(*     connect lcp     *)
(*---------------------*)
connect_lcp:
begin
lock msg as data: lcp_conn_type do
act_lcp_ident:= data.lcp_ident.id;
if first_free <= max_lcp then
begin     (* free entry in lcp table avaiblable *)
index:= first_free;
if insert_table(act_lcp_ident, index,
ncp_index, act_nr_lcp, lcp_index_table) then
begin     (* lcp not already connected *)
repeat
first_free:= first_free + 1;
if first_free > max_lcp then
continue:= false
else     (* first_free <= max_lcp *)
continue:= (lcp_table(first_free).lcp_ident <> free_entry);
until continue = false;
with lcp_table(index) do
begin     (* initialize lcp_table(index) *)
lcp_ident:= act_lcp_ident;
event_sc_addr:= event_addr;
state.connect:= conn;
end;     (* with lcp_table(index) *)
reset_lcp_stat(index);
msg^.u2:= ok;
msg^.u3:= index;
if connection in event_mask then
send_event(ev_connect);
end     (* if insert_table(act_lcp_ident, index) *)
else     (* not insert_table(act_lcp_ident, index) *)
begin     (* lcp already connected *)
index:= lcp_index_table(index).index;
ncp_error(index, 1);     (****   error 1   ****)
msg^.u2:= fct_not_allw;
if collision in event_mask then
send_event(ev_collision);
end;     (* else not insert_table(act_lcp_ident, index) *)
end     (* if first_free <= max_lcp *)
else     (* first_free > max_lcp *)
begin     (* no free entry avaiblable *)
ncp_error(first_free, 2);     (****   error 2   ****)
msg^.u2:= busy;
if lack_of_res in event_mask then
send_event(ev_lack_res);
end;     (* else first_free > max_lcp *)
return(msg);
end;    (* connect_lcp *)

(*------------------------*)
(*     disconnect lcp     *)
(*------------------------*)
disconnect_lcp:
begin
lock msg as data: lcp_disc_type do
act_lcp_ident:= data.lcp_ident.id;
if remove_table(act_lcp_ident, index,
ncp_index, act_nr_lcp, lcp_index_table) then
begin     (* lcp was connected *)
if index < first_free then
first_free:= index;
lcp_table(index).lcp_ident:= free_entry;
lcp_table(index).state.connect:= disconn;
continue:= true;
repeat     (* return wait messages, if any *)
sensesem(msg_ref, lcp_table(index).wait_msg_sem);
if not nil(msg_ref) then
begin     (* wait message found *)
msg_ref^.u2:= user_term;
return(msg_ref);
end      (* if not nil *)
else
continue:= false;
until continue = false;
continue:= true;
repeat     (* return pending supervisor messages, if any *)
sensesem(msg_ref, lcp_table(index).pending_sem);
if not nil(msg_ref) then
return_sup(msg_ref, (.lcp_unknown.), index)
else     (* not nil(msg_ref) *)
continue:= false;
until continue = false;
lcp_table(index).state.msg_pending:= not_pending;
(* return hanging 'wait event buffer' messages *)
continue:= true;
while continue do
begin     (* run through wait_ev_buf_sem *)
sensesem(msg_ref, wait_ev_buf_sem);
if not nil(msg_ref) then
if msg_ref^.u3 = index then
begin     (* 'wait event buffer' belonging to the disconnecting lcp is found *)
msg_ref^.u2:= user_term;
return(msg_ref);
end     (* if msg_ref^.u3 = index *)
else     (* msg_ref^.u3 <> index *)
signal(msg_ref, help_sem)
else     (* nil(msg_ref) *)
continue:= false;
end;     (* while continue *)
continue:= true;
while continue do
begin
sensesem(msg_ref, help_sem);
if not nil(msg_ref) then
signal(msg_ref, wait_ev_buf_sem)
else     (* nil(msg_ref) *)
continue:= false;
end;     (* while continue *)
continue:= true;
rep_index:= 0;
repeat
rep_index:= rep_index + 1;
if rep_index > max_repeat then
continue:= false
else     (* rep_index <= max_repeat *)
if not nil(repeat_table(rep_index).msg) then
begin     (* repeatable function found *)
lock repeat_table(rep_index).msg as data: sup_mess_type do
help_int:= data.sp_head.receiver_id.id;
if help_int = act_lcp_ident then
release_rep(rep_index, index);
end;     (* if not nil(repeat_table(rep_index).msg) *)
until continue = false;
msg^.u2:= ok;
if disconnection in event_mask then
send_event(ev_disconnect);
end     (* if remove_table(act_lcp_ident) *)
else     (* not remove_table(act_lcp_ident) *)
begin     (* lcp not connected *)
ncp_error(index, 11);     (****   error 11   ****)
msg^.u2:= rec_unkw;
end;     (* else not remove_table(act_lcp_ident) *)
return(msg);
end;     (* disconnect_lcp *)

(*------------------------------*)
(*     request event buffer     *)
(*     wait event buffer        *)
(*------------------------------*)
req_event_buf, wait_event_buf:
begin
index:= msg^.u3;
if check_index(index) then
begin     (* index ok *)
act_lcp_ident:= lcp_table(index).lcp_ident;
case msg^.u1 of
req_event_buf:
get_event_buf(act_lcp_ident, no_wait, event_ref);
wait_event_buf:
get_event_buf(act_lcp_ident, wait_forever, event_ref);
end;     (* case msg^.u1 of *)
if not nil(event_ref) then
begin     (* free event buffer avaiblable *)
msg^.u2:= ok;
push(msg, event_ref);
return(event_ref);
end;     (* if not nil(event_ref) *)
end     (* if check_index *)
else     (* check_index = false *)
begin     (* illegal index *)
ncp_error(index, 21);     (****   error 21   ****)
msg^.u2:= format_err;
return(msg);
end;     (* else check_index = false *)
end;     (* req_event_buf, wait_event_buf *)

(*----------------------*)
(*     wait message     *)
(*----------------------*)
wait_message:
begin
index:= msg^.u3;
if check_index(index) then
begin     (* index ok *)
case lcp_table(index).state.msg_pending of

(*------------------------------------*)
(*     supervisor message pending     *)
(*------------------------------------*)
pending:
begin
sensesem(msg_ref, lcp_table(index).pending_sem);
if not nil(msg_ref) then
send_lcp_sup(msg, msg_ref, index)
else     (* nil(msg_ref) *)
begin
lcp_table(index).state.msg_pending:= not_pending;
signal(msg, lcp_table(index).wait_msg_sem);
end;     (* else nil(msg_ref) *)
end;     (* pending *)

(*---------------------------------------*)
(*     no supervisor message pending     *)
(*---------------------------------------*)
not_pending:
begin
signal(msg, lcp_table(index).wait_msg_sem);
end;     (* not_pending *)
end;     (* case lcp_table(index).state.msg_pending *)
end      (* if check_index *)
else     (* check_index = false *)
begin     (* illegal index *)
ncp_error(index, 31);     (****   error 31   ****)
msg^.u2:= format_err;
return(msg);
end;     (* else check_index = false *)
end;     (* wait_message *)

(*-------------------------*)
(*     illegal message     *)
(*-------------------------*)
otherwise     (* illegal u1 code *)
ncp_error(index, 41);     (****   error 41   ****)
msg^.u2:= ill_opcode;
return(msg);
end     (* case msg^.u1 *)
else     (* not empty(msg) *)
begin     (* message from lcp is stacked *)
ncp_error(index, 51);     (****   error 51   ****)
msg^.u2:= format_err;
return(msg);
end;     (* else not empty(msg) *)
end;     (* message *)

(*----------------*)
(*     answer     *)
(*----------------*)
otherwise
case msg^.u4 of

(*---------------*)
(*     event     *)
(*---------------*)
event_str:
begin
index:= msg^.u3;
if check_index(index) then
begin
case msg^.u2 of
ok:
begin
lock msg as data: sup_mess_type do
data.sp_head.sender_id.id:= lcp_table(index).event_sc_addr.rec_ident;
update_sp_head(msg);
alloc(sc_msg, sc_mess_pool, ncp_sem.s^);
lock sc_msg as scdata: sc_out_type do
with scdata do
begin
first:= 6;
last:= sc_out_last;
next:= 6;
local_port:= ncp_port;
rec_sc:= lcp_table(index).event_sc_addr.sc_addr;
end;     (* with scdata and lock sc_msg *)
push(sc_msg, msg);
send_sc(msg, true);
if prod_stat in event_mask then
begin
inc15(lcp_table(index).lcp_stat.events);
inc15(ncp_stat.lcp_stat.events);
end;     (* if prod_stat in event_mask *)
end;     (* ok *)
otherwise     (* not ok *)
ncp_error(index, 101);     (****   error 101   ****)
release_event(msg, index);
end;     (* case msg^.u2 *)
end      (* if check_index(index) *)
else     (* check_index(index) = false *)
begin     (* illegal index *)
ncp_error(index, 102);     (****   error 102   ****)
release_event(msg, index);
end;     (* else check_index(index) = false *)
end;     (* event_str *)

(*---------------------*)
(*     lcp message     *)
(*---------------------*)
lcp_msg_str:
begin
index:= msg^.u3;
if check_index(index) then
begin
case msg^.u2 of
ok:
return_sup(msg, (..), index);
otherwise     (* not ok *)
ncp_error(index, 111);     (****   error 111   ****)
release_sup(msg, index);
end;     (* case msg^.u2 *)
end      (* if check_index(index) *)
else     (* check_index(index) = false *)
begin     (* illegal index *)
ncp_error(index, 112);     (****   error 112   ****)
release_sup(msg, index);
end;     (* else check_index(index) = false *)
end;     (* lcp_msg_str *)

(*------------------*)
(*     ts input     *)
(*------------------*)
sc_input_str:
begin
act_sc_input:= act_sc_input - 1;
receive_sc;     (* send new input buffer to sc *)
case msg^.u2 of
ok:
begin
pop(sc_msg, msg);
if not nil(msg) then
begin     (* stack from sc ok *)
lock msg as data: sup_mess_type do
with data.sp_head do
begin
if receiver_id.i = 1 then
ind_rec:= true     (* receiver_id is indirectly addressed *)
else     (* receiver_id.i = 0 *)
ind_rec:= false;     (* receiver_id directly addressed *)
if sender_id.i = 1 then
ind_sen:= true     (* sender_id is indirectly addressed *)
else     (* sender_id.i = 0 *)
ind_sen:= false;     (* sender_id directly addressed *)
end;     (* with data.sp_head and lock msg *)
if ind_rec or ind_sen then

(*-------------------------------*)
(*     indirectly addressing     *)
(*-------------------------------*)
begin
lock msg as data: ind_addr_data do
lock sc_msg as scdata: sc_out_type do
begin
scdata.local_port:= ncp_port;
sc_data_var:= data.sc_addr;
sc_data_to_comm(sc_data_var, scdata.rec_sc);
if ind_rec then     (* indirect receiver_id highest priority *)
data.head.sp_head.receiver_id:= data.lcp_ident
else     (* ind_sen *)
data.head.sp_head.sender_id:= data.lcp_ident;
<*
ind_addr_lgt:= ind_addr_size + data.sc_addr.nuid_signf;
*> ind_addr_lgt:= ind_addr_size + nuid_lgt; (******** dyn. arrays *)
end;     (* lock sc_msg and lock msg *)
lock msg as data: sup_data do
begin
count:= data.head.sp_head.bytecount - ind_addr_lgt;
data.head.sp_head.bytecount:= count;
data.head.last:= 5 + sp_head_lgt + count;
index_to:= 1;
index_from:= ind_addr_lgt + 1;
while count > 0 do
begin     (* remove indirect addressing field in supervisor data *)
data.sp_data(index_to):= data.sp_data(index_from);
count:= count - 1;
index_to:= index_to + 1;
index_from:= index_from + 1;
end;     (* while count > 0 *)
end;     (* lock msg *)
end;     (* if ind_sen or ind_rec *)
if ind_rec then

(*--------------------------------*)
(*     receiver_id indirectly     *)
(*--------------------------------*)
begin
push(sc_msg, msg);
send_sc(msg, false);
end     (* if ind_rec *)
else     (* not ind_rec *)

(*------------------------------------*)
(*     receiver_id not indirectly     *)
(*     or no indirect addressing      *)
(*------------------------------------*)
begin
lock msg as data: sup_mess_type do
begin
act_lcp_ident:= data.sp_head.receiver_id.id;
ncp_contr:= data.sp_head.sp_type.ncp_control;
repeat_func:= data.sp_head.sp_type.rep_func;
count:= data.sp_head.bytecount;
end;     (* lock msg *)
if search_table(act_lcp_ident, index,
ncp_index, act_nr_lcp, lcp_index_table) then
begin     (* receiver_id known *)
index:= lcp_index_table(index).index;
lock sc_msg as scdata: sc_in_type do
scdata.first:= scdata.last + 1;
push(msg, sc_msg);
msg:=: sc_msg;
case ncp_contr of
no_ncp_cntr:
case index of
ncp_index:
send_int_lcp(msg);
otherwise     (* not ncp_index *)
sensesem(msg_ref, lcp_table(index).wait_msg_sem);
if not nil(msg_ref) then
(* 'wait message' message hanging *)
send_lcp_sup(msg_ref, msg, index)
else     (* nil(msg_ref) *)
begin     (* no 'wait message' message hanging *)
lcp_table(index).state.msg_pending:= pending;
signal(msg, lcp_table(index).pending_sem);
if prod_stat in event_mask then
begin
inc15(lcp_table(index).lcp_stat.pending_msg);
inc15(ncp_stat.lcp_stat.pending_msg);
end;     (* if prod_stat in event_mask *)
end;     (* else nil(msg_ref) *)
end;     (* case index *)

(*------------------------*)
(*     repeat message     *)
(*------------------------*)
ncp_cntr:
case repeat_func of
start_rep:
if (count >= rep_data_lgt) and (count <= rep_buf_size) then
if first_free_rep <= max_repeat then
begin     (* free entry in repeat_table available *)
rep_index:= first_free_rep;
repeat_table(rep_index).state:= used;
repeat
first_free_rep:= first_free_rep + 1;
if first_free_rep > max_repeat then
continue:= false
else     (* first_free_rep <= max_repeat *)
continue:=
(repeat_table(first_free_rep).state = used);
until continue = false;
alloc(sc_msg, sc_mess_pool, ncp_sem.s^);
pop(msg_ref, msg);
lock msg as data: sc_out_type do
lock sc_msg as scdata: sc_out_type do
scdata:= data;
push(msg_ref, msg);
alloc(msg_ref, repeat_pool, ncp_sem.s^);
push(msg_ref, sc_msg);
msg_ref:=: sc_msg;
lock msg as data: repeat_data do
lock msg_ref as refdata: rep_sup_data do
begin
repeat_table(rep_index).ticks:= data.ticks;
refdata.head:= data.head;
refdata.head.sp_head.bytecount:=
data.head.sp_head.bytecount - rep_data_lgt;
refdata.head.last:=
refdata.head.sp_head.bytecount + sp_head_lgt + 5;
refdata.sp_data:= data.sp_data;
if data.start_time = time_0 then
count:= 0
else     (* data.time <> time_0 *)
begin
(****************************)
(*                          *)
(*     udregn resttiden     *)
(*                          *)
(****************************)
count:= 15;     (* forel|big *)
end;     (* else data.time <> time_0 *)
end;     (* lock msg *)
release_sup(msg, index);
msg_ref^.u3:= index;
repeat_table(rep_index).msg:=: msg_ref;
alloc(msg, timeout_pool, help_sem);
alloc(msg_ref, timeout_pool, ncp_sem.s^);
msg_ref^.u4:= time_out_str;
timerbook(msg, msg_ref, count, rep_index,
timeout_sem.s^, help_sem);
repeat_table(rep_index).timeout_ref:=: msg;
lcp_table(index).repeat_stat.repeat_opers:=
lcp_table(index).repeat_stat.repeat_opers + 1;
ncp_stat.repeat_stat.repeat_opers:=
ncp_stat.repeat_stat.repeat_opers + 1;
end     (* if first_free_rep <= max_repeat *)
else     (* first_free_rep > max_repeat *)
return_sup(msg, (.rep_res_lack.), index)
else     (* count < rep_data_lgt *)
return_sup(msg, (.data_error.), index);
stop_rep:
begin
rep_index:= 0;
repeat
rep_index:= rep_index + 1;
if rep_index > max_repeat then
continue:= false
else     (* rep_index <= max_repeat *)
if not nil(repeat_table(rep_index).msg) then
lock repeat_table(rep_index).msg as tabdata:
sup_mess_type do
lock msg as data: sup_mess_type do
continue:= not ((data.sp_head.receiver_id.id =
tabdata.sp_head.receiver_id.id) and
(data.sp_head.lcp_oper =
tabdata.sp_head.lcp_oper))
else     (* nil(repeat_table(rep_index).msg) *)
continue:= true;
until continue = false;
if rep_index <= max_repeat then
begin     (* repeat function is found in repeat_table *)
release_rep(rep_index, index);
return_sup(msg, (..), index);
end     (* if rep_index <= max_repeat *)
else     (* rep_index > max_repeat *)
return_sup(msg, (.ill_lcp_oper.), index);
end;     (* stop_rep *)
end;     (* case repeat_func *)
end;     (* case ncp_contr *)
end     (* if search_table(act_lcp_ident, .... ) *)
else     (* not search_table(act_lcp_ident, .... ) *)
begin     (* receiver_id unknown *)
push(msg, sc_msg);
return_sup(sc_msg, (.lcp_unknown.), index);
end;     (* else not search_table(act_lcp_ident, .... ) *)
end;     (* else not ind_rec *)
end     (* if not nil(msg) *)
else     (* nil(msg) *)
begin     (* stack from sc not ok *)
ncp_error(index, 121);     (****   error 121   ****)
release(sc_msg);
end;     (* else nil(msg) *)
end;     (* ok *)
otherwise     (* not ok *)
ncp_error(index, 122);     (****   error 122   ****)
release_sc(msg, index, false);
end;     (* case msg^.u2 *)
end;     (* sc_input_str *)

(*-------------------------------*)
(*     sc output, supervisor     *)
(*-------------------------------*)
sc_output_str:
begin
case msg^.u2 of
ok:  ;     (* do nothing *)
otherwise     (* not ok *)
ncp_error(index, 131);     (****   error 131   ****)
end;     (* case msg^.u2 *)
release_sc(msg, index, false);
end;     (* sc_output_str *)

(*--------------------------*)
(*     sc output, event     *)
(*--------------------------*)
sc_ev_out_str:
begin
case msg^.u2 of
ok:  ;     (* do nothing *)
otherwise     (* not ok *)
ncp_error(index, 141);     (****   error 141   ****)
end;     (* case msg^.u2 *)
release_sc(msg, index, true);
end;     (* sc_ev_out_str *)

(*------------------*)
(*     time out     *)
(*------------------*)
time_out_str:
begin
lock msg as data: object_type do
rep_index:= data.object;
if not nil(repeat_table(rep_index).msg) then
begin     (* a repeatable function is still hanging *)
index:= repeat_table(rep_index).msg^.u3;
help_int:= msg^.u2;
timerbook(repeat_table(rep_index).timeout_ref, msg,
repeat_table(rep_index).ticks, rep_index, timeout_sem.s^, help_sem);
case help_int of
timeout_ok:
if act_nr_sup_buf >= 1 then
begin     (* free supervisor buffers available *)
if index <> ncp_index then
sensesem(msg_ref, lcp_table(index).wait_msg_sem);
if (index = ncp_index) or (not nil(msg_ref)) then
begin     (* generate a repeat supervisor message *)
alloc(sc_msg, sc_mess_pool, ncp_sem.s^);
pop(msg, repeat_table(rep_index).msg);
lock sc_msg as scdata: sc_out_type do
lock repeat_table(rep_index).msg as tabdata: sc_out_type do
begin
scdata:= tabdata;
scdata.first:= 6;
end;     (* lock sc_msg and lock repeat_table(rep_index).msg *)
push(msg, repeat_table(rep_index).msg);
alloc(msg, sup_mess_pool, ncp_sem.s^);
act_nr_sup_buf:= act_nr_sup_buf - 1;
lock msg as data: rep_sup_data do
lock repeat_table(rep_index).msg as tabdata: rep_sup_data do
data:= tabdata;
push(msg, sc_msg);
case index of
ncp_index:
send_int_lcp(sc_msg);
otherwise     (* not ncp_index *)
send_lcp_sup(msg_ref, sc_msg, index);
end;     (* case index *)
end     (* if (index = ncp_index) or (not nil(msg_ref)) *)
else     (* not ((index = ncp_index) or (not nil(msg_ref))) *)
begin
inc15(lcp_table(index).repeat_stat.lost_repeat);
inc15(ncp_stat.repeat_stat.lost_repeat);
end;     (* else not ((index = ncp_index) or (not nil(msg_ref))) *)
end     (* if act_nr_sup_buf >= 1 *)
else     (* act_nr_sup_buf < 1 *)
begin
inc15(lcp_table(index).repeat_stat.lost_repeat);
inc15(ncp_stat.repeat_stat.lost_repeat);
end;     (* else act_nr_sup_buf < 1 *)
otherwise     (* not timeout_ok *)
ncp_error(index, 151);     (****   error 151   ****)
end;     (* case help_int *)
end     (* if not nil(repeat_table(rep_index).msg) *)
else     (* nil(repeat_table(rep_index).msg) *)
begin
repeat_table(rep_index).state:= unused;
if rep_index < first_free_rep then
first_free_rep:= rep_index;
release(msg);
end;     (* else nil(repeat_table(rep_index).msg) *)
end;     (* time_out_str *)

(*----------------------*)
(*     internal lcp     *)
(*----------------------*)
int_lcp_str:
begin
index:= msg^.u3;
case msg^.u2 of
ok:
begin
lock msg as data: sup_mess_type do
with data.sp_head do
begin
stat_control:= sp_type.stat_cntr;
basic_oper:= lcp_oper.basic;
modif_oper:= lcp_oper.modif;
count:= bytecount;
end;     (* with data.sp_head and lock msg *)
sup_status:= (..);     (* reset status in supervisor head *)
case basic_oper of

(*---------------------------*)
(*     control operation     *)
(*---------------------------*)
lcp_cntr:
begin
case modif_oper of

(*------------------------*)
(*     set event mask     *)
(*------------------------*)
set_event_mask:
if check_datalgt(msg, 4) then     (* datalgt >= 4 *)
lock msg as data: ev_mask_data do
with data do
begin
event_mask:= (update_mask * ev_mask) +
((full_mask - update_mask) * event_mask);
update_mask:= event_mask;
count:= 2;
end;     (* with data and lock msg and if check_datalgt(msg, 4) *)

(*---------------------------*)
(*     set date and time     *)
(*---------------------------*)
set_time:
if check_datalgt(msg, 12) then     (* datalgt >= 12 *)
begin
lock msg as data: sup_data do
lock work_ref as workdata: date_time_type do
with data, workdata do
begin
first:= 6;
last:= first + 17;
next:= last + 1;
year(1):= sp_data(1);
year(2):= sp_data(2);
month(1):= sp_data(3);
month(2):= sp_data(4);
day(1):= sp_data(5);
day(2):= sp_data(6);
hour(1):= sp_data(7);
hour(2):= sp_data(8);
minute(1):= sp_data(9);
minute(2):= sp_data(10);
second(1):= sp_data(11);
second(2):= sp_data(12);
end;     (* with data, workdata, lock work_ref, and lock msg *)
work_ref^.u1:= set_date_time;
work_ref^.u2:= message;
signal(work_ref, timeout_sem.s^);
wait(work_ref, help_sem);
if work_ref^.u2 <> timeout_ok then
sup_status:= (.data_error.);
end;     (* if check_datalgt and set_time *)

(*---------------------------*)
(*     set event address     *)
(*---------------------------*)
set_event_addr:
begin
if (count mod reclgt_ev_addr) = 0 then
continue:= true     (* bytecount ok *)
else     (* (count mod reclgt_ev_addr) <> 0 *)
continue:= false;     (* bytecount not ok *)
if continue then
begin
help_int:= count div reclgt_ev_addr;
while continue and (help_int > 0) do
begin     (* update event address *)
continue:= set_ev_ans(msg, help_int);
help_int:= help_int - 1;
end;     (* while continue and (help_int > 0) *)
if not continue or (help_int <> 0) then     (* data error *)
sup_status:= (.lcp_unknown.);
end     (* if continue *)
else     (* not continue *)
sup_status:= (.data_error.);
end;     (* set_event_addr *)

(*--------------------------------------*)
(*     set exception return address     *)
(*--------------------------------------*)
set_except_addr:
begin
help_int:= nuid_lgt + 4;
if check_datalgt(msg, help_int) then
lock msg as data: exc_addr_data do
begin
sc_data_var:= data.exc_sc_addr.sc_addr;
sc_data_to_comm(sc_data_var, except_addr.sc_addr);
except_addr.rec_ident:= data.exc_sc_addr.rec_ident.id;
end;     (* lock msg *)
end;      (* set_except_addr *)

(*-----------------------------------*)
(*     illegal control operation     *)
(*-----------------------------------*)
otherwise     (* illegal modif_oper *)
sup_status:= (.ill_lcp_oper.);
end;     (* case modif_oper *)
end;     (* lcp_cntr *)

(*-------------------------*)
(*     sense operation     *)
(*-------------------------*)
lcp_sense:
begin
case modif_oper of

(*------------------------*)
(*     get event mask     *)
(*------------------------*)
get_event_mask:
if check_datalgt(msg, 0) then     (* datalgt >= 0 *)
begin
lock msg as data: ev_mask_data do
data.update_mask:= event_mask;
count:= 2;
end;     (* if check_datalgt(msg, 0) *)

(*---------------------------*)
(*     get event address     *)
(*---------------------------*)
get_event_addr:
begin
if (count mod 2) = 0 then
continue:= true     (* bytecount ok *)
else     (* (count mod 2) <> 0 *)
continue:= false;     (* bytecount not ok *)
if continue then
begin
count:= count div 2;
help_int:= count;
lock msg as data: sup_data do
lock work_ref as workdata: sup_data do
workdata:= data;
while continue and (count > 0) do
begin
continue:= get_ev_ans(msg, count);
count:= count - 1;
end;     (* while continue and (count > 0) *)
if not continue or (count <> 0) then
lock msg as data: sup_data do
lock work_ref as workdata: sup_data do
begin     (* a data error has been detected *)
data:= workdata;
sup_status:= (.lcp_unknown.);
count:= data.head.sp_head.bytecount;
end     (* if not continue or (count <> 0) *)
else     (* continue and (count = 0) *)
count:= help_int * reclgt_ev_addr;
end     (* if continue *)
else     (* not continue *)
sup_status:= (.data_error.);
end;     (* get_event_addr *)

(*--------------------------------------*)
(*     get exception return address     *)
(*--------------------------------------*)
get_except_addr:
if check_datalgt(msg, 0) then     (* datalgt >= 0 *)
lock msg as data: exc_addr_data do
begin
sc_comm_to_data(except_addr.sc_addr, sc_data_var);
with data.exc_sc_addr do
begin
sc_addr:= sc_data_var;
rec_ident.i:= 0;
rec_ident.id:= except_addr.rec_ident;
count:= 6 + nuid_lgt;
end;     (* with data.exc_sc_addr *)
end;     (* lock msg and if check_datalgt(msg, 0) *)

(*-----------------------------*)
(*     get connected lcp's     *)
(*-----------------------------*)
get_conn_lcp:
if check_datalgt(msg, 0) then     (* datalgt >= 0 *)
begin
lock msg as data: conn_lcp_data do
for help_int:= 0 to act_nr_lcp do
data.lcp_ident(help_int):= lcp_index_table(help_int).key;
count:= (act_nr_lcp + 1) * 2;
end;     (* if check_datalgt(msg, 0) *)

(*----------------------------------*)
(*     get repeatable functions     *)
(*----------------------------------*)
get_rep_func:
if check_datalgt(msg, 0) then     (* datalgt >= 0 *)
lock msg as data: rep_func_data do
begin
count:= 0;
for help_int:= 1 to max_repeat do
if not nil(repeat_table(help_int).msg) then
lock repeat_table(help_int).msg as tabdata: sup_mess_type do
begin
count:= count + 1;
data.rep_data(count).lcp_ident:= tabdata.sp_head.receiver_id.id;
data.rep_data(count).seq_no:= tabdata.sp_head.seq_no;
data.rep_data(count).lcp_oper:= tabdata.sp_head.lcp_oper;
end;     (* lock repeat_table, if not nil and for help_int *)
count:= count * rep_func_lgt;
end;     (* lock msg and if check_datalgt(msg, 0) *)



(*---------------------------------*)
(*     illegal sense operation     *)
(*---------------------------------*)
otherwise
sup_status:= (.ill_lcp_oper.);
end;     (* case modif_oper *)
end;     (* lcp_sense *)

(*----------------------------------*)
(*     get statistics operation     *)
(*----------------------------------*)
lcp_get_stat:
begin
case modif_oper of

(*----------------------------*)
(*     get lcp statistics     *)
(*----------------------------*)
get_lcp_stat:
begin
if (count mod 2) = 0 then
continue:= true     (* bytecount ok *)
else     (* (count mod 2) <> 0 *)
continue:= false;     (* bytecount not ok *)
count:= count div 2;
if continue then
begin
help_int:= count;
lock msg as data: sup_data do
lock work_ref as workdata: sup_data do
workdata:= data;
lock msg as data: stat_data do
begin
data.ncp_stat:= ncp_stat;
lock work_ref as workdata: lcp_stat_data do
begin
index_to:= 0;
while continue and (count > 0) do
begin
continue:= search_table(workdata.lcp_ident(index_to),
index_from, ncp_index, act_nr_lcp, lcp_index_table);
if continue then     (* specified lcp is connected *)
begin
index_from:= lcp_index_table(index_from).index;
data.lcp_statis(index_to).lcp_ident:=
workdata.lcp_ident(index_to);
data.lcp_statis(index_to).lcp_stat:=
lcp_table(index_from).lcp_stat;
data.lcp_statis(index_to).repeat_stat:=
lcp_table(index_from).repeat_stat;
index_to:= index_to + 1;
count:= count - 1;
end;     (* if continue *)
end;     (* while continue and (count > 0) *)
end;     (* lock work_ref *)
end;     (* lock msg *)
if not continue or (count <> 0) then
lock msg as data: sup_data do
lock work_ref as workdata: sup_data do
begin     (* a data error has been detected *)
data:= workdata;
sup_status:= (.lcp_unknown.);
count:= data.head.sp_head.bytecount;
end     (* if not continue or (count <> 0) *)
else     (* continue and (count = 0) *)
begin
if stat_control = reset_stat then
lock work_ref as workdata: lcp_stat_data do
begin
count:= help_int;
index_to:= 0;
while count > 0 do
begin
continue:= search_table(workdata.lcp_ident(index_to),
index_from, ncp_index, act_nr_lcp, lcp_index_table);
index_from:= lcp_index_table(index_from).index;
reset_lcp_stat(index_from);
index_to:= index_to + 1;
count:= count - 1;
end;     (* while count > 0 *)
end;     (* if stat_control = reset_stat and lock work_ref *)
count:= ncp_stat_lgt + help_int * lcp_stat_lgt;
end;     (* else continue and (count = 0) *)
end     (* if continue *)
else     (* not continue *)
sup_status:= (.data_error.);
end;     (* get_lcp_stat *)

(*------------------------------------------*)
(*     illegel get statistics operation     *)
(*------------------------------------------*)
otherwise     (* illegal modif_oper *)
sup_status:= (.ill_lcp_oper.);
end;     (* case modif_oper *)






end;     (* lcp_get_stat *)
end;     (* case basic_oper *)
lock msg as data: sup_mess_type do
with data do
begin
last:= 5 + sp_head_lgt + count;
sp_head.status:= sup_status;
sp_head.bytecount:= count;
end;     (* with data and lock msg *)
msg^.u4:= lcp_msg_str;
return(msg);
end;     (* ok *)
otherwise     (* not ok *)
ncp_error(index, 201);     (****   error 201   ****)
release_sup(msg, index);
end;     (* case msg^.u2 *)
end;     (* int_lcp_str *)
otherwise     (* unknown stream *)
ncp_error(index, 211);     (****   error 211   ****)
msg^.u2:= not_mess;
return(msg);
end;     (* case msg^.u4 *)
end;     (* case msg^.u2 *)
until forever;
end.


(*********************************************************************)
(*                                                                   *)
(*                     end of ncp program                            *)
(*                                                                   *)
(*********************************************************************)


«eof»