Google
 

Trailing-Edge - PDP-10 Archives - BB-P363B-SM_1985 - mcb/drivers/dcp.b16
There are no other files named dcp.b16 in the archive.
module DCP (	! DDCMP Protocol Processor
		ident = 'X05180',
		language (bliss16)
		) =
begin

!
!                    COPYRIGHT (c) 1980, 1981, 1982
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     This software is furnished under a license and may  be  used
!     and copied only in accordance with the terms of such license
!     and with the inclusion of the above copyright notice.   This
!     software  or any other copies thereof may not be provided or
!     otherwise made available to any other person.  No  title  to
!     and ownership of the software is hereby transferred.
!
!     The information  in  this  software  is  subject  to  change
!     without  notice  and should not be construed as a commitment
!     by DIGITAL EQUIPMENT CORPORATION.
!
!     DIGITAL assumes no responsibility for the use or reliability
!     of  its  software  on  equipment  which  is  not supplied by
!     DIGITAL.
!

!++
!
! FACILITY: MCB DDCMP Protocol Driver
!
! ABSTRACT:
!
!	This module contains the DDCMP protocol routines.
!
! ENVIRONMENT: MCB V3.2
!
! AUTHOR: Alan D. Peckham	CREATION DATE: 1-Jul-81
!
! MODIFIED BY:
!
!	Alan D. Peckham, 1-Jul-81: Version 5
! 01	- Rewritten in BLISS
! 02	- Rewrite driver control code to insure device stop requests
!	  are performed.
! 03	- Dot bug in CHANGE_PROTOCOL_STATE.
!	  Wrong event class for maintenance "load me" notification.
!	  Wrong event types for threshold notifications.
! 04	- Fix to insure that there is only one control CCB to driver
!	  at any one timer (confuses the KDP driver).
! 05	- The last fix did not catch all cases in SET_DEVICE.
! 06	- Do not set half duplex in maintenance.
! 07	- Fix REP timer bug in DCPXCP.
! 08	- Fix state reporting.
! 09	- Out-of-range acks should not dump a data message.
! 10	- Update to NM V3.0.0 .
! 11	- Remove 'counters zeroed' event in DCPNMX.
! 12	- Fix event number for MOP requested event.
! 13	- Get KDP parameters from PLL.
! 14	- De-commit half-duplex.
! 15	- Do not use select timer when in FDX maintenance mode.
! 16	- Poke KDP DEVTYPE in maintenance messages that need it.
! 17	- Handle change in NMX interface in DCPINI.
! 18	- Modify CTLSTR to return the CIRCUIT COST to XPT in C_PRM1.
!--
!
! INCLUDE FILES:
!

library 'MCBLIB';

library 'XPORTX';

library 'NMXLIB';

$SHOW (NONE)
require 'DLLLIB';

library 'DCPDAT';

!
! TABLE OF CONTENTS:
!

linkage
    DCP_CCB_DB = jsr (register = 4, register = 5) :
	nopreserve (0, 1, 2, 3, 4),
    DCP_CCB_DB_STS = jsr (register = 4, register = 5, register = 3) :
	nopreserve (0, 1, 2, 3, 4),
    DCP_CCB = jsr (register = 4) :
	nopreserve (0, 1, 2, 3),
    DCP_CTR = jsr (register = 0),
    DCP_DB = jsr (register = 5) :
	nopreserve (0, 1, 2, 3, 4),
    DCP_DB_N0 = jsr (register = 5) :
	preserve (0),
    DCP_DB_CCB = jsr (register = 5, register = 4) :
	nopreserve (0, 1, 2, 3),
    DCP_DB_CCB_N0 = jsr (register = 5, register = 4) :
	preserve (0) nopreserve (3),
    DCP_DB_CCBR = jsr (register = 5, register = 4) :
	nopreserve (0, 1, 2, 3, 4),
    DCP_DB_CCB_HDR = jsr (register = 5, register = 4; register = 4) :
	nopreserve (0, 1, 2, 3),
    DCP_DB_CTR_STS = jsr (register = 5, register = 0, register = 3) :
	nopreserve (0, 1, 2, 3),
    DCP_DB_STS = jsr (register = 5, register = 3) :
	nopreserve (0, 1, 2, 3);

forward routine
    BUILD_CONTROL_MESSAGE : DCP_DB,
    BUILD_DATA_MESSAGE : DCP_DB_CCBR,
    BUILD_MAINTENANCE_MESSAGE : DCP_DB_CCBR,
    BUMP_8_BIT_COUNTER : DCP_CTR novalue,
    CCPGET : MCB_DB_CCB novalue,
    CCPSET : MCB_DB_CCB novalue,
    CCPSTP : MCB_DB_CCB novalue,
    CCPSTR : MCB_DB_CCB novalue,
    CHANGE_PROTOCOL_STATE : DCP_DB novalue,
    CKACK : DCP_DB,
    CKREP : DCP_DB novalue,
    CTLSTP : MCB_DB_CCB novalue,
    CTLSTR : MCB_DB_CCB novalue,
    DCPCCP : MCB_DB_CCB_MOD novalue,
    DCPCTL : MCB_DB_CCB_MOD novalue,
    DCPKCP : MCB_DB_CCB novalue,
    DCPRCE : MCB_DB_CCB novalue,
    DCPRCP : MCB_DB_CCB novalue,
    DCPTIM : MCB_DB_CCB_MOD novalue,
    DCPXCP : MCB_DB_CCB novalue,
    DCPXME : MCB_DB_CCB_MOD novalue,
    ENTER_MAINTENANCE : MCB_DB_CCB novalue,
    HEADER_CCB : DCP_DB_CCB_HDR,
    HEADER_FORMAT_ERROR : DCP_DB novalue,
    IGNORE_MESSAGE : DCP_DB novalue,
    INITIALIZE_LINK : MCB_DB_CCB novalue,
    MESSAGE_LENGTH : DCP_CCB,
    PROCESS_ACK_MESSAGE : DCP_DB novalue,
    PROCESS_CONTROL_MESSAGE : DCP_DB_CCBR novalue,
    PROCESS_DATA_MESSAGE : DCP_DB_CCBR novalue,
    PROCESS_MAINTENANCE_MESSAGE : DCP_DB_CCBR novalue,
    PROCESS_NAK_MESSAGE : DCP_DB novalue,
    PROCESS_REP_MESSAGE : DCP_DB novalue,
    PROCESS_SELECT_FLAG : DCP_DB novalue,
    PROCESS_STACK_MESSAGE : DCP_DB novalue,
    PROCESS_START_MESSAGE : DCP_DB novalue,
    RECORD_DRIVER_ERROR : DCP_DB_CCB novalue,
    RECORD_NAK_REASON : DCP_DB novalue,
    RESYNCHRONIZE : DCP_DB novalue,
    RETRANSMIT_UNACKED_MESSAGES : DCP_DB novalue,
    RETURN_ACKED_MESSAGES : DCP_DB novalue,
    SCHEDULE_PERSISTENT_AST : DCP_CCB_DB novalue,
    SCHEDULE_RECEIVE : DCP_CCB_DB novalue,
    SCHEDULE_STATE_AST : DCP_CCB_DB novalue,
    SCHEDULE_TRANSIENT_AST : DCP_CCB_DB novalue,
    SCHEDULE_TRANSMIT : DCP_CCB_DB_STS novalue,
    SEND_DATA : DCP_DB novalue,
    SEND_PERSISTENT_ERROR : DCP_DB_STS novalue,
    SEND_STATE : DCP_DB novalue,
    SEND_TRANSIENT_ERROR : DCP_DB_STS novalue,
    SET_DEVICE : DCP_DB novalue,
    SET_LINK : DCP_DB novalue,
    STARCE : DCP_DB_CCBR novalue,
    START_DEVICE : DCP_CCB_DB novalue,
    STOP_DEVICE : DCP_CCB_DB novalue,
    STOP_LINK : MCB_DB_CCB novalue,
    SYNCHRONIZE : DCP_DB_CCB_N0 novalue,
    TERMINATE_SELECTION_INTERVAL : DCP_DB novalue,
    TEST_RECEIVE_THRESHOLD : DCP_DB_N0 novalue,
    TEST_THRESHOLD : DCP_DB_CTR_STS novalue,
    TEST_TRANSMIT_THRESHOLD : DCP_DB_N0 novalue,
    TEST_SELECT_THRESHOLD : DCP_DB_N0 novalue,
    TIMCCB : MCB_DB_CCB novalue,
    TIMLTM : MCB_DB novalue,
    TIMPWF : MCB_DB novalue,
    TRANSMIT : MCB_DB_CCB novalue;

global bind routine
    TSTTH = TEST_TRANSMIT_THRESHOLD : DCP_DB novalue;

!
! MACROS:
!

macro
    $SIGNED (FLD0, FLD1, FLD2, FLD3) =
	%if %null (FLD1)
	%then
	    %fieldexpand (FLD0, 0),
	    %fieldexpand (FLD0, 1),
	    %fieldexpand (FLD0, 2)
	%else
	    FLD0, FLD1, FLD2
	%fi, 1 %;

macro
    FLUSH_QUEUE (QUEUE, RETURN_CALL) =
	while 1 eql 1 do
	    begin

	    local
		_DCP_CCB : ref block field (C_FIELDS);

	    if not CMQRM$ (QUEUE, _DCP_CCB) then exitloop;

	    RETURN_CALL (._DCP_CCB %if not %null (%remaining) %then , %remaining %fi);
	    end %;

