|
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: 56064 (0xdb00) Types: TextFileVerbose Names: »tsatcjoba«
└─⟦a41ae585a⟧ Bits:30001842 SW-save af projekt 1000, Alarm-system └─⟦72244f0ef⟧ └─⟦this⟧ »tsatcjoba«
job nla 9 200 area 10 size 100000 time 11 59 perm disc1 2000 20 ( mode list.yes source = copy 25.1 atcsource = set 1 disc1 ( i atcedit1 atcsource = edit source end ) if ok.no finis outlst = set 1 disc1 outlst = indent atcsource mark lc templist = set 1 disc1 templist = cross outlst clear temp outlst o errors pascal80 spacing.12000 codesize.10000 alarmenv atcsource o c lookup pass6code if ok.yes ( tsatcbina = set 1 disc1 tsatcbina = move pass6code scope user tsatcbina ) tsatclst = set 1 disc1 tsatclst = copy templist errors scope user tsatclst convert errors clear temp templist finis ) process atconnector( (*t1 op_sem : sempointer; t1*) var main_sem , (* Pointer to ATC's main semaphore. - All messages are received here *) queue_sem : !ts_pointer; (* Pointers to the queue semaphore, that - holds control an test messages while ATC is busy *) var ath_sem , (* Pointer to the main semaphore of ATH *) driver_sem , (* Pointer to main semaphore of LAM driver *) timer_sem , com_pool : !sempointer; (* Pointer to the semaphore that holds - the vacant message resources of the TS *) var dc_macro , (* macro address of own dc *) ts_macro : !macroaddr; (* macro address of own ts *) own_addr : integer; (* Micro address of this ATC inarnation *) channel_no : byte ); (* i/o channel number used by this ATC incarnation *) const version = "vers 3.08a/"; (********************************************************************************* * * description : The purpose and function of the AT_CONNECTOR is mainly to * run the protocole with an AT. The ATC is the master of * this communication. * The state of the transmission line is monitored by ATC * and alarms concerning the conditions of transmission are * signalled to PVC or DC. * Furtermore commands originating from DC and VC are executed * and alarms from AT are signalled to a VC. * AT_CONNECTOR participates in the module supervision in * the TS. * * externals : check5 * testopen * testout * * environment : alarm environment (latest version) * * author : NLA * *********************************************************************************) \f (********************************************************************************* * * PSEUDO CODE of AT_CONNECTOR * * process atconnector * * constant, type and variable declaration parts * 1) shielded types * 2) telegrams from TS to AT * 3) telegrams from AT to TS * 4) state telegrams from AT to TS * 5) operation codes and formats * 6) watch central table and management of it * 7) management of states and protocol * 8) supervision of transmission line * 9) miscellaneous * * forward declaration part * * subroutine declaration part * * * begin * * initialize; * * restrict_protocole; * <* end of initialize sequence *> * * repeat <* forever *> * * if conversation = idle then * begin * if open( queue ) then <* preprocess queue *> * begin * wait( msg, queue ); * initiate_conversation <* messages in the queue always involve AT *> * end * else * begin * sendtimer( delay_msg ); * send_telegram( poll, 0 ) * end * end; * * wait( msg, main ); * * if ownertest( driver_pool, msg ) then * driver_msg :=: msg * else * case message_origin of * * ATH: * begin * if operation_code in (.control, testi1, testi2, teste.) then * signal( msg, queue ) * else * read_write( msg ) <* AT not involved, execute at once *> * end; * * DRIVER: * if transmission_error and limit_overflow then * signal( call_limit_alarm, ATH ) * else * begin * if limit_underflow then * signal( recall_limit_alarm, ATH ); * * case AT_operation_code of * * p_ack: conversation:= idle; * * au_alarm: * if no_of_bytes = AVC_block_size then * signal( au_alarm, AVC ) * else * send_telegram( poll, 0 ); * * addr: * begin * search_address_code; * send_telegram( poll, 0 ) * end; * * state_alarm: * if state_byte <> current_state then * begin * update_current_state; * signal( state_alarm, PVC ) * end; * * d_ack: * if no_of_bytes = block_size then * signal( control_receipt, sender ) * else * send_telegram( cntrl, next_cntrl_byte ); * * t_ack: * begin * signal( test_receipt, sender ); * conversation:= idle * end; * * end <* case AT_operation_code *> * * end * * end <* case message origin *> * * until forever * * end. <* process AT_CONNECTOR *> * *********************************************************************************) \f (********************************************************************************* * * ABBREVIATION LIST * * at, AT alarm terminal * atc, ATC alarm terminal connector * ath, ATH alarm terminal (connector) handler * au alarm unit * avc alternative watch central * dc district centre * driver lam driver * msg reference to a message * pvc primary watch central * r_w read_write * sem semaphore * s_a.. stop activity (e.g. s_a_limit) * t_e../..t_e transmission error (e.g. t_e_counter) * TS, ts terminal station * vc watch central * * * * * * * * * * * * *********************************************************************************) \f (********************************************************************************* * declaration part 1: shielded types * *********************************************************************************) var (* pools. Allocation takes place with main_sem as answer semaphore *) driver_pool : pool 1 of integer; (* driver message is allocated from this pool *) delay_pool : pool 1; (* delay message is allocated from this pool *) (* reference variables *) delay_msg, (* holds delay out message while it's unused *) ath_msg, (* holds message from ATH while waiting for response from AT *) driver_msg, (* holds message from DRIVER while while it's unused *) alarm_msg, (* general use. Holds alarm message while it's updated *) atc_msg : reference; (* holds message from input semaphore while it's inspected *) \f (********************************************************************************* * declaration part 2: telegrams from master (TS) to slave (AT) * *********************************************************************************) const (* operation codes *) poll_opc = 0; atc_cntrl = 1; atc_testi = 2; atc_teste = 3; (* data bytes *) poll_byte = 0; tEsti1_byte = 0; testi2_byte = 1; type atc_op_codes = poll_opc..atc_teste; atc_format = packed record out_data : byte; atc_opc : atc_op_codes; serial_number : boolean; checkbits : 0..31 end; var last_telegram : atc_format := atc_format( 0, 0, false, 0 ); \f (********************************************************************************* * declaration part 3: telegrams from slave (AT) to master (TS) * *********************************************************************************) const (* operation codes *) p_ack = 0; state = 1; au_alarm = 2; addr = 3; d_ack = 4; t_ack = 5; e_ack = 6; n_ack = 7; (* test intern bytes *) test_int_ok = #h06; (* 0000 0110 *) test_int_err = #h15; (* 0001 0101 *) type at_op_codes = p_ack..n_ack; at_format = packed record in_data : byte; at_opc : at_op_codes; checkbits : 0..31 end; \f (********************************************************************************* * declaration part 4: state telegrams from slave (AT) to master (TS) * *********************************************************************************) const (* at state bits *) unused = 0; at_time_out = 1; hs_error = 2; au_error = 3; serif_error = 4; restart = 5; batt_limit = 6; batt_supply = 7; type state_bits = unused..batt_supply; state_byte = set of state_bits; var state_bit : state_bits := unused; \f (********************************************************************************* * declaration part 5: alarm net operation codes and formats * *********************************************************************************) const (* pvc log operation code *) pvc_alarm_log = #h01; (* garbage message *) reject_opc = #h12; (* alarms *) au_alarm_opc = #h30; line_alarm = #h31; state_alarm = #h32; service_alarm = #h34; s_a_alarm = #h35; (* control *) ts_cntrl = #h40; group_cntrl = #h44; (* tests *) ts_testi1 = #h80; ts_testi2 = #h82; ts_teste = #h84; (* change of activity *) ts_newactivity = #h90; service_poll = ts_newactivity + service_code; connect_test = #h92; \f (* updating of watch central table *) upd_vc_table = #ha0; (* read package counter *) read_package_count = #hb4; (* read or update of parameter *) r_w_tec = #hb2; r_w_service_limit = #hb6; r_w_s_a_limit = #hba; r_w_max_succ_t_e = #hbc; dummy_alarm = #hc8; type word_msg_format = record alarmnetlabel : alarmlabel; param : array( 0..( size_listen - ( label_size + 1 ) ) ) of integer end; byte_msg_format = record alarmnetlabel : alarmlabel; datapart : alarm end; connect_msg_format = record alarmnetlabel : alarmlabel; vc_address : alarmnetaddr end; \f (********************************************************************************* * declaration part 6: watch central table and management of it * *********************************************************************************) const pvc_index = 1; type vc_spann = pvc_index..vc_addr_l; vc_update_format = record alarmnetlabel : alarmlabel; new_vc : vc_addr_e end; var vc_addr_table : array( vc_spann ) of vc_addr_e; actual_vc_index, top_avc_index : vc_spann := pvc_index; \f (********************************************************************************* * declaration part 7: management of states and protocol * *********************************************************************************) const forever = false; driver_ready = #hff; type run_set = set of byte; type_of_conversation = ( idle, (* no telegram pending *) busy, (* poll pending *) control, (* control pending *) testi, (* testi1 or testi2 telegram pending *) teste, (* test extern pending *) coll_alarm1 , (* ATC is collecting multi byte alarm *) coll_alarm2 ); (* a poll is pending to look for a new alarm *) var runtimeset : run_set := (..); conversation : type_of_conversation := idle; \f (********************************************************************************* * declaration part 8: supervision of transmission line * *********************************************************************************) type valid_set = set of at_op_codes; t_e_kind_type = ( no_error, time_excess, (* reported from DRIVER *) not_ack, (* n_ack operation code received *) bit_error, (* error in checksum *) ill_opc, (* unexpected operation code in response *) channel_error ); (* reported from DRIVER *) var t_e_step : integer := trans_err_rate; (* increment of t_e_counter when a transmission error occurs *) service_limit : integer := service_lim; (* t_e_counter service_limit. *) s_a_limit : integer := stop_poll_lim; (* t_e_counter stop activity limit. *) max_succ_t_e : integer := max_succ_lin_err; (* number of successive transmission errors before line alarm *) t_e_counter, (* transmission error counter *) no_succ_t_e : integer := 0; valid_response : array( busy..coll_alarm2 ) of valid_set; t_e_kind : t_e_kind_type := no_error; line_state : ( low, (* t_e_counter below service limit *) serv_lim_excess, (* service_limit exceeded *) s_a_lim_excess ) := low; (* stop activity limit exceeded *) \f (********************************************************************************* * declaration part 9: miscellaneous * *********************************************************************************) const override = false; dummy = 0; dummy_macro = macroaddr( dummy, dummy, dummy ); (*t3 tek_offs = #h18; tec_offs = #h28; cnv_offs = #h60; t3*) (*t3 dump_st_off = #hd0; dump_st_on = #hd1; t3*) type create_ch_format = array( 0..1 ) of byte; var package_count : integer := 0; (* is counted circular from 0 through 32766 = ( max_int - 1) *) delay3, delay4 : byte; (* contents u3 and u4 values of delay message *) current : byte := 1; block_size : byte := 0; at_op_code : at_op_codes := 0; at_data : byte := 0; (*t3 dump_state : boolean := false; t3*) (*t1 z : zone; t1*) \f (********************************************************************************* * forward declaration part * *********************************************************************************) procedure restrict_protocol; forward; \f (*t3 procedure dump_state_block( text: alfa; param: integer ); type hexa = array( 0..15 ) of char; four_digits = packed array( 9..12 ) of 0..15; state_block = array( 0..15 ) of four_digits; const hex_convert = hexa( "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ); var temp_msg : reference; string : alfa; word : 0..15; position : 9..12; begin testout( z, text, param ); string:= " "; repeat wait( temp_msg, com_pool^ ); if ( temp_msg^.u3 = dummy_route ) then return( temp_msg ) until not nil( temp_msg ); lock temp_msg as locvar: run_set do locvar:= runtimeset; t3*) (* end lock temp_msg *) (*t3 lock temp_msg as locvar: state_block do begin for word:= 0 to 15 do begin for position:= 9 to 12 do string( position ):= hex_convert( locvar( word, position ) ); testout( z, string, word ) end end; t3*) (* lock temp_msg *) (*t3 return( temp_msg ) end; t3*) (* procedure dump_state_block *) \f (*t3 procedure print_telegram( var msg: reference; transmit: boolean; param: byte ); type hexa = array( 0..15 ) of char; const hex_convert = hexa( "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ); var string : alfa; begin string:= " "; if transmit then lock msg as locvar: atc_format do with locvar do begin string( 1 ):= "T"; string( 4 ):= hex_convert( atc_opc ); string( 6 ):= hex_convert( ord( serial_number ) ); string( 8 ):= hex_convert( checkbits div 16 ); string( 9 ):= hex_convert( checkbits mod 16 ); string( 11 ):= hex_convert( out_data div 16 ); string( 12 ):= hex_convert( out_data mod 16 ) end t3*) (* lock msg *) (*t3 else lock msg as locvar: at_format do with locvar do begin string( 1 ):= "R"; string( 6 ):= hex_convert( at_opc ); string( 8 ):= hex_convert( checkbits div 16 ); string( 9 ):= hex_convert( checkbits mod 16 ); string( 11 ):= hex_convert( in_data div 16 ); string( 12 ):= hex_convert( in_data mod 16 ); end; t3*) (* lock msg *) (*t3 testout( z, string, param ) end; t3*)(* procedure print_telegram *) \f procedure send_telegram( new_opc :atc_op_codes; data_byte :byte; new_serial_no, transmission_error: boolean); (********************************************************************************* * description : Updates and sends a telegram to AT (through DRIVER) and requests a * delay message from TIMER * * call value : new_opc = operation code of telegram or unsignificant * data_byte = data byte of telegram or unsignificant * new_serial_no = indicates whether serial number of * telegram is to be alternated. Significant * only if transmission error * transmision_error = indicates whether last telegram is to be * repeated. * return value : all are unchanged * globals : driver_msg = nil after the call * last_telegram = updated *********************************************************************************) begin if transmission_error and ( not new_serial_no ) then (* repeat last telegram *) lock driver_msg as locvar: atc_format do locvar:= last_telegram (* end lock driver_msg *) else with last_telegram do begin if not transmission_error then (* set up new telegram *) begin atc_opc:= new_opc; serial_number:= not serial_number; out_data:= data_byte end else if new_serial_no then serial_number:= not serial_number; lock driver_msg as locvar: atc_format do locvar:= last_telegram; (* end lock driver_msg *) if check5( driver_msg, generate ) then; lock driver_msg as locvar: atc_format do last_telegram:= locvar (* end lock driver_msg *) end; (*t3 print_telegram( driver_msg, true, ord( conversation ) ); t3*) if not nil( delay_msg ) then with delay_msg^ do begin u3:= delay3; u4:= delay4; sendtimer( delay_msg ) end; driver_msg^.u2:= channel_no; signal( driver_msg, driver_sem^ ) end; (* procedure send_telegram *) \f function ready_byte_msg( var msg: reference; data_byte: byte; var current: byte; block_size: byte ): boolean; (********************************************************************************* * description : Enters one data byte in message datapart. Takes a message * from common resources when it's necessary * call value : msg = references message to fill * data_byte = byte in question * current = indices byte number in message * block_size = number of bytes to fill * return value : ready_byte_msg = true if filling is completed * current = next position. Initiated if there's no more * data to fill * data_byte, block_size * = unchanged * globals : none *********************************************************************************) begin if nil( msg ) then sensesem( msg, com_pool^ ); if nil( msg ) then ready_byte_msg:= true else begin (*t3 testout( z, "current byte", current ); t3*) if ( current <= block_size ) then lock msg as locvar: byte_msg_format do locvar.datapart( current ):= data_byte; (* end lock msg *) ready_byte_msg:= ( current >= block_size ); if ( current < block_size ) then current:= current + 1 else current:= 1 end end; (* function ready_byte_msg *) \f procedure finish_message( var msg : reference; rec_macro : macroaddr; rec_micro : integer; vc_index : vc_spann; route , operation_code , block_size : byte; res : result_range; log_to_pvc : boolean ); (*********************************************************************************** * description : Updates the user fields and message label part and sends * then message to ATH. * call value : msg = references message to be send * vc_index = index to vc address table for receiver vc if any * route, operation_code, block_size, res * = message label information * log_to_pvc = true if the alarm is to be logged at pvc * return value : msg = nil * the others are unchanged * globals : own_addr = unchanged ************************************************************************************) type log_msg_format = record alarmnetlabel : alarmlabel; avc_address : alarmnetaddr; data_part : array( 5..2 * size_listen - label_size - 2 ) of byte end; var temp_msg : reference; alarm_bytes : alarm; \f begin if not nil( msg ) then begin with msg^ do begin (*t3 testout( z, "OUT. route", route ); t3*) (*t3 testout( z, "OUT. opcode", operation_code ); t3*) u3:= route; u4:= operation_code end; lock msg as locvar: byte_msg_format do with locvar, locvar.alarmnetlabel do begin if ( route <> at_route ) then begin no_of_by:= block_size + label_size; rec.macro:= rec_macro; rec.micro:= rec_micro; ts_add( 0 ):= vc_addr_table( vc_index ).vc_index; if log_to_pvc then alarm_bytes:= datapart; end else begin rec:= send; if ( block_size <> 0 ) then no_of_by:= block_size + label_size; end; send.macro:= ts_macro; send.micro:= own_addr; result:= res end; (* lock msg *) signal( msg, ath_sem^ ); \f if log_to_pvc then begin sensesem( temp_msg, com_pool^ ); if not nil( temp_msg ) then lock temp_msg as locvar: log_msg_format do with locvar, avc_address do begin micro:= vc_addr_table( actual_vc_index ).vc_index; for current:= 1 to block_size do data_part( current + 5 ):= alarm_bytes( current ); end; finish_message( temp_msg, dummy_macro, dummy, pvc_index, route, pvc_alarm_log, (**) ( block_size + 4 ), res, not log_to_pvc ); current:= 1 end; if operation_code in (.pvc_alarm_log, au_alarm_opc, line_alarm, state_alarm, ts_cntrl, group_cntrl, ts_teste, ts_newactivity.) then package_count:= ( package_count + 1 ) mod max_int; end end; (* procedure finish_message *) \f procedure garbage_message( var msg: reference; (*t3 text: alfa; t3*)error_code: result_range ); (********************************************************************************* * description : Sends an unrecognizable message to ATH. The supposed * message label is moved to the data part of the message * and a normal alarmnetlabel and user fields is set up. * If this is impossible, the message is released * call value : msg = references message in question * text = error diagnose * error_code = entered in label * return value : msg = nil * text, error_code = unchanged * globals : none *********************************************************************************) type error_format = array( 0..1 ) of alarmlabel; begin (*t3 testout( z, text, error_code ); t3*) if ( msg^.size >= (label_size + 2 )) then begin lock msg as locvar: error_format do begin locvar( 1 ):= locvar( 0 ); locvar( 1 ).op_code:= msg^.u4 end; (* lock msg *) finish_message( msg, dummy_macro, dummy, actual_vc_index, (**) at_route, reject_opc, ( label_size + 2 ), error_code, override ) end else release( msg ) end; (* procedure garbage_message *) \f function search_addr_code( table_entry: byte; var table_index: vc_spann ): boolean; (********************************************************************************** * description : Searches vc address table for watch central address code * * call value : table_entry = address code to search * table_index = undefined * return value : search_addr_code = true if the entry is found else false * table_entry = unchanged * table_index = indices entry if it exists * globals : vc_addr_table = unchanged *********************************************************************************) begin table_index:= pvc_index; while ( table_index < top_avc_index ) and ( table_entry <> vc_addr_table( table_index ).addr_code ) do table_index:= table_index + 1; search_addr_code:= ( table_entry = vc_addr_table( table_index ).addr_code ) end; (* function search_addr_code *) \f function search_vc_index( table_entry: integer; var table_index: vc_spann ): boolean; (********************************************************************************* * description : Searches vc address table for watch central index * * call value : table_entry = entry to search * table_index = undefined * return value : search_vc_index = true if the entry is found, otherwise false * table_entry = unchanged * table_index = indices entry if it exists * globals : vc_addr_table = unchanged *********************************************************************************) begin table_index:= pvc_index; while ( table_index < top_avc_index ) and ( table_entry <> vc_addr_table( table_index ).vc_index ) do table_index:= table_index + 1; search_vc_index:= ( table_entry = vc_addr_table( table_index ).vc_index ) end; (* function search_vc_index *) \f procedure transm_cntrl( var at_op_code: at_op_codes; var at_data: byte; valid_response: valid_set ); (********************************************************************************* * description : Monitors the conditions of transmission and manages * the sending of messages concerning the state of the transmission line. * Alarms are hold back when ATC is in service_poll. * The counters are not updated if AT state says no power * call value : at_op_code = undefined * at_data = undefined * valid_response = the set of responses from AT (slave) which are * valid in relation to the telegram send * return value : at_op_code = the operation code of the telegram * if this is found to be valid * at_data = data byte from telegram if transmission * isn't disturbed * valid_response = unchanged * globals : runtimeset = updated * t_e_counter = updated * no_succ_line_err = updated * line_state = updated * t_e_kind = updated acc. to state/kind of transmission * max_succ_t_e, service_limit, s_a_limit * = unchanged ********************************************************************************) \f procedure send_line_state( op_code, data: byte ); (********************************************************************************* * description : Sends a message to DC or VC concerning the state of * the transmission line * call value : op_code = line, service or stop_activity alarm * data = call (may be time out) or recall * return value : both are unchanged * globals : runtimeset = unchanged * actual_vc_index = unchanged *********************************************************************************) var temp_msg : reference; current : byte := 1; begin if not ( service_poll in runtimeset ) then if ready_byte_msg( temp_msg, data, current, 1 ) then finish_message( temp_msg, dc_macro, dc_erh_mic_addr, pvc_index, (**) at_route1, op_code, 1, accepted, override ) end; (* procedure send_line_state *) \f begin (* procedure transm_cntrl *) (*t3 runtimeset:= runtimeset - t3*) (**) (*t3 (.ord( t_e_kind ) + tek_offs, ord( line_state ) + tec_offs.); t3*) if ( driver_msg^.u2 = ok_result ) then (* no error result from DRIVER *) begin if check5( driver_msg, check ) = false then (* bit error *) t_e_kind:= bit_error else lock driver_msg as locvar: at_format do with locvar do begin if ( at_opc = n_ack ) then t_e_kind:= not_ack else if at_opc in valid_response then begin t_e_kind:= no_error; at_op_code:= at_opc; at_data:= in_data end else t_e_kind:= ill_opc end (* lock driver_msg *) end else begin (* driver_msg^.u2 <> ok_result: error result from DRIVER *) if ( driver_msg^.u2 = timeout_err ) then t_e_kind:= time_excess else t_e_kind:= channel_error end; (*t3 print_telegram( driver_msg, false, ord( t_e_kind ) ); t3*) \f if not ( runtimeset >= (.batt_limit, batt_supply.) ) then begin if ( t_e_kind <> no_error ) then begin t_e_counter:= t_e_counter + ( ord( t_e_counter < s_a_limit ) ) * t_e_step; (* don't go too high *) (*t1 no_succ_t_e:= no_succ_t_e + ( ord( no_succ_t_e < max_int ) ); t1*) (* don't overflow *) if ( no_succ_t_e = max_succ_t_e ) then (* send line alarm *) begin send_line_state( line_alarm, (**) ( ord( t_e_kind = time_excess ) * ( timeout_err - 1 ) + call ) ); if not ( service_poll in runtimeset ) then runtimeset:= runtimeset - (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) end end else begin t_e_counter:= t_e_counter - ord( t_e_counter > 0 ); (* freeze at zero point *) if ( no_succ_t_e >= max_succ_t_e ) then (* recall line alarm *) begin send_line_state( line_alarm, recall ); if not ( service_poll in runtimeset ) then runtimeset:= runtimeset + (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.); no_succ_t_e:= 0 end end; \f case line_state of low: if ( t_e_counter >= service_limit ) then (* send service alarm *) begin send_line_state( service_alarm, call ); line_state:= serv_lim_excess end; serv_lim_excess: if ( t_e_counter < service_limit ) then (* recall service alarm *) begin send_line_state( service_alarm, recall ); line_state:= low end else if ( t_e_counter >= s_a_limit ) then (* send stop activity alarm *) begin send_line_state( s_a_alarm, call ); line_state:= s_a_lim_excess end; s_a_lim_excess: if ( t_e_counter < s_a_limit ) then (* recall stop activity alarm *) begin send_line_state( s_a_alarm, recall ); line_state:= serv_lim_excess end otherwise end (* case line_state *) end; (*t3 runtimeset:= runtimeset + t3*) (**) (*t3 (.ord( t_e_kind ) + tek_offs, ord( line_state ) + tec_offs.) t3*) end; (* procedure transm_cntrl *) \f procedure initiate_conversation( var request_msg: reference ); (********************************************************************************* * description : Initiates a conversation witg AT in accordance with * operation code in then message from ATH * call value : request_msg = references message from ATH * return value : request_msg = nil if the message is rejected, * otherwise unchanged * globals : conversation = updated according to operation code * current = initiated * block_size = number of bytes to send to AT * t_e_kind = unchanged * vc_addr_table = unchanged *********************************************************************************) var result_code : result_range := accepted; steering_vc_index : vc_spann; begin lock request_msg as locvar: byte_msg_format do with locvar, locvar.alarmnetlabel do begin block_size:= no_of_by - label_size; \f case request_msg^.u4 of (* operation code *) ts_cntrl: if search_vc_index( ts_add( 0 ), steering_vc_index ) then begin if vc_addr_table( steering_vc_index ).steering then begin (* legal sender *) conversation:= control; send_telegram( atc_cntrl, datapart( current ), (**) ( t_e_kind = ill_opc ), override (* ! *) ) (* ! override transmission error *) end else result_code:= not_steering end else result_code:= unknown_sender; ts_testi1, ts_testi2: if ( send.macro <> dc_macro ) then result_code:= forbidden else begin conversation:= testi; block_size:= block_size + 1; if ( request_msg^.u4 = ts_testi1 ) then send_telegram( atc_testi, testi1_byte, (**) ( t_e_kind = ill_opc ), override (* ! *) ) (* ! override transmission error *) else send_telegram( atc_testi, testi2_byte, (**) ( t_e_kind = ill_opc ), override (* ! *) ) (* ! override transmission error *) end; ts_teste: begin conversation:= teste; send_telegram( atc_teste, datapart( current ), (**) ( t_e_kind = ill_opc ), override (* ! *) ) (* ! override transmission error *) end; otherwise end; (* case request_msg^.u4 *) end; (* lock request_msg *) if ( result_code <> accepted ) then finish_message( request_msg, dummy_macro, dummy, actual_vc_index, at_route, (**) ( request_msg^.u4 + receipt ), 0, result_code, override ) end; (* procedure initiate_conversation *) \f procedure exec_conn_operation( var msg: reference ); (******************************************************************************** * description : Executes on request from ATH, those operation types, * that doesn't involve DRIVER and sends a receipt to ATH * call value : msg = reference to message from ATH * return value : msg = nil * globals : runtimeset * according to operation code: * actual_vc_index, top_vc_index, vc_addr_table ********************************************************************************) var res : result_range := accepted; block_size : byte := 0; operation_code : byte; table_index : vc_spann; \f procedure compute_delay( delay: integer ); (********************************************************************************* * description : Computes delay to enter the u3 and u4 fields of the delay * message as (u3*2^u4) * call value : delay = integer value of delay * return value : delay = unchanged * globals : delay3, delay4 = altered according to formula above *********************************************************************************) begin delay:= ( delay mod 33 ) * time_out_unit; delay4:= 0; while delay > max_byte do begin delay:= delay div 2; delay4:= delay4 + 1 end; delay3:= delay; end; (* procedure compute_delay *) \f procedure rw_param( var parameter: integer ); (********************************************************************************* * description : Reads or updates a parameter according to operation code * and update field and sends a receipt to ATH * call value : parameter = parameter en question * return value : parameter = updated if update is insert_code * globals : none *********************************************************************************) begin lock msg as locvar: word_msg_format do with locvar, locvar.alarmnetlabel do if ( send.macro <> dc_macro ) then res:= forbidden else case update of read_code: begin param( 0 ):= parameter; block_size:= 2 end; modify_code: if ( msg^.u4 <> read_package_count ) then parameter:= param( 0 ) else res:= forbidden; otherwise res:= unknown_update end (* case update *) end; (* procedure rw_param *) \f begin (* procedure exec_conn_operation *) (*t3 testout( z, "exec_conn_op", msg^.u4 ); t3*) if ( msg^.u4 <> max_byte ) then operation_code:= msg^.u4 + receipt; case msg^.u4 of (* operation code *) reject_opc: return( msg ); ts_newactivity: lock msg as locvar: word_msg_format do with locvar, alarmnetlabel do if ( send.macro <> dc_macro ) and ( send.micro <> ath_mic_addr ) then res:= forbidden else begin (*t3 testout( z, "new activity", update ); t3*) case update of stop_code: begin (*t3 runtimeset:= runtimeset - (.( tek_offs + ord( t_e_kind ) ), ( tec_offs + ord( line_state ) ), ( cnv_offs + ord( conversation ) ).); t3*) if not nil( alarm_msg ) then with vc_addr_table( pvc_index ) do begin finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, at_route, au_alarm_opc, (**) ( current - 1 ), data_incomplete, (**) ( vc_addr_table( actual_vc_index ).vc_index <> vc_index ) ); current:= 1; conversation:= busy end; runtimeset:= runtimeset - (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste, ts_newactivity, service_poll.) end; \f start_code: if not ( upd_vc_table in runtimeset ) then res:= not_ready else begin (*t3 runtimeset:= runtimeset + (.tek_offs, tec_offs, cnv_offs.); t3*) t_e_counter:= param( 0 ); compute_delay( param( 1 ) ); valid_response( busy ):= (.p_ack, au_alarm, addr, state, n_ack.); valid_response( control ):= (.state, d_ack, n_ack.); valid_response( testi ):= (.state, t_ack, n_ack.); valid_response( teste ):= (.state, e_ack, n_ack.); valid_response( coll_alarm1 ):= (.au_alarm, addr, state, n_ack.); valid_response( coll_alarm2 ):= (.p_ack, au_alarm, addr, state, n_ack.); line_state:= low; no_succ_t_e:= 0; runtimeset:= runtimeset + (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste, ts_newactivity.) - (.at_time_out..batt_supply, service_poll.) end; \f service_code: begin (*t3 runtimeset:= runtimeset + (.tek_offs, tec_offs, cnv_offs.); t3*) runtimeset:= runtimeset + (.ts_testi1, ts_testi2, ts_newactivity, service_poll.) - (.ts_cntrl, group_cntrl, ts_teste.) - (.at_time_out..batt_supply.); if not nil( alarm_msg ) then with vc_addr_table( pvc_index ) do begin finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, at_route, au_alarm_opc, (**) ( current - 1 ), data_incomplete, (**) ( vc_addr_table( actual_vc_index ).vc_index <> vc_index ) ); current:= 1; conversation:= busy end; compute_delay( param( 1 ) ); valid_response( busy ):= (.p_ack, n_ack.); valid_response( testi ):= (.t_ack, n_ack.) end; otherwise res:= unknown_update end (* case update *) end; (* lock msg *) \f connect_test: begin lock msg as locvar: connect_msg_format do with locvar, alarmnetlabel do begin rec:= vc_address; vc_address:= send; send:= rec end; operation_code:= dummy_alarm end; dummy_alarm: ; ( dummy_alarm + receipt ): lock msg as locvar: connect_msg_format do with locvar, alarmnetlabel do begin rec:= vc_address; vc_address:= send; send:= rec; operation_code:= connect_test + receipt end ; \f upd_vc_table: lock msg as locvar: vc_update_format do with locvar, new_vc, alarmnetlabel do if ( send.macro <> dc_macro ) then res:= forbidden else begin (*t3 testout( z, "update kind ", update ); testout( z, "address code", addr_code ); testout( z, "vc index ", vc_index ); testout( z, "blocksize ", block ); testout( z, "steering ", ord( steering ) ); t3*) case update of (* change of vc address table *) read_code: if search_addr_code( addr_code, table_index ) then begin new_vc:= vc_addr_table( table_index ); res:= accepted end else res:= not_found ; insert_code: (* insert new vc *) begin if ( upd_vc_table in runtimeset ) then begin if ( top_avc_index < vc_addr_l ) then begin (*t3 runtimeset:= runtimeset + (.upd_vc_table + top_avc_index.); t3*) if search_addr_code( addr_code, table_index ) then (* .. modify!!!!!! *) vc_addr_table( table_index ):= new_vc else begin top_avc_index:= top_avc_index + 1; vc_addr_table( top_avc_index ):= new_vc end end else res:= no_room (* no room in vc address table *) end else begin runtimeset:= runtimeset + (.upd_vc_table.); vc_addr_table( pvc_index ):= new_vc end end; \f remove_code: (* delete avc *) begin if search_addr_code( addr_code, table_index ) then begin if ( table_index = pvc_index ) then res:= forbidden else begin top_avc_index:= top_avc_index - 1; runtimeset:= runtimeset - (.upd_vc_table + top_avc_index.); if ( actual_vc_index > table_index ) then actual_vc_index:= actual_vc_index - 1 else if ( actual_vc_index = table_index ) then actual_vc_index:= pvc_index; (* compress *) for table_index:= table_index to top_avc_index do vc_addr_table( table_index ):= vc_addr_table( table_index + 1 ) end end else res:= not_found (* vc index not found *) end; otherwise res:= unknown_update end (* case update *) end; (* lock *) \f r_w_tec: rw_param( t_e_counter ); read_package_count: rw_param( package_count ); r_w_service_limit: rw_param( service_limit ); r_w_s_a_limit: rw_param( s_a_limit ); r_w_max_succ_t_e: rw_param( max_succ_t_e ); (*t3 dump_st_off, dump_st_on: begin dump_state:= ( msg^.u4 <> dump_st_off ); if dump_state then dump_state_block( " state block", ord( conversation ) ); return( msg ) end; t3*) otherwise garbage_message( msg,(*t3 "exec conn op", t3*) unknown_opcode ); end; (* case operation code *) finish_message( msg, dummy_macro, dummy, actual_vc_index, at_route, (**) operation_code, 0 + block_size, res, override ) end; (* procedure exec_conn_operation *) \f procedure finish_conversation; (********************************************************************************* * description : Takes the approbiate action in relation to a received * response from DRIVER (AT) * globals : alarm_msg = nil or holding a message * driver_mes = nil or holding driver message * runtimeset = updated * current = updated * block_size = updated * conversation = updated * vc_addr_table = unchanged * actual_vc_index = updated * state_bit = updated *********************************************************************************) begin (*t3 runtimeset:= runtimeset - (.ord( conversation ) + cnv_offs.); t3*) if ( t_e_kind <> no_error ) then begin case conversation of busy: conversation:= idle; testi, teste, control, coll_alarm1, coll_alarm2: if ( no_succ_t_e < max_succ_t_e ) then (* try to get through with the last telegram *) send_telegram( dummy, dummy, ( ( no_succ_t_e > 1 ) and ( t_e_kind = ill_opc ) ), (**) ( t_e_kind <> no_error ) ) else begin conversation:= idle; with vc_addr_table( actual_vc_index ) do finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, (**) at_route1, au_alarm_opc, ( current - 1 ), data_incomplete, (**) ( vc_addr_table( pvc_index ).vc_index <> vc_index ) ); current:= 1 end; otherwise end (* case conversation *) end else \f begin (* not transmission error *) case at_op_code of p_ack: conversation:= idle; au_alarm: with vc_addr_table( actual_vc_index ) do begin if ready_byte_msg( alarm_msg, at_data, current , block ) then begin (* au alarm is collected *) with vc_addr_table( actual_vc_index ) do finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, (**) at_route1, au_alarm_opc, block, accepted, (**) ( vc_addr_table( pvc_index ).vc_index <> vc_index ) ); if ( conversation = coll_alarm2 ) then conversation:= idle else begin (* poll immediately *) conversation:= coll_alarm2; send_telegram( poll_opc, poll_byte, (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ) end end else begin (* collect multi byte alarm *) if ( conversation <> coll_alarm2 ) then conversation:= coll_alarm1; send_telegram( poll_opc, poll_byte, (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ) end end; \f addr: begin if not nil( alarm_msg ) then (* finish not completed alarm *) begin with vc_addr_table( actual_vc_index ) do finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, at_route1, au_alarm_opc, (**) ( current - 1 ), data_incomplete, (**) ( vc_addr_table( pvc_index ).vc_index <> vc_index ) ); current:= 1 end; if not search_addr_code( at_data, actual_vc_index ) then actual_vc_index:= pvc_index; (* send a poll immediately *) begin conversation:= busy; send_telegram( poll_opc, poll_byte, (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ) end end; \f state: begin if not nil( alarm_msg ) then (* finish not completed alarm *) begin with vc_addr_table( actual_vc_index ) do finish_message( alarm_msg, dummy_macro, dummy, actual_vc_index, at_route1, au_alarm_opc, (**) ( current - 1 ), data_incomplete, (**) ( vc_addr_table( pvc_index ).vc_index <> vc_index ) ); current:= 1 end; lock driver_msg as locvar: state_byte do begin runtimeset:= runtimeset + (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) - (.unused..batt_supply.) + locvar; if ready_byte_msg( alarm_msg, at_data, current, 1 ) then finish_message( alarm_msg, dummy_macro, dummy, pvc_index, at_route1, state_alarm, 1, (**) accepted, override ); if ( runtimeset >= (.batt_limit, batt_supply.) ) then runtimeset:= runtimeset - (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) else if ( (.serif_error, au_error.) * runtimeset ) <> (..) then runtimeset:= runtimeset - (.ts_cntrl, group_cntrl, ts_teste.) else if ( hs_error in runtimeset ) then runtimeset:= runtimeset - (.ts_teste.); end; (* lock driver_msg *) conversation:= idle end; \f d_ack, t_ack, e_ack: if ready_byte_msg( ath_msg, at_data, current, block_size ) then (* send result of control, testi1, testi2, teste to ATH *) begin finish_message( ath_msg, dummy_macro, dummy, actual_vc_index, at_route, (**) ( ath_msg^.u4 + receipt ), block_size, accepted, override ); conversation:= idle end else (* multi byte control: send the next data_byte *) lock ath_msg as locvar: byte_msg_format do with locvar do send_telegram( atc_cntrl, datapart( current ), (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ); (* end lock ath_msg *) otherwise end (* case at_op_code *) end; (*t3 runtimeset:= runtimeset + (.ord( conversation ) + cnv_offs.) t3*) end; (* procedure finish_conversation *) \f procedure restrict_protocol; (********************************************************************************* * description : Handles the situation, where ATC isn't allowed to run the * full protocol against AT. The reason being either: * initiating, stop activity or service_poll ordered from DC or * the following state errors in AT: serif, au, hs or * battery supply + limit * globals : all globals may be used *********************************************************************************) var temp_msg : reference; res : result_range := accepted; begin repeat (* until 'full' runtimeset *) if ( conversation = idle ) then begin while ( conversation = idle ) and ( open( queue_sem.w^ ) or not nil( ath_msg ) ) do begin if nil( ath_msg ) then repeat wait( ath_msg, queue_sem.w^ ); if ( ath_msg^.u3 = dummy_route ) then return( ath_msg ) until passive( queue_sem.w^ ) or not nil( ath_msg ); if not nil( ath_msg ) then begin if ( ath_msg^.u4 in runtimeset ) then initiate_conversation( ath_msg ) else begin if ( ts_newactivity in runtimeset ) then begin if ( service_poll in runtimeset ) then res:= forbidden else begin if ( no_succ_t_e >= max_succ_t_e ) then res:= transmit_error else res:= state_error end end else res:= passivated; finish_message( ath_msg, dummy_macro, dummy, actual_vc_index, at_route, (**) ( ath_msg^.u4 + receipt ), 0, res, override ) end end end; if ( conversation = idle ) then if ( ts_newactivity in runtimeset ) and not nil( delay_msg ) then begin conversation:= busy; send_telegram( poll_opc, poll_byte, (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ) end end; \f wait( atc_msg, main_sem.w^ ); (*t3 testout( z, "PROTL. route", atc_msg^.u3 ); t3*) (*t3 if dump_state then dump_state_block( "PROTL.RESTR.", atc_msg^.u4 ); t3*) if ownertest( delay_pool, atc_msg ) then delay_msg :=: atc_msg (* hold the message *) else case atc_msg^.u3 of (* message origin *) dummy_route: return( atc_msg ); netc_route: (* message from ATH *) if atc_msg^.u4 in (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) then signal( atc_msg, queue_sem.s^ ) else (* execute the operations that doesn't involve DRIVER *) exec_conn_operation( atc_msg ); \f at_route: (* message from DRIVER *) begin (*t3 runtimeset:= runtimeset - (.ord( conversation ) + cnv_offs.); t3*) driver_msg :=: atc_msg; (* hold message *) if ( driver_ready in runtimeset ) then begin if ( ts_newactivity in runtimeset ) then begin transm_cntrl( at_op_code, at_data, valid_response( conversation ) ); if ( runtimeset >= (.batt_limit, batt_supply.) ) then begin if ( t_e_kind = no_error ) and ( at_op_code = state ) then finish_conversation else conversation:= idle end else begin finish_conversation; end end else conversation:= idle end else begin runtimeset:= runtimeset + (.driver_ready.); conversation:= idle; (******************************************************************** * Set up the user field, that DRIVER doesn't update ********************************************************************) with driver_msg^ do u1:= write_read_at; end; (*t3 runtimeset:= runtimeset + (.ord( conversation ) + cnv_offs.) t3*) end; otherwise (* unknown route *) garbage_message( atc_msg, (*t3 "PROTL. error", t3*) unknown_route ); end (* case message origin *) until ( runtimeset >= (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste, ts_newactivity, upd_vc_table, driver_ready.) ); end; (* procedure restrict_protocol *) \f (********************************************************************************* * * AT CONNECTOR : MAIN * *********************************************************************************) begin (*t1 testopen( z, own.incname, op_sem ); t1*) (*t1 testout( z, version , al_env_version ); testout( z, "chann/addr ", ( ( channel_no * 1000 ) + own_addr ) ); t1*) runtimeset:= (..); (********************************************************************************* * Set up and send a buffer create channel to DRIVER *********************************************************************************) alloc( driver_msg, driver_pool, main_sem.s^ ); with driver_msg^ do begin u1:= create_at_ch; u2:= channel_no; u3:= at_route end; lock driver_msg as locvar: create_ch_format do begin locvar( 0 ):= at_control; locvar( 1 ):= con_lam_time end; (* lock driver_msg *) conversation:= busy; signal( driver_msg, driver_sem^ ); \f (******************************************************************************** * Allocate TIMER message with main_sem as answer- and delay_pool semaphore * as owner-semaphore ********************************************************************************) alloc( delay_msg, delay_pool, main_sem.s^ ); (******************************************************************************** * Start initialisation sequence ********************************************************************************) restrict_protocol; (******************************************************************************** * End of initialization sequence ********************************************************************************) (*t3 testout( z, "end init ", ord( conversation ) ); t3*) \f repeat (* forever........................................................................ *) if ( conversation = idle ) then begin (*t3 runtimeset:= runtimeset - (.ord( conversation ) + cnv_offs.); t3*) if not nil( ath_msg ) or open( queue_sem.w^ ) then (* ignore delay and resume the interrupted conversation or start a queued one *) begin if nil( ath_msg ) then (* message(s) in queue *) repeat wait( ath_msg, queue_sem.w^ ); if ( ath_msg^.u3 = dummy_route ) then return( ath_msg ) until passive( queue_sem.w^ ) or not nil( ath_msg ); initiate_conversation( ath_msg ) end else if not nil( delay_msg ) then begin conversation:= busy; send_telegram( poll_opc, poll_byte, (**) ( t_e_kind = ill_opc ), ( t_e_kind <> no_error ) ) end; (*t3 runtimeset:= runtimeset + (.ord( conversation ) + cnv_offs.) t3*) end; wait( atc_msg, main_sem.w^ ); (*t3 if dump_state then dump_state_block( "RUNN. route", atc_msg^.u3 ); t3*) \f if ownertest( delay_pool, atc_msg ) then delay_msg :=: atc_msg (* hold the message *) else case atc_msg^.u3 of (* message origin *) dummy_route: return( atc_msg ); netc_route: (* message from ATH *) begin if atc_msg^.u4 in (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) then signal( atc_msg, queue_sem.s^ ) else (* always execute the operations that does not involve DRIVER *) begin exec_conn_operation( atc_msg ); if not ( ts_newactivity in runtimeset ) or ( service_poll in runtimeset ) then restrict_protocol end end; at_route: (* response message from DRIVER *) begin driver_msg :=: atc_msg; (* hold message *) transm_cntrl( at_op_code, at_data, valid_response( conversation ) ); finish_conversation; if not ( runtimeset >= (.ts_cntrl, group_cntrl, ts_testi1, ts_testi2, ts_teste.) ) then restrict_protocol end; otherwise (* unknown route *) garbage_message( atc_msg, (*t3 "run error ", t3*) unknown_route ) end (* case message origin *) until forever; end. (* process atconnector*) «eof»