|
DataMuseum.dkPresents historical artifacts from the history of: RC3500 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC3500 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 108288 (0x1a700) Types: TextFileVerbose Names: »sncp«
└─⟦a41ae585a⟧ Bits:30001842 SW-save af projekt 1000, Alarm-system └─⟦72244f0ef⟧ └─⟦this⟧ »sncp«
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»