!
! EQUATED SYMBOLS:
!

literal
    TRUE = 1 EQL 1,
    FALSE = 1 EQL 0,
    NO_OPERATION = 0;

literal
    LCL = 0,
    RMT = 1;

macro
    C_HANDLE = %fieldexpand (C_LIN, 0), 0, %bpval, 0 %;

global literal
    %name ('D.LEN') = D_LENGTH*%upval;

!
! OWN STORAGE:
!

external routine
    $DSPCR : novalue;

$MCB_PROCESS (
    NAME = DCP,
    DLC_DISPATCH = TABLE$ ($DSPCR, FC_CCP,
	(FC_CTL, DCPCTL),
	(FC_XME, DCPXME),
	(FC_RCE, DCPRCE),
	(FC_TIM, DCPTIM),
	(FC_XCP, DCPXCP),
	(FC_RCP, DCPRCP),
	(FC_KCP, DCPKCP),
	(FC_CCP, DCPCCP)));

!
! EXTERNAL REFERENCES:
!

linkage
    DDM_CCB = jsr (register = 4) : nopreserve (4);

external routine
    DCPNM : DCP_DB_CCBR novalue,
    TIMPIN : MCB_DB novalue;

external
    MCB$GAW_PROCESS_DATA_BASE : vector [2],
    MCB$GW_PROCESS_HANDLE;

bind
    DB_BIAS = MCB$GAW_PROCESS_DATA_BASE [0];

macro
    GET_DCP_DATA_BASE (NAME) =
	%if %declared (NAME)
	%then map NAME : ref
	%else bind NAME = .MCB$GAW_PROCESS_DATA_BASE [1] :
	%fi block field (D_FIELDS); %;
routine BUILD_CONTROL_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS),
	PTR;

    if (PTR = HEADER_CCB (DB [D_TIM], 0; CCB)) eqla 0 then return .PTR;

    ch$wchar_a (CM_ENQ, PTR);

    selectone TRUE of
	set
	[.DB [SS_SEND_STACK]] :
	    begin
	    DB [SS_SEND_STACK] = FALSE;
	    DB [SS_START_REP_TIMER] = TRUE;
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    ch$wchar_a (MT_STK, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (1, PTR);

	    if .DB [L_PROTOCOL] eql DP_DMC then SYNCHRONIZE (DB [D_TIM], .CCB);

	    end;
	[.DB [SS_SEND_START]] :
	    begin
	    DB [SS_SEND_START] = FALSE;
	    DB [SS_START_REP_TIMER] = TRUE;
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    ch$wchar_a (MT_STR, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (1, PTR);

	    if .DB [L_PROTOCOL] eql DP_DMC then SYNCHRONIZE (DB [D_TIM], .CCB);

	    end;
	[.DB [SS_SEND_NAK]] :
	    begin
	    DB [SS_SEND_NAK] = FALSE;
	    ch$wchar_a (MT_NAK, PTR);
	    ch$wchar_a (.DB [S_PENDING_NAK_REASON], PTR);
	    ch$wchar_a (.DB [S_R], PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (1, PTR);
	    SYNCHRONIZE (DB [D_TIM], .CCB);
	    end;
	[.DB [SS_SEND_REP]] :
	    begin
	    DB [SS_SEND_REP] = FALSE;
	    ch$wchar_a (MT_REP, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (.DB [S_N], PTR);
	    ch$wchar_a (1, PTR);
	    SYNCHRONIZE (DB [D_TIM], .CCB);
	    end;
	[.DB [SS_SEND_ACK]] :
	    begin
	    DB [SS_SEND_ACK] = FALSE;
	    ch$wchar_a (MT_ACK, PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (.DB [S_R], PTR);
	    ch$wchar_a (0, PTR);
	    ch$wchar_a (1, PTR);

	    if .DB [L_PROTOCOL] eql DP_DMC then SYNCHRONIZE (DB [D_TIM], .CCB);

	    end;
	tes;

    if .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] neqa 0
    then
	CCB [C_PRM4] = .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_LAST)];

    $MCB_QUEUE_CCB (DB [L_PRE_TRANSMIT], .CCB);
    DB [S_MOTD] = .DB [S_MOTD] + 1;
    .PTR
    end;			!of routine BUILD_CONTROL_MESSAGE
routine BUILD_DATA_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	DCCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS),
	CNT,
	PTR;

    if (PTR = HEADER_CCB (DB [D_TIM], .DCCB; CCB)) eqla 0 then return .PTR;

    DB [SS_SEND_ACK] = FALSE;
    DB [L_MESSAGES_AT_DRIVER] = .DB [L_MESSAGES_AT_DRIVER] + 1;
    CNT = MESSAGE_LENGTH (.CCB);

    if .DB [S_N] eqlu .DB [S_TM1]
    then
	begin
	DB [S_N] = .DB [S_N] + 1;
	COUNTER_ADD (DB, S_BYTES_TRANSMITTED, .CNT);
	COUNTER_INCREMENT (DB, S_DATA_BLOCKS_TRANSMITTED);
	end;

    DB [S_TM1] = .DB [S_TM1] + 1;
    ch$wchar_a (CM_SOH, PTR);
    ch$wchar_a (.CNT <0, 8>, PTR);
    ch$wchar_a (.CNT <8, 8>, PTR);
    ch$wchar_a (.DB [S_R], PTR);
    ch$wchar_a (.DB [S_TM1], PTR);
    ch$wchar_a (1, PTR);

    if .DB [L_PROTOCOL] eql DP_DMC then SYNCHRONIZE (DB [D_TIM], .CCB);

    if .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] neqa 0
    then
	CCB [C_PRM4] = .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_LAST)];

    $MCB_QUEUE_CCB (DB [L_PRE_TRANSMIT], .CCB);
    DB [S_MOTD] = .DB [S_MOTD] + 1;
    .PTR
    end;			!of routine BUILD_DATA_MESSAGE
routine BUILD_MAINTENANCE_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	DCCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS),
	CNT,
	PTR;

    if (PTR = HEADER_CCB (DB [D_TIM], .DCCB; CCB)) eqla 0 then return .PTR;

    DB [SS_SEND_SELECT] = TRUE;
    DB [L_MESSAGES_AT_DRIVER] = .DB [L_MESSAGES_AT_DRIVER] + 1;
    CNT = MESSAGE_LENGTH (.CCB);
    ch$wchar_a (CM_DLE, PTR);
    ch$wchar_a (.CNT <0, 8>, PTR);
    ch$wchar_a (.CNT <8, 8>, PTR);
    ch$wchar_a (0, PTR);
    ch$wchar_a (0, PTR);
    ch$wchar_a (1, PTR);
    SYNCHRONIZE (DB [D_TIM], .CCB);

    if .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] neqa 0
    then
	CCB [C_PRM4] = .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_LAST)];

    $MCB_QUEUE_CCB (DB [L_PRE_TRANSMIT], .CCB);
    DB [S_MOTD] = .DB [S_MOTD] + 1;
    .PTR
    end;			!of routine BUILD_MAINTENANCE_MESSAGE
routine BUMP_8_BIT_COUNTER

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CTR : ref block)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CTR novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    CTR [0, 0, 8, 0] = .CTR [0, 0, 8, 0] + 1;

    if .CTR [0, 0, 8, 0] eql 0
    then
	CTR [0, 0, 8, 0] = .CTR [0, 0, 8, 0] - 1;

    end;			!of routine BUMP_8_BIT_COUNTER
routine CCPGET

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [K_REGISTER] = .CCB [C_PRM1];
    DB [D_REGISTER] = .CCB [C_PRM2];
    DB [K_VECTOR] = .CCB [C_PRM3];
    DB [K_PRIORITY] = .CCB [C_PRM4];
    $MCB_RETURN_CCB (.CCB);
    end;			!of routine CCPGET
routine CCPSET

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    external routine
	$DDSTR : DDM_CCB novalue;

    $DDSTR (.CCB);
    end;			!of routine CCPSET
routine CCPSTP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    $MCB_RETURN_CCB (.CCB);
    DB [SS_DEVICE_BEING_SET] = FALSE;
    FLUSH_QUEUE (DB [S_WAITING_FOR_ACK],
	%quote SCHEDULE_TRANSMIT, DB [D_TIM], DLL$_ABORTED);
    FLUSH_QUEUE (DB [S_WAITING_FOR_TRANSMIT],
	%quote SCHEDULE_TRANSMIT, DB [D_TIM], DLL$_ABORTED);
    SET_DEVICE (DB [D_TIM]);
    end;			!of routine CCPSTP
routine CCPSTR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    $MCB_RETURN_CCB (.CCB);
    DB [SS_DEVICE_BEING_SET] = FALSE;
    DB [LS_STATION_ENABLED] = TRUE;
    DB [SS_DEVICE_RUNNING] = TRUE;
    SET_DEVICE (DB [D_TIM]);
    end;			!of routine CCPSTR
routine CHANGE_PROTOCOL_STATE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	STATE,
	REASON)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if .DB [S_PROTOCOL_STATE] eql .STATE then return;

    $NM_DLL_EVENT (.REASON, .DB [S_CIRCUIT_ENTITY],
	PARAMETER_C_1 (0, DB [S_PROTOCOL_STATE]),
	DB [S_PROTOCOL_STATE] = .STATE,
	PARAMETER_C_1 (1, DB [S_PROTOCOL_STATE]));
    SEND_STATE (DB [D_TIM]);
    end;			!of routine CHANGE_PROTOCOL_STATE
routine CKACK

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB =
!
! SIDE EFFECTS:
!	None
!--

    begin

    field
	NUM = [0, 0, 8, 0];

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    local
	LAST_ACK : block [1] field (NUM),
	NUM_ACKED : block [1] field (NUM),
	NUM_SENT : block [1] field (NUM);

    LAST_ACK = .DB [$SIGNED (S_A)];
    NUM_ACKED = .HEADER [$SIGNED (H_RESP)];

    if .LAST_ACK [NUM] eql .NUM_ACKED [NUM]
    then
	begin

	if .LAST_ACK [NUM] eql .DB [S_N] then DB [S_TRANSMIT_THRESHOLD] = 7;

	return TRUE
	end;

    NUM_ACKED = .NUM_ACKED - .LAST_ACK;
    NUM_SENT = .DB [$SIGNED (S_N)];
    NUM_SENT = .NUM_SENT - .LAST_ACK;

    if .NUM_SENT [NUM] lssu .NUM_ACKED [NUM]
    then
	return FALSE;

    DB [S_A] = .HEADER [H_RESP];
    RETURN_ACKED_MESSAGES (DB [D_TIM]);
    return TRUE
    end;			!of routine CKACK
routine CKREP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [SS_START_REP_TIMER] = FALSE;
    DB [SS_TIMING_REP] = FALSE;

    if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

    if
	begin

	field
	    NUM = [0, 0, 8, 0];

	local
	    NUM_NOT_ACKED : block [1] field (NUM),
	    NUM_NOT_TRANSMITTED : block [1] field (NUM);

	NUM_NOT_TRANSMITTED = .DB [$SIGNED (S_N)];
	NUM_NOT_ACKED = .NUM_NOT_TRANSMITTED;
	NUM_NOT_TRANSMITTED = .NUM_NOT_TRANSMITTED - .DB [$SIGNED (S_X)];
	NUM_NOT_ACKED = .NUM_NOT_ACKED - .DB [$SIGNED (S_A)];
	.NUM_NOT_ACKED [NUM] gtru .NUM_NOT_TRANSMITTED [NUM]
	end
    then

	if .DB [L_DUPLEX] eql DL_FULL
	then
	    begin
	    DB [SS_TIMING_REP] = TRUE;
	    DB [D_TIM] = .DB [L_RETRANSMIT_TIMER];
	    end
	else
	    DB [SS_START_REP_TIMER] = TRUE;

    end;			!of routine CKREP
routine CTLSTP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [SS_NOTIFY_STATE] = FALSE;
    DB [S_TRANSIENT_ERROR] = 0;
    DB [S_PERSISTENT_ERROR] = 0;
    DB [S_USER_HANDLE] = 0;
    CCB [C_FNC] = FC_CCP;
    CCB [C_STS] = DLL$_SUCCESS;

    if .DB [D_USER_BUFFERS] eql 0
    then
	$MCB_SCHEDULE_CCB (.CCB)
    else
	DB [S_CONTROL_CCB] = .CCB;

    end;			!of routine CTLSTP
routine CTLSTR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	STATUS = TABLE$ (0, 0,
	    (SS_HALTED^1, DLL$_STATE_OFF),
	    (SS_ISTRT^1, DLL$_STATE_SYNCHRONIZING),
	    (SS_ASTRT^1, DLL$_STATE_SYNCHRONIZING),
	    (SS_RUNNING^1, DLL$_STATE_RUNNING),
	    (SS_MAINTENANCE^1, DLL$_STATE_MAINTENANCE)) : vector;

    DB [S_USER_HANDLE] = .CCB [C_HANDLE];

    if .CCB [C_PRM1] eql 0
    then
	CCB [C_PRM1] = .DB [S_CIRCUIT_COST];

    CCB [C_STS] = .STATUS [.DB [S_PROTOCOL_STATE]];
    CCB [C_FNC] = FC_CCP;
    $MCB_SCHEDULE_CCB (.CCB);
    end;			!of routine CTLSTR
routine CURRENT_STATUS (DB) : LINKAGE_DB =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!	DB = address of DCP data base.
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    GET_DCP_DATA_BASE (DB)

    literal
	DLL_OFF = 0,
	DLL_SYNCHRONIZING = 1,
	DLL_RUNNING = 2,
	DLL_MAINTENANCE = 3;

    bind
	STATUS = TABLE$ (0, 0,
	    (SS_HALTED^1, DLL_OFF),
	    (SS_ISTRT^1, DLL_SYNCHRONIZING),
	    (SS_ASTRT^1, DLL_SYNCHRONIZING),
	    (SS_RUNNING^1, DLL_RUNNING),
	    (SS_MAINTENANCE^1, DLL_MAINTENANCE)) : vector,
	DLL_STATUS = TABLE$ (0, 0,
	    (DLL_OFF^1, DLL$_STATE_OFF),
	    (DLL_SYNCHRONIZING^1, DLL$_STATE_SYNCHRONIZING),
	    (DLL_RUNNING^1, DLL$_STATE_RUNNING),
	    (DLL_MAINTENANCE^1, DLL$_STATE_MAINTENANCE)) : vector;

    if .DB [SS_NOTIFY_OFF]
    then
	begin
	DB [SS_NOTIFY_OFF] = FALSE;

	if .DB [D_REPORTED_STATE] eql DLL_OFF
	then
	    DB [SS_NOTIFY_STATE] = FALSE;

	return .DLL_STATUS [DB [D_REPORTED_STATE] = DLL_OFF];
	end;

    DB [SS_NOTIFY_STATE] = FALSE;
    .DLL_STATUS [DB [D_REPORTED_STATE] = .STATUS [.DB [S_PROTOCOL_STATE]]]
    end;			!of routine CURRENT_STATUS
routine DCPCCP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS),
	MODIFIER)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB_MOD novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, FD_TIM,
	    (FM_GET, CCPGET),
	    (FM_SET, CCPSET),
	    (FM_STR, CCPSTR),
	    (FM_STP, CCPSTP)),
	(DB [D_TIM], .CCB),
	MCB_DB_CCB);
    end;			!of routine DCPCCP
routine DCPCTL

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS),
	MODIFIER)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB_MOD novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, 0,
	    (FM_NM, DCPNM),
	    (FM_STR, CTLSTR),
	    (FM_STP, CTLSTP)),
	(DB [D_TIM], .CCB),
	MCB_DB_CCB);
    end;			!of routine DCPCTL
routine DCPKCP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    $MCB_RETURN_CCB (.CCB);
    DB [LS_RESYNCH_IN_PROGRESS] = FALSE;
    end;			!of routine DCPKCP
routine DCPRCE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    STARCE (DB [D_TIM], .CCB);
    DB [D_USER_BUFFERS] = .DB [D_USER_BUFFERS] - 1;

    if .DB [D_USER_BUFFERS] neq 0 then return;

    if .DB [S_CONTROL_CCB] neqa 0
    then
	begin
	$MCB_SCHEDULE_CCB (.DB [S_CONTROL_CCB]);
	DB [S_CONTROL_CCB] = 0;
	end;

    end;			!of routine DCPRCE
routine DCPRCP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    !
    ! Copy the header and adjust the buffer pointer
    !
    begin

    map
	HEADER : vector [H_LENGTH];

    local
	HDR_0, HDR_1, HDR_2;

    begin

    local
	SAVE_MAP;

    SMAP$ (SAVE_MAP);
    MAP$ (.CCB [C_BIAS]);
    begin

    local
	PTR : ref vector;

    PTR = .CCB [C_ADDR];
    HDR_0 = .PTR [0];
    HDR_1 = .PTR [1];
    HDR_2 = .PTR [2];
    CCB [C_ADDR] = PTR = PTR [3];
    CCB [C_CNT] = .CCB [C_CNT] - H_LENGTH*%upval;
    end;
    MAP$ (.SAVE_MAP);
    end;
    begin

    local
	PTR : ref vector;

    PTR = HEADER [0];
    PTR [0] = .HDR_0;
    PTR [1] = .HDR_1;
    PTR [2] = .HDR_2;
    PTR = PTR [2]; %(force auto-increment)%
    end;
    end;
    !
    ! Toss if we are re-synchronizing or halted
    !
    if .DB [LS_RESYNCH_IN_PROGRESS] or (.DB [S_PROTOCOL_STATE] eql SS_HALTED)
    then
	begin
	STARCE (DB [D_TIM], .CCB);
	return;
	end;

    if (.CCB [C_STS] geq 0) or (.CCB [C_STS] eql CE_DCR)
    then
	begin

	selectone .HEADER [H_IDENTIFIER] of
	    set
	    [CM_ENQ] : PROCESS_CONTROL_MESSAGE (DB [D_TIM], .CCB);
	    [CM_SOH] : PROCESS_DATA_MESSAGE (DB [D_TIM], .CCB);
	    [CM_DLE] : PROCESS_MAINTENANCE_MESSAGE (DB [D_TIM], .CCB);
	    [otherwise] :
		begin
		HEADER_FORMAT_ERROR (DB [D_TIM]);
		STARCE (DB [D_TIM], .CCB);
		end;
	    tes;

	end
    else
	begin
	!
	! There was an error in message reception -
	! record where appropriate.
	!
	RECORD_DRIVER_ERROR (DB [D_TIM], .CCB);
	STARCE (DB [D_TIM], .CCB);
	end;

    SEND_DATA (DB [D_TIM]);
    end;			!of routine DCPRCP
routine DCPTIM

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS),
	MODIFIER)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB_MOD novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, FD_TIM,
	    (FM_LTM, TIMLTM),
	    (FM_PWF, TIMPWF),
	    (FM_PIN, TIMPIN),
	    (FM_CCB, TIMCCB)),
	(DB [D_TIM], .CCB),
	MCB_DB_CCB);
    end;			!of routine DCPTIM
routine DCPXCP

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    begin

    map
	HEADER : vector [H_LENGTH];

    local
	PTR : ref vector;

    PTR = .CCB [C_ADDR];
    HEADER [0] = .PTR [0];
    HEADER [1] = .PTR [1];
    HEADER [2] = .PTR [2];
    PTR = PTR [2]; %(force auto-increment)%
    end;
    !
    ! If a data message, put it in the proper place
    !
    if .HEADER [H_IDENTIFIER] neq CM_ENQ
    then
	begin
	DB [L_MESSAGES_AT_DRIVER] = .DB [L_MESSAGES_AT_DRIVER] - 1;

	if .HEADER [H_IDENTIFIER] eql CM_SOH
	then
	    begin
	    $MCB_QUEUE_CCB (DB [S_WAITING_FOR_ACK], .CCB [C_STK]);
	    RETURN_ACKED_MESSAGES (DB [D_TIM]);
	    end
	else
	    SCHEDULE_TRANSMIT (.CCB [C_STK], DB [D_TIM], DLL$_SUCCESS);

	end;

    $MCB_RETURN_CCB (.CCB);
    !
    ! One less message at the driver
    !
    DB [S_MOTD] = .DB [S_MOTD] - 1;

    if .DB [S_MOTD] eql 0
    then

	if .DB [SS_RETRANSMIT] then RETRANSMIT_UNACKED_MESSAGES (DB [D_TIM]);

    !
    ! If halted, then there is nothing else to do.
    !
    if .DB [S_PROTOCOL_STATE] eql SS_HALTED then return;
    !
    ! Do post-transmit processing
    !
    selectone .HEADER [H_IDENTIFIER] of
	set
	[CM_ENQ] :

	    if .HEADER [H_TYPE] eql MT_REP
	    then
		DB [SS_START_REP_TIMER] = TRUE;

	[CM_SOH] :
	    begin

	    if
		begin

		field
		    NUM = [0, 0, 8, 0];

		local
		    NUM_NOT_ACKED : block [1] field (NUM),
		    NUM_NOT_TRANSMITTED : block [1] field (NUM);

		NUM_NOT_TRANSMITTED = .DB [$SIGNED (S_N)];
		NUM_NOT_ACKED = .NUM_NOT_TRANSMITTED;
		NUM_NOT_TRANSMITTED = .NUM_NOT_TRANSMITTED -
		    (DB [S_X] = .HEADER [$SIGNED (H_NUM)]);
		NUM_NOT_ACKED = .NUM_NOT_ACKED - .DB [$SIGNED (S_A)];
		.NUM_NOT_ACKED [NUM] gtru .NUM_NOT_TRANSMITTED [NUM]
		end
	    then
		begin

		if not (.DB [SS_START_REP_TIMER] or .DB [SS_TIMING_REP])
		then
		    DB [SS_START_REP_TIMER] = TRUE;

		end
	    else
		begin
		DB [SS_START_REP_TIMER] = FALSE;
		DB [SS_TIMING_REP] = FALSE;

		if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

		end;

	    end;
	tes;
    !
    ! Start the rep timer if asked
    !
    if .DB [SS_START_REP_TIMER]
    then
	begin
	DB [SS_START_REP_TIMER] = FALSE;
	DB [SS_TIMING_REP] = TRUE;

	if .DB [L_DUPLEX] eql DL_FULL
	then DB [D_TIM] = .DB [L_RETRANSMIT_TIMER];

	end;
    !
    ! Process select flag if appropriate
    !
    if .DB [L_DUPLEX] neq DL_FULL
    then

	if .HEADER [H_SELECT]
	then
	    begin
	    COUNTER_INCREMENT (DB, S_SELECTION_INTERVALS);
	    DB [D_TIM] = .DB [L_RETRANSMIT_TIMER];
	    end;
    !
    ! Send more data
    !
    SEND_DATA (DB [D_TIM]);
    end;			!of routine DCPXCP
routine DCPXME

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS),
	MODIFIER)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB_MOD novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DISPATCH$ (
	.MODIFIER,
	TABLE$ ($DSPCR, 0,
	    (DLL$K_ENTER_MAINTENANCE, ENTER_MAINTENANCE),
	    (DLL$K_INITIALIZE_LINK, INITIALIZE_LINK),
	    (DLL$K_STOP_LINK, STOP_LINK),
	    (DLL$K_TRANSMIT, TRANSMIT),
	    (DLL$K_TRANSMIT_AND_TIME, TRANSMIT)),
	(DB [D_TIM], .CCB),
	MCB_DB_CCB);
    end;			!of routine DCPXME
routine ENTER_MAINTENANCE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    SET_LINK (DB [D_TIM], SS_HALTED);
    DB [DC_SET_REQUESTED_STATE] = TRUE;
    DB [S_REQUESTED_STATE] = SS_MAINTENANCE;
    SET_DEVICE (DB [D_TIM]);
    CCB [C_FNC] = FC_XCP;
    CCB [C_STS] = DLL$_SUCCESS;
    $MCB_SCHEDULE_CCB (.CCB);
    end;			!of routine ENTER_MAINTENANCE
routine HEADER_CCB

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	STACK_CCB : ref block field (C_FIELDS);
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCB_HDR =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if not $MCB_GET_CCB (CCB) then return 0;

    CCB [C_CHN] = CCB [C_STK] = .STACK_CCB;
    CCB [C_HANDLE] = .DB [L_DRIVER_HANDLE];
    CCB [C_PRM4] = 0;
    CCB [C_CNT] = 6;
    CCB [C_BIAS] = 0;
    CCB [C_ADDR] = ch$ptr (CCB [C_PRM1])
    end;			!of routine HEADER_CCB
routine HEADER_FORMAT_ERROR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT] :
	    begin
	    DB [SS_SEND_START] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    end;
	[SS_ASTRT] :
	    begin
	    DB [SS_SEND_STACK] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    end;
	[SS_RUNNING] :
	    begin
	    DB [SS_SEND_NAK] = TRUE;
	    DB [S_PENDING_NAK_REASON] = RN_HFE;
	    DB [SS_SEND_ACK] = FALSE;
	    COUNTER_INCREMENT (DB, L_REMOTE_STATION_ERRORS);
	    COUNTER_INCREMENT (DB, LR_N17);
	    $NM_DLL_EVENT (6, .DB [S_CIRCUIT_ENTITY],
		PARAMETER_HI (2, 6, DB [L_HEADER]));
	    end;
	[inrange] :
	    NO_OPERATION;
	tes;

    end;			!of routine HEADER_FORMAT_ERROR
routine IGNORE_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT] :
	    begin
	    DB [SS_SEND_START] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    end;
	[SS_ASTRT] :
	    begin
	    DB [SS_SEND_STACK] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    end;
	[inrange] :
	    NO_OPERATION;
	tes;

    end;			!of routine IGNORE_MESSAGE
routine INITIALIZE_LINK

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    SET_LINK (DB [D_TIM], SS_HALTED);
    DB [DC_SET_REQUESTED_STATE] = TRUE;
    DB [S_REQUESTED_STATE] = SS_RUNNING;
    SET_DEVICE (DB [D_TIM]);
    CCB [C_FNC] = FC_XCP;
    CCB [C_STS] = DLL$_SUCCESS;
    $MCB_SCHEDULE_CCB (.CCB);
    end;			!of routine INITIALIZE_LINK
routine MESSAGE_LENGTH

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CNT;

    CCB = .CCB [C_CHN];
    CNT = 0;

    do (CNT = .CNT + .CCB [C_CNT]) while (CCB = .CCB [C_CHN]) neqa 0;

    .CNT
    end;			!of routine MESSAGE_LENGTH
routine PROCESS_ACK_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT] :
	    return IGNORE_MESSAGE (DB [D_TIM]);
	[SS_ASTRT] :

	    if .HEADER [H_RESP] eqlu 0
	    then
		begin
		CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_RUNNING, 1);
		DB [S_TRANSMIT_THRESHOLD] = 7;
		DB [S_RECEIVE_THRESHOLD] = 7;

		if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

		end
	    else
		return IGNORE_MESSAGE (DB [D_TIM]);

	[SS_RUNNING] :

	    if CKACK (DB [D_TIM])
	    then
		CKREP (DB [D_TIM])
	    else
		return IGNORE_MESSAGE (DB [D_TIM]);

	[SS_MAINTENANCE] :
	    NO_OPERATION;
	[inrange] :
	    return NO_OPERATION;
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_ACK_MESSAGE
routine PROCESS_CONTROL_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    CASE .HEADER [H_TYPE] from MT_LOW to MT_HIGH of
	set
	[MT_STR] : PROCESS_START_MESSAGE (DB [D_TIM]);
	[MT_STK] : PROCESS_STACK_MESSAGE (DB [D_TIM]);
	[MT_ACK] : PROCESS_ACK_MESSAGE (DB [D_TIM]);
	[MT_NAK] : PROCESS_NAK_MESSAGE (DB [D_TIM]);
	[MT_REP] : PROCESS_REP_MESSAGE (DB [D_TIM]);
	[inrange, outrange] : HEADER_FORMAT_ERROR (DB [D_TIM]);
	tes;

    STARCE (DB [D_TIM], .CCB);
    end;			!of routine PROCESS_CONTROL_MESSAGE
routine PROCESS_DATA_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ASTRT] :

	    if .HEADER [H_RESP] eqlu 0
	    then
		begin

		if
		    begin

		    local
			NEW_NUM;

		    NEW_NUM = .DB [S_R] + 1;
		    .HEADER [H_NUM] eql .NEW_NUM <0, 8>
		    end
		then
		    begin

		    if .CCB [C_STS] geq 0
		    then
			begin
			DB [S_R] = .DB [S_R] + 1;
			COUNTER_INCREMENT (DB, S_DATA_BLOCKS_RECEIVED);
			COUNTER_ADD (DB, S_BYTES_RECEIVED, .CCB [C_CNT]);
			DB [SS_SEND_ACK] = TRUE;
			DB [SS_SEND_NAK] = FALSE;
			DB [S_RECEIVE_THRESHOLD] = 7;
			CCB [C_MOD] = DLL$K_DATA_RECEIVED;
			SCHEDULE_RECEIVE (.CCB, DB [D_TIM], DLL$_SUCCESS);
			end
		    else
			begin
			RECORD_DRIVER_ERROR (DB [D_TIM], .CCB);
			STARCE (DB [D_TIM], .CCB);
			end;

		    end
		else
		    STARCE (DB [D_TIM], .CCB);

		end
	    else
		STARCE (DB [D_TIM], .CCB);

	[SS_RUNNING] :
	    begin

	    if CKACK (DB [D_TIM])
	    then
		CKREP (DB [D_TIM]);

	    if
		begin

		local
		    NEW_NUM;

		NEW_NUM = .DB [S_R] + 1;
		.HEADER [H_NUM] eql .NEW_NUM <0, 8>
		end
	    then
		begin

		if .CCB [C_STS] geq 0
		then
		    begin
		    DB [S_R] = .DB [S_R] + 1;
		    COUNTER_INCREMENT (DB, S_DATA_BLOCKS_RECEIVED);
		    COUNTER_ADD (DB, S_BYTES_RECEIVED, .CCB [C_CNT]);
		    DB [SS_SEND_ACK] = TRUE;
		    DB [SS_SEND_NAK] = FALSE;
		    DB [S_RECEIVE_THRESHOLD] = 7;
		    CCB [C_MOD] = DLL$K_DATA_RECEIVED;
		    SCHEDULE_RECEIVE (.CCB, DB [D_TIM], DLL$_SUCCESS);
		    end
		else
		    begin
		    RECORD_DRIVER_ERROR (DB [D_TIM], .CCB);
		    STARCE (DB [D_TIM], .CCB);
		    end;

		end
	    else
		STARCE (DB [D_TIM], .CCB);

	    end;
	[inrange] :
	    STARCE (DB [D_TIM], .CCB);
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_DATA_MESSAGE
routine PROCESS_MAINTENANCE_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    if .DB [L_PROTOCOL] eql DP_DMC
    then
	begin
	HEADER [H_SELECT] = TRUE;
	HEADER [H_QSYNC] = TRUE;
	end;

    if not .HEADER [H_SELECT]
    then
	HEADER_FORMAT_ERROR (DB [D_TIM]);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT, SS_RUNNING] :
	    begin
	    $NM_DLL_EVENT (96^6 + 13, .DB [S_CIRCUIT_ENTITY]);
	    SEND_PERSISTENT_ERROR (DB [D_TIM], DLL$_MAINTENANCE_RECEIVED);
	    SET_LINK (DB [D_TIM], DB [S_REQUESTED_STATE] = SS_HALTED);
	    SET_DEVICE (DB [D_TIM]);
	    STARCE (DB [D_TIM], .CCB);
	    end;
	[SS_MAINTENANCE] :
	    begin

	    if .CCB [C_STS] geq 0
	    then
		begin
		DB [S_RECEIVE_THRESHOLD] = 7;
		CCB [C_MOD] = DLL$K_MAINTENANCE_RECEIVED;
		SCHEDULE_RECEIVE (.CCB, DB [D_TIM], DLL$_SUCCESS);
		end
	    else
		begin
		COUNTER_INCREMENT (DB, L_MAINTENANCE_BCC_ERRORS);
		STARCE (DB [D_TIM], .CCB);
		end;

	    end;
	[inrange] :
	    STARCE (DB [D_TIM], .CCB);
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_MAINTENANCE_MESSAGE
routine PROCESS_NAK_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT] :
	    return IGNORE_MESSAGE (DB [D_TIM]);
	[SS_RUNNING] :

	    if CKACK (DB [D_TIM])
	    then
		begin

		if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

		RECORD_NAK_REASON (DB [D_TIM]);
		PROCESS_SELECT_FLAG (DB [D_TIM]);
		end
	    else
		return IGNORE_MESSAGE (DB [D_TIM]);

	[SS_MAINTENANCE] :
	    NO_OPERATION;
	[inrange] :
	    return NO_OPERATION;
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_NAK_MESSAGE
routine PROCESS_REP_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT] :
	    return IGNORE_MESSAGE (DB [D_TIM]);
	[SS_RUNNING] :

	    if .HEADER [H_NUM] nequ .DB [S_R]
	    then
		begin
		DB [SS_SEND_NAK] = TRUE;
		DB [S_PENDING_NAK_REASON] = RN_REP;
		DB [SS_SEND_ACK] = FALSE;
		TEST_RECEIVE_THRESHOLD (DB [D_TIM]);
		COUNTER_INCREMENT (DB, SI_N3);
		COUNTER_INCREMENT (DB, S_DATA_ERRORS_INBOUND);
		end
	    else
		begin
		DB [SS_SEND_ACK] = TRUE;
		DB [SS_SEND_NAK] = FALSE;
		COUNTER_INCREMENT (DB, S_REMOTE_REPLY_TIMEOUTS);
		end;

	[SS_MAINTENANCE] :
	    NO_OPERATION;
	[inrange] :
	    return NO_OPERATION;
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_REP_MESSAGE
routine PROCESS_SELECT_FLAG

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    if .DB [L_DUPLEX] neq DL_FULL
    then

	if .HEADER [H_SELECT]
	then
	    begin
	    DB [D_TIM] = 0;
	    DB [S_SELECT_THRESHOLD] = 7;
	    TERMINATE_SELECTION_INTERVAL (DB [D_TIM]);
	    end
	else
	    DB [D_TIM] = .DB [L_RETRANSMIT_TIMER];

    end;			!of routine PROCESS_SELECT_FLAG
routine PROCESS_STACK_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT] :
	    begin

	    if not .HEADER [H_SELECT]
	    then
		return HEADER_FORMAT_ERROR (DB [D_TIM]);

	    DB [SS_SEND_ACK] = TRUE;

	    if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

	    CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_RUNNING, 0);
	    DB [S_TRANSMIT_THRESHOLD] = 7;
	    DB [S_RECEIVE_THRESHOLD] = 7;
	    end;
	[SS_RUNNING] :
	    DB [SS_SEND_ACK] = TRUE;
	[SS_MAINTENANCE] :
	    NO_OPERATION;
	[inrange] :
	    return NO_OPERATION;
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_STACK_MESSAGE
routine PROCESS_START_MESSAGE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT] :
	    begin

	    if not .HEADER [H_SELECT]
	    then
		return HEADER_FORMAT_ERROR (DB [D_TIM]);

	    CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_ASTRT, 0);
	    DB [S_TRANSMIT_THRESHOLD] = 7;
	    DB [S_RECEIVE_THRESHOLD] = 7;
	    DB [SS_SEND_STACK] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    end;
	[SS_RUNNING] :
	    begin
	    SEND_PERSISTENT_ERROR (DB [D_TIM], DLL$_START_RECEIVED);
	    SET_LINK (DB [D_TIM], DB [S_REQUESTED_STATE] = SS_HALTED);
	    SET_DEVICE (DB [D_TIM]);
	    end;
	[SS_MAINTENANCE] :
	    $NM_DLL_EVENT (2, .DB [S_CIRCUIT_ENTITY]);
	[inrange] :
	    return NO_OPERATION;
	tes;

    PROCESS_SELECT_FLAG (DB [D_TIM]);
    end;			!of routine PROCESS_START_MESSAGE
routine RECORD_DRIVER_ERROR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    selectone .CCB [C_STS] of
	set
	[CE_DCR] :
	    if .DB [S_PROTOCOL_STATE] eql SS_RUNNING
	    then
		begin
		DB [S_PENDING_NAK_REASON] = RN_DBC;
		COUNTER_INCREMENT (DB, SI_N2);
		COUNTER_INCREMENT (DB, S_DATA_ERRORS_INBOUND);
		end
	    else
		begin
		COUNTER_INCREMENT (DB, LL_NNS);
		COUNTER_INCREMENT (DB, L_LOCAL_STATION_ERRORS);
		return;
		end;
	[CE_BUF] :
	    begin
	    DB [S_PENDING_NAK_REASON] = RN_BUF;
	    COUNTER_INCREMENT (DB, SL_N8);
	    COUNTER_INCREMENT (DB, S_LOCAL_BUFFER_ERRORS);
	    end;
	[CE_ROV] :
	    begin
	    DB [S_PENDING_NAK_REASON] = RN_ROV;
	    COUNTER_INCREMENT (DB, LL_N9);
	    COUNTER_INCREMENT (DB, L_LOCAL_STATION_ERRORS);
	    end;
	[CE_MTL] :
	    begin

	    external
		MCB$GW_RDB_SIZE;

	    $NM_DLL_EVENT (9, .DB [S_CIRCUIT_ENTITY],
		PARAMETER_DU_2 (8, MCB$GW_RDB_SIZE));
	    DB [S_PENDING_NAK_REASON] = RN_MTL;
	    COUNTER_INCREMENT (DB, SL_N16);
	    COUNTER_INCREMENT (DB, S_LOCAL_BUFFER_ERRORS);
	    end;
	[CE_HFE] :
	    begin
	    DB [S_PENDING_NAK_REASON] = RN_HBC;
	    COUNTER_INCREMENT (DB, SI_N1);
	    COUNTER_INCREMENT (DB, S_DATA_ERRORS_INBOUND);
	    end;
	[otherwise] :
	    return;
	tes;

    DB [SS_SEND_NAK] = TRUE;
    DB [SS_SEND_ACK] = FALSE;
    TEST_RECEIVE_THRESHOLD (DB [D_TIM]);
    SEND_DATA (DB [D_TIM]);
    end;			!of routine RECORD_DRIVER_ERROR
routine RECORD_NAK_REASON

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    bind
	HEADER = DB [L_HEADER] : block [H_LENGTH] field (HDR_FIELDS);

    selectone .HEADER [H_SUBTYPE] of
	set
	[RN_HBC] :
	    begin
	    COUNTER_INCREMENT (DB, SO_N1);
	    COUNTER_INCREMENT (DB, S_DATA_ERRORS_OUTBOUND);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[RN_DBC] :
	    begin
	    COUNTER_INCREMENT (DB, SO_N2);
	    COUNTER_INCREMENT (DB, S_DATA_ERRORS_OUTBOUND);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[RN_REP] :
	    begin
	    COUNTER_INCREMENT (DB, SO_N3);
	    COUNTER_INCREMENT (DB, S_DATA_ERRORS_OUTBOUND);
	    end;
	[RN_BUF] :
	    begin
	    COUNTER_INCREMENT (DB, SR_N8);
	    COUNTER_INCREMENT (DB, S_REMOTE_BUFFER_ERRORS);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[RN_ROV] :
	    begin
	    COUNTER_INCREMENT (DB, LR_N9);
	    COUNTER_INCREMENT (DB, L_REMOTE_STATION_ERRORS);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[RN_MTL] :
	    begin
	    COUNTER_INCREMENT (DB, SR_N16);
	    COUNTER_INCREMENT (DB, S_REMOTE_BUFFER_ERRORS);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[RN_HFE] :
	    begin
	    COUNTER_INCREMENT (DB, LL_N17);
	    COUNTER_INCREMENT (DB, L_LOCAL_STATION_ERRORS);
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	    end;
	[otherwise] :
	    TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
	tes;

    if .HEADER [H_RESP] neq .DB [S_TM1]
    then
	begin
	DB [SS_RETRANSMIT] = TRUE;

	if .DB [S_MOTD] eql 0 then RETRANSMIT_UNACKED_MESSAGES (DB [D_TIM]);

	end;

    DB [SS_START_REP_TIMER] = FALSE;
    DB [SS_TIMING_REP] = FALSE;

    if .DB [L_DUPLEX] eql DL_FULL then DB [D_TIM] = 0;

    end;			!of routine RECORD_NAK_REASON
routine RESYNCHRONIZE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS);

    external routine
	$DDCRA : DDM_CCB novalue;

    if .DB [LS_RESYNCH_IN_PROGRESS] then return;

    if not $MCB_GET_CCB (CCB) then return;

    DB [LS_RESYNCH_IN_PROGRESS] = TRUE;
    CCB [C_HANDLE] = .DB [L_DRIVER_HANDLE];
    $DDCRA (.CCB);
    end;			!of routine RESYNCHRONIZE
routine RETRANSMIT_UNACKED_MESSAGES

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [SS_RETRANSMIT] = FALSE;

    if .DB [$SUB_FIELD (S_WAITING_FOR_ACK, LIST_FIRST)] neqa 0
    then
	begin

	if (.DB [$SUB_FIELD (S_WAITING_FOR_ACK, LIST_LAST)] =
	    .DB [$SUB_FIELD (S_WAITING_FOR_TRANSMIT, LIST_FIRST)]) eqla 0
	then
	    DB [$SUB_FIELD (S_WAITING_FOR_TRANSMIT, LIST_LAST)] = .DB [$SUB_FIELD (S_WAITING_FOR_ACK, LIST_LAST)];

	DB [$SUB_FIELD (S_WAITING_FOR_TRANSMIT, LIST_FIRST)] = .DB [$SUB_FIELD (S_WAITING_FOR_ACK, LIST_FIRST)];
	$MCB_INITIALIZE_QUEUE (DB [S_WAITING_FOR_ACK]);
	end;

    DB [S_TM1] = .DB [S_A];
    end;			!of routine RETRANSMIT_UNACKED_MESSAGES
routine RETURN_ACKED_MESSAGES

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    until .DB [S_AR] eql .DB [S_A] do
	begin

	local
	    CCB : ref block field (C_FIELDS);

	if not $MCB_DEQUEUE_CCB (DB [S_WAITING_FOR_ACK], CCB) then return;

	DB [S_AR] = .DB [S_AR] + 1;
	DB [S_TRANSMIT_THRESHOLD] = 7;
	SCHEDULE_TRANSMIT (.CCB, DB [D_TIM], DLL$_SUCCESS);
	end;

    end;			!of routine RETURN_ACKED_MESSAGES
routine SCHEDULE_PERSISTENT_AST

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),	! CCB to use for status nodification.
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    CCB [C_HANDLE] = .DB [S_USER_HANDLE];
    CCB [C_FNC] = FC_AST;
    CCB [C_MOD] = DLL$K_PERSISTENT_ERROR;
    CCB [C_STS] = .DB [S_PERSISTENT_ERROR];
    $MCB_SCHEDULE_CCB (.CCB);
    DB [S_PERSISTENT_ERROR] = 0;
    end;			!of routine SCHEDULE_PERSISTENT_AST
routine SCHEDULE_RECEIVE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    CCB [C_HANDLE] = .DB [S_USER_HANDLE];

    if .CCB [C_HANDLE] eqlu 0 then return STARCE (DB [D_TIM], .CCB);

    DB [D_USER_BUFFERS] = .DB [D_USER_BUFFERS] + 1;
    CCB [C_FNC] = FC_RCP;
    CCB [C_STS] = DLL$_SUCCESS;
    $MCB_SCHEDULE_CCB (.CCB);
    end;			!of routine SCHEDULE_RECEIVE
routine SCHEDULE_STATE_AST

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if not .DB [SS_NOTIFY_STATE] then return $MCB_RETURN_CCB (.CCB);

    CCB [C_HANDLE] = .DB [S_USER_HANDLE];
    CCB [C_FNC] = FC_AST;
    CCB [C_MOD] = DLL$K_STATE;
    CCB [C_STS] = CURRENT_STATUS (DB [D_TIM]);
    $MCB_SCHEDULE_CCB (.CCB);

    if .DB [SS_NOTIFY_STATE]
    then

	if $MCB_GET_CCB (CCB)
	then
	    SCHEDULE_STATE_AST (.CCB, DB [D_TIM])
	else
	    $MCB_REQUEST_CCB ();
    end;			!of routine SCHEDULE_STATE_AST
routine SCHEDULE_TRANSIENT_AST

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    CCB [C_HANDLE] = .DB [S_USER_HANDLE];
    CCB [C_FNC] = FC_AST;
    CCB [C_MOD] = DLL$K_TRANSIENT_ERROR;
    CCB [C_STS] = .DB [S_TRANSIENT_ERROR];
    $MCB_SCHEDULE_CCB (.CCB);
    DB [S_TRANSIENT_ERROR] = 0;
    end;			!of routine SCHEDULE_TRANSIENT_AST
routine SCHEDULE_TRANSMIT

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS),
	STATUS)
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB_STS novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    CCB [C_FNC] = FC_XCP;
    CCB [C_STS] = .STATUS;
    $MCB_SCHEDULE_CCB (.CCB);

    DB [D_USER_BUFFERS] = .DB [D_USER_BUFFERS] - 1;

    if .DB [D_USER_BUFFERS] neq 0 then return;

    if .DB [S_CONTROL_CCB] neqa 0
    then
	begin
	$MCB_SCHEDULE_CCB (.DB [S_CONTROL_CCB]);
	DB [S_CONTROL_CCB] = 0;
	end;

    end;			!of routine SCHEDULE_TRANSMIT
routine SEND_DATA

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if .DB [D_CONTROL_FLAGS] neq 0 then return;

    if .DB [L_MESSAGES_AT_DRIVER] gtru 0 then return;

    if not .DB [LS_STATION_ENABLED] then return;

    DB [L_BABBLE_COUNT] = .DB [S_MAXIMUM_TRANSMITS] %(4)%;

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT] :
	    begin

	    if not (.DB [SS_SEND_START] or .DB [SS_SEND_STACK]) then return;

	    if (BUILD_CONTROL_MESSAGE (DB [D_TIM]) eqla 0) then return;

	    end;
	[SS_RUNNING] :
	    begin

	    label
		BUILD_MESSAGES;

	    BUILD_MESSAGES : begin

	    while (.DB [SS_SEND_REP] or .DB [SS_SEND_NAK]) do

		if (BUILD_CONTROL_MESSAGE (DB [D_TIM]) eqla 0) then leave BUILD_MESSAGES;

	    if not .DB [SS_RETRANSMIT]
	    then

		while .DB [L_MESSAGES_AT_DRIVER] lss .DB [L_MAXIMUM_AT_DRIVER] do
		    begin

		    local
			CCB : ref block field (C_FIELDS);

		    if not $MCB_DEQUEUE_CCB (DB [S_WAITING_FOR_TRANSMIT], CCB) then exitloop;

		    if (BUILD_DATA_MESSAGE (DB [D_TIM], .CCB) eqla 0)
		    then
			begin
			$MCB_STACK_CCB (DB [S_WAITING_FOR_TRANSMIT], .CCB);
			leave BUILD_MESSAGES;
			end;

		    if (DB [L_BABBLE_COUNT] = .DB [L_BABBLE_COUNT] - 1) eql 0 then exitloop;

		    end;

	    if .DB [SS_SEND_SELECT] and (.DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] eqla 0)
	    then
		DB [SS_SEND_ACK] = TRUE;

	    if .DB [SS_SEND_ACK]
	    then
		BUILD_CONTROL_MESSAGE (DB [D_TIM]);

	    end;
	    end;
	[SS_MAINTENANCE] :
	    begin

	    local
		CCB : ref block field (C_FIELDS);

	    if not $MCB_DEQUEUE_CCB (DB [S_WAITING_FOR_TRANSMIT], CCB) then return;

	    if (BUILD_MAINTENANCE_MESSAGE (DB [D_TIM], .CCB) eqla 0)
	    then
		begin
		$MCB_STACK_CCB (DB [S_WAITING_FOR_TRANSMIT], .CCB);
		return;
		end;

	    end;
	[inrange] : return;
	tes;

    if .DB [SS_SEND_SELECT] and (.DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] neqa 0)
    then
	begin

	local
	    CCB : ref block field (C_FIELDS);

	CCB = .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_LAST)];
	DB [SS_SEND_SELECT] = FALSE;
	begin

	local
	    HEADER : ref block [H_LENGTH] field (HDR_FIELDS);

	HEADER = .CCB [C_ADDR];
	HEADER [H_SELECT] = TRUE;
	end;
	CCB [C_MOD] = FM_SYN;

	if (CCB = .CCB [C_PRM4]) neqa 0
	then
	    begin

	    local
		HEADER : ref block [H_LENGTH] field (HDR_FIELDS);

	    HEADER = .CCB [C_ADDR];
	    HEADER [H_QSYNC] = TRUE;
	    end;


	if .DB [L_DUPLEX] neq DL_FULL
	then
	    DB [LS_STATION_ENABLED] = FALSE;

	end;

    begin

    local
	CCB : ref block field (C_FIELDS);

    if (CCB = .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)]) neqa 0
    then
	SYNCHRONIZE (DB [D_TIM], .CCB);

    end;
    begin

    external routine
	$DDXME : DDM_CCB novalue;

    FLUSH_QUEUE (DB [L_PRE_TRANSMIT], %quote $DDXME);
    end;
    end;			!of routine SEND_DATA
routine SEND_PERSISTENT_ERROR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	STATUS)
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_STS novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS);

    if .DB [S_USER_HANDLE] eql 0 then return;

    DB [S_PERSISTENT_ERROR] = .STATUS;

    if $MCB_GET_CCB (CCB)
    then
	SCHEDULE_PERSISTENT_AST (.CCB, DB [D_TIM])
    else
	$MCB_REQUEST_CCB ();

    end;			!of routine SEND_PERSISTENT_ERROR
routine SEND_STATE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS);

    if .DB [S_USER_HANDLE] eql 0 then return;

    if .DB [S_PROTOCOL_STATE] eql SS_HALTED then DB [SS_NOTIFY_OFF] = TRUE;

    DB [SS_NOTIFY_STATE] = TRUE;

    if $MCB_GET_CCB (CCB)
    then
	SCHEDULE_STATE_AST (.CCB, DB [D_TIM])
    else
	$MCB_REQUEST_CCB ();

    end;			!of routine SEND_STATE
routine SEND_TRANSIENT_ERROR

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	STATUS)
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_STS novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    local
	CCB : ref block field (C_FIELDS);

    if .DB [S_USER_HANDLE] eql 0 then return;

    DB [S_TRANSIENT_ERROR] = .STATUS;

    if $MCB_GET_CCB (CCB)
    then
	SCHEDULE_TRANSIENT_AST (.CCB, DB [D_TIM])
    else
	$MCB_REQUEST_CCB ();

    end;			!of routine SEND_TRANSIENT_ERROR
global routine SET_DEVICE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    while .DB [D_CONTROL_FLAGS] neq 0 do
	begin

	if .DB [SS_DEVICE_BEING_SET] then return;

	selectone TRUE of
	    set
	    [.DB [DC_STOP_DEVICE]] :

		if .DB [SS_DEVICE_RUNNING]
		then
		    begin

		    local
			CCB : ref block field (C_FIELDS);

		    if not $MCB_GET_CCB (CCB) then return $MCB_REQUEST_CCB ();

		    STOP_DEVICE (.CCB, DB [D_TIM]);
		    end
		else
		    DB [DC_STOP_DEVICE] = FALSE;

	    [.DB [DC_START_DEVICE]] :

		if not .DB [SS_DEVICE_RUNNING]
		then
		    begin

		    local
			CCB : ref block field (C_FIELDS);

		    if not $MCB_GET_CCB (CCB) then return $MCB_REQUEST_CCB ();

		    START_DEVICE (.CCB, DB [D_TIM]);
		    end
		else
		    DB [DC_START_DEVICE] = FALSE;

	    [.DB [DC_SET_REQUESTED_STATE]] :

		selectone TRUE of
		    set
		    [.DB [L_LINE_STATE] neq DL_ON]:
			DB [DC_SET_REQUESTED_STATE] = FALSE;
		    [.DB [S_PROTOCOL_STATE] eql .DB [S_REQUESTED_STATE]] :
			DB [DC_SET_REQUESTED_STATE] = FALSE;
		    [otherwise] :
			begin
			SET_LINK (DB [D_TIM], .DB [S_REQUESTED_STATE]);
			DB [DC_SET_REQUESTED_STATE] = FALSE;
			end;
		    tes;

	    tes;

	end;

    if .DB [S_PROTOCOL_STATE] eql SS_HALTED then return;

    SEND_DATA (DB [D_TIM]);
    end;			!of routine SET_DEVICE
global routine SET_LINK

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	STATE)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [LS_STATION_ENABLED] = FALSE;
    DB [SS_TIMING_REP] = FALSE;
    DB [SS_RETRANSMIT] = FALSE;
    DB [SS_START_REP_TIMER] = FALSE;
    DB [LS_RESYNCH_IN_PROGRESS] = FALSE;
    DB [SS_SEND_SELECT] = FALSE;
    DB [SS_SEND_ACK] = FALSE;
    DB [SS_SEND_REP] = FALSE;
    DB [SS_SEND_NAK] = FALSE;
    DB [SS_SEND_START] = FALSE;
    DB [SS_SEND_STACK] = FALSE;
    DB [S_R] = 0;
    DB [S_TM1] = 0;
    DB [S_X] = 0;
    DB [S_N] = 0;
    DB [S_A] = 0;
    DB [S_AR] = 0;
    DB [S_PENDING_NAK_REASON] = 0;
    DB [S_TRANSMIT_THRESHOLD] = 7;
    DB [S_RECEIVE_THRESHOLD] = 7;
    DB [S_SELECT_THRESHOLD] = 7;

    case .STATE from SS_LOW to SS_HIGH of
	set
	[SS_ISTRT, SS_ASTRT, SS_RUNNING] :
	    begin

	    if .DB [L_DUPLEX] eql DL_FULL
	    then
		DB [SS_HALF_DUPLEX] = FALSE
	    else
		DB [SS_HALF_DUPLEX] = TRUE;

	    DB [SS_SEND_START] = TRUE;
	    DB [SS_SEND_SELECT] = TRUE;
	    DB [DC_START_DEVICE] = TRUE;
	    DB [SS_ACTIVE] = TRUE;
	    CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_ISTRT, LCL);
	    end;
	[SS_MAINTENANCE] :
	    begin
	    DB [SS_HALF_DUPLEX] = TRUE;
	    DB [DC_START_DEVICE] = TRUE;
	    DB [SS_ACTIVE] = TRUE;
	    CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_MAINTENANCE, LCL);
	    end;
	[inrange] :
	    begin
	    DB [DC_STOP_DEVICE] = TRUE;
	    DB [SS_ACTIVE] = FALSE;
	    CHANGE_PROTOCOL_STATE (DB [D_TIM], SS_HALTED, LCL);
	    end;
	tes;

    end;			!of routine SET_LINK
global routine STARCE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCBR novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    external routine
	$DDRCE : DDM_CCB novalue;

    CCB [C_ADDR] = .CCB [C_ADDR] - H_LENGTH*%upval;
    CCB [C_CNT] = .CCB [C_CNT] + H_LENGTH*%upval;
    CCB [C_HANDLE] = .DB [L_DRIVER_HANDLE];
    $DDRCE (.CCB);
    end;			!of routine STARCE
routine START_DEVICE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    external routine
	$DDSET : DDM_CCB novalue;

    DB [DC_START_DEVICE] = FALSE;
    DB [SS_DEVICE_BEING_SET] = TRUE;
    CCB [C_PRM4] = .DB [L_CLOCK];
    CCB [C_PRM3] = .DB [L_CONTROLLER];
    CCB [C_PRM2] = .DB [L_DUPLEX];
    CCB [C_HANDLE] = .DB [L_DRIVER_HANDLE];
    $DDSET (.CCB);
    end;			!of routine START_DEVICE
routine STOP_DEVICE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (CCB : ref block field (C_FIELDS),
	DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_CCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    external routine
	$DDSTP : DDM_CCB novalue;

    DB [DC_STOP_DEVICE] = FALSE;
    DB [SS_DEVICE_RUNNING] = FALSE;
    DB [SS_DEVICE_BEING_SET] = TRUE;
    CCB [C_HANDLE] = .DB [L_DRIVER_HANDLE];
    $DDSTP (.CCB);
    end;			!of routine STOP_DEVICE
routine STOP_LINK

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [DC_SET_REQUESTED_STATE] = TRUE;
    DB [S_REQUESTED_STATE] = SS_HALTED;
    SET_DEVICE (DB [D_TIM]);
    CCB [C_FNC] = FC_XCP;
    CCB [C_STS] = DLL$_SUCCESS;
    $MCB_SCHEDULE_CCB (.CCB);
    end;			!of routine STOP_LINK
routine SYNCHRONIZE

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CCB_N0 novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if .DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_FIRST)] neqa 0
    then
	begin

	local
	    HEADER : ref block field (HDR_FIELDS);

	HEADER = .block [.DB [$SUB_FIELD (L_PRE_TRANSMIT, LIST_LAST)], C_ADDR];
	HEADER [H_QSYNC] = TRUE;    
	end;

    CCB [C_MOD] = FM_SYN;
    end;			!of routine SYNCHRONIZE
routine TERMINATE_SELECTION_INTERVAL

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if .DB [SS_TIMING_REP]
    then
	begin
	DB [SS_START_REP_TIMER] = FALSE;
	DB [SS_TIMING_REP] = FALSE;

	case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	    set
	    [SS_ISTRT] :
		begin
		DB [SS_SEND_START] = TRUE;
		DB [SS_SEND_SELECT] = TRUE;
		end;
	    [SS_ASTRT] :
		begin
		DB [SS_SEND_STACK] = TRUE;
		DB [SS_SEND_SELECT] = TRUE;
		end;
	    [SS_RUNNING] :
		begin
		DB [SS_SEND_REP] = TRUE;
		COUNTER_INCREMENT (DB, S_LOCAL_REPLY_TIMEOUTS);
		TEST_TRANSMIT_THRESHOLD (DB [D_TIM]);
		end;
	    [inrange] :
		NO_OPERATION;
	    tes;

	end;

    DB [LS_STATION_ENABLED] = TRUE;

    if .DB [SS_HALF_DUPLEX] then DB [SS_SEND_SELECT] = TRUE;

    SEND_DATA (DB [D_TIM]);
    end;			!of routine TERMINATE_SELECTION_INTERVAL
routine TEST_RECEIVE_THRESHOLD

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_N0 novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    TEST_THRESHOLD (DB [D_TIM], DB [S_RECEIVE_THRESHOLD], 4, DLL$_RECEIVE_THRESHOLD);
    end;			!of routine TEST_RECEIVE_THRESHOLD
routine TEST_SELECT_THRESHOLD

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_N0 novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    TEST_THRESHOLD (DB [D_TIM], DB [S_SELECT_THRESHOLD], 5, DLL$_SELECTION_THRESHOLD);
    end;			!of routine TEST_SELECT_THRESHOLD
routine TEST_THRESHOLD

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CTR : ref block,
	TYPE,
	STS)
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_CTR_STS novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    macro
	NUM = 0, 0, 8, 1 %;

    CTR [NUM] = .CTR [NUM] - 1;

    if .CTR [NUM] neq 0
    then
	begin

	if .CTR [NUM] lss 0 then CTR [NUM] = 0;

	return;
	end;

    if .DB [S_PROTOCOL_STATE] eql SS_RUNNING
    then
	CTR [NUM] = 7;

    begin

    external routine
	PARAMETER_CIRCUIT_COUNTERS : LINKAGE_DB novalue;

    $NM_DLL_EVENT (.TYPE, .DB [S_CIRCUIT_ENTITY],
	PARAMETER_CIRCUIT_COUNTERS (DB [D_TIM]));
    end;
    SEND_TRANSIENT_ERROR (DB [D_TIM], .STS);
    end;			!of routine TEST_THRESHOLD
routine TEST_TRANSMIT_THRESHOLD

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: DCP_DB_N0 novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    TEST_THRESHOLD (DB [D_TIM], DB [S_TRANSMIT_THRESHOLD], 3, DLL$_TRANSMIT_THRESHOLD);
    end;			!of routine TEST_TRANSMIT_THRESHOLD
routine TIMCCB

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    map
	CCB : ref block field (C_FIELDS);

    label
	RECOVERY;

    do RECOVERY :
	begin

	if .DB [DC_STOP_DEVICE]
	then
	    leave RECOVERY with STOP_DEVICE (.CCB, DB [D_TIM]);

	if .DB [DC_START_DEVICE]
	then
	    leave RECOVERY with START_DEVICE (.CCB, DB [D_TIM]);

	if .DB [S_USER_HANDLE] eql 0 then return $MCB_RETURN_CCB (.CCB);

	if .DB [SS_NOTIFY_STATE] or .DB [SS_NOTIFY_OFF]
	then
	    leave RECOVERY with SCHEDULE_STATE_AST (.CCB, DB [D_TIM]);

	if .DB [S_TRANSIENT_ERROR] neq 0
	then
	    leave RECOVERY with SCHEDULE_TRANSIENT_AST (.CCB, DB [D_TIM]);

	if .DB [S_PERSISTENT_ERROR] neq 0
	then
	    leave RECOVERY with SCHEDULE_PERSISTENT_AST (.CCB, DB [D_TIM]);

	return $MCB_RETURN_CCB (.CCB);
	end
    while $MCB_GET_CCB (CCB);

    $MCB_REQUEST_CCB ();
    end;			!of routine TIMCCB
routine TIMPWF

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    NO_OPERATION;
    end;			!of routine TIMPWF
routine TIMLTM

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin

    if .DB [L_DUPLEX] neq DL_FULL
    then
	begin
	COUNTER_INCREMENT (DB, S_SELECTION_TIMEOUTS);
	COUNTER_INCREMENT (DB, SS_NRT);
	TEST_SELECT_THRESHOLD (DB [D_TIM]);
	end;

    case .DB [S_PROTOCOL_STATE] from SS_LOW to SS_HIGH of
	set
	[SS_HALTED] :
	    return;
	[SS_ISTRT, SS_ASTRT, SS_RUNNING] : 

	    if .DB [L_DUPLEX] neq DL_FULL then RESYNCHRONIZE (DB [D_TIM]);

	[SS_MAINTENANCE] :
	    RESYNCHRONIZE (DB [D_TIM]);
	tes;

    TERMINATE_SELECTION_INTERVAL (DB [D_TIM]);
    end;			!of routine TIMLTM
routine TRANSMIT

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
       (DB : ref block field (D_FIELDS),
	CCB : ref block field (C_FIELDS))
!
! IMPLICIT INPUTS:
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!
	: MCB_DB_CCB novalue =
!
! SIDE EFFECTS:
!	None
!--

    begin
    DB [D_USER_BUFFERS] = .DB [D_USER_BUFFERS] + 1;

    if .DB [SS_ACTIVE]
    then
	begin

	if .DB [S_PROTOCOL_STATE] eql SS_MAINTENANCE
	then
	    begin
	    local
		SAVE_MAP;
	    SMAP$ (SAVE_MAP);
	    MAP$ (.CCB [C_BIAS]);
	    selectone ch$rchar (.CCB [C_ADDR]) of
		set
		[8, 12]:
		    ch$wchar (28, ch$plus (.CCB [C_ADDR], 1));
		tes;
	    MAP$ (.SAVE_MAP);
	    end;

	$MCB_QUEUE_CCB (DB [S_WAITING_FOR_TRANSMIT], .CCB);
	SEND_DATA (DB [D_TIM]);
	end
    else
	SCHEDULE_TRANSMIT (.CCB, DB [D_TIM], DLL$_ABORTED);

    end;			!of routine TRANSMIT
end
eludom