%CONTROL 1
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!           INFO MARK 2--ITP CONSOLE HANDLER
!
!           FILE=ITPS
!
!           27TH AUG 1980
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!        THIS MODULE TAKES CONNECTIONS TO FACILITY 18 FROM GATE AND HANDLES
!     CONSEQUENT ITP LOGONS FROM CONSOLES. IT ASSOCIATES THE CONSOLE WITH THE USER TASK
!      AND WILL LOAD OTHER TASKS TO GIVE THE REQUIRED SERVICE.
!        IT THEN HANDLES THE FLOW OF DATA FROM THE TASK TO THE CONSOLE AND VICE-VERSA.
!     LOGGING OFF THE CONSOLE IS ALSO CONTROLLED FROM HERE.
!
!        SEE INFO NOTES 2 AND 3 FOR INTERFACE DETAILS.
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!     SYSTEM DECLARATIONS
!
%RECORDFORMAT NSIF((%BYTEINTEGERARRAY X(0:245) %OR %BYTEINTEGER FN,SUFL,ST,SS, %C
   FLAG,UFL,CONSN,HB1,HB2,(%BYTEINTEGER LENG, %C
   %BYTEINTEGERARRAY DATA(0:234) %OR %STRING(235) S)))
%INCLUDE "ERCM08.INC_RECORDS"
%INCLUDE "ERCM08.INC_DEIMOSPERM"
%CONSTRECORD(*)%NAME NULL==0
%BEGIN
!
!
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!           CONNECTION HANDLING
!
%CONSTINTEGER NCONS=15;                 !NUMBER OF CONNECTIONS
%RECORDFORMAT CONF(%BYTEINTEGER STATE,PORT,NODE,TERM, %C
      %RECORD(QF) OUTPUT Q)
%OWNRECORD(CONF)%ARRAY CONNS(0:NCONS)
%OWNRECORD(CONF)%NAME CONN
!
!           CONNECTION STATES
!
%CONSTINTEGER UNALLOC=0
%CONSTINTEGER DATA GONE=1;              !DATA SENT TO GATE
%CONSTINTEGER TX ENABLED=2;             !OK TO SEND TO GATE
!
!           ITP CONSOLE HANDLING
!
%CONSTINTEGER NITPS=31;                 !NUMBER OF CONSOLES
%RECORDFORMAT ITPF(%BYTEINTEGER STATE,TASK SER,LENGO,GAHS, %C
      CLK,CONSNO,ITPNO,%RECORD(CONF)%NAME CONN)
%OWNRECORD(ITPF)%ARRAY ITPS(0:NITPS)
%OWNRECORD(ITPF)%NAME ITP
!
!           ITP STATE-UNALLOC AS ABOVE
!
%CONSTINTEGER TASK PROMPT=1;            !PROMPT FROM TASK SENT
%CONSTINTEGER DATA ASKED FOR=2
%CONSTINTEGER BLOCKED=3;                !WAITING FOR GOAHEADS
%CONSTINTEGER TIMEDOUT=4
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
   %INCLUDE "ERCM08.INC_ITPINT"
   %INCLUDE "ERCM08.INC_GATEINT"
   %INCLUDE "ERCM08.INC_SERVICES"
!
!           ITP HEADER BYTES
!
%CONSTINTEGER CONTROL=1
%CONSTINTEGER GAHBIT=2
%CONSTINTEGER DISC=4
%CONSTINTEGER HELLOBIT=8
!HB2
%CONSTINTEGER BREAKBIT=1
%CONSTINTEGER SETBIT=2
%CONSTINTEGER PROMPTBIT=4
%CONSTINTEGER TERMBIT=2
!           GENERAL VARIABLES
!
%OWNRECORD(PEF) P
%OWNRECORD(NSIF) %NAME NSL
%OWNINTEGER MONIT,CLOCK,I
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!                 ROUTINES START HERE
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!
!        ROUTINES TO INTERFACE TO THE BUFFER MANAGER
!
!
!     RELEASE BLOCK
!
%ROUTINE RELEASE BLOCK(%RECORD(MEF)%NAME MES)
      P_SER=BUFFER MANAGER; P_REPLY=OWN ID
      P_FN=RELEASE BUFFER; P_MES==MES
      PON(P)
%END
!
!     ASK FOR BLOCK
!
%ROUTINE ASK FOR BLOCK
      P_SER=BUFFER MANAGER; P_REPLY=OWN ID
      P_FN=REQUEST BUFFER; P_S0=1
      PONOFF(P)
%END
!
!        PUSH AND POP ROUTINES TO REPLACE DEIMOS PERM ONES
!
%ROUTINE PUSH(%RECORD (QF) %NAME Q,NEW)
%IF Q_LINK == NULL %THENSTART
   Q_LINK == NEW
   NEW_LINK == NEW
%FINISHELSESTART
   NEW_LINK == Q_LINK_LINK
   Q_LINK_LINK == NEW
   Q_LINK == NEW
%FINISH
%END
%RECORD (QF) %MAP POP(%RECORD (QF) %NAME Q)
%RECORD (QF) %NAME OLD
%IF Q_LINK == NULL %THEN OLD == NULL %ELSESTART
   %IF Q_LINK_LINK == Q_LINK %THENSTART ;!One element only on Q
      OLD == Q_LINK
      Q_LINK == NULL
   %FINISHELSESTART
      OLD == Q_LINK_LINK
      Q_LINK_LINK == OLD_LINK
   %FINISH
%FINISH
%RESULT == OLD
%END
!     SEND MESSAGE TO GATE
!
%ROUTINE TO GATE(%INTEGER FN)
      %INTEGER I
      P_SER=GATE SER; P_REPLY=OWN ID
      P_FN=FN; P_PORT=CONN_PORT
      PON(P)
      %IF MONIT&1#0 %START
         PRINTSTRING("TO GATE:")
         WRITE(FN,3); WRITE(P_PORT,3)
         %IF P_MES##NULL %START
            %FOR I=0,1,14 %CYCLE
               WRITE(P_MES_NSL_X(I),1)
            %REPEAT
         %FINISH
         NEWLINE
      %FINISH
%END
!
!     SEND MESSAGE TO OTHER TASK
!
%ROUTINE TO TASK(%INTEGER FN)
      P_SER=ITP_TASK SER; P_REPLY=ITP SER
      P_FN=FN; P_PORT=ITP_ITPNO
      PON(P)
%END
!
!     RESET ITP.......RECORDS EVENT 31 (LOGOFF)
!
%ROUTINE RESET ITP
!      WRITE(31,2);! WRITE(ITP_ITPNO,2)
!      NEWLINE
      ITP_STATE=UNALLOC; ITP_TASK SER=0
      ITP_GAHS=0; ITP_CONSNO=0
      ITP_CONN==NULL
%END
!
!
!     HANDLE CONNECTION FROM GATE
!
!        ROUTINE FINDS A FREE CONN PORT
!
%ROUTINE HANDLE CONNECTION
      %INTEGER I
      %FOR I=0,1,NCONS %CYCLE
         %IF CONNS(I)_STATE=UNALLOC %START;          !GOT FREE ONE
            CONN==CONNS(I)
            CONN_PORT=P_PORT
            CONN_NODE=P_MES_NSL_FLAG
            CONN_TERM=P_MES_NSL_ST
            P_S1=P_S0;                  !ACCEPT FLAG
            TO GATE(CALL REPLY)
            CONN_STATE=TX ENABLED
            %IF MONIT&1#0 %START
               PRINTSTRING("CONN "); WRITE(CONN_PORT,2)
               WRITE(I,2); NEWLINE
            %FINISH
            %EXIT
         %FINISHELSEIF I=NCONS %START; !NONE LEFT
            P_S1=0
            TO GATE(CALL REPLY)
            PRINTSTRING("*** OUT OF PORTS !!!!!"); NEWLINE
         %FINISH
      %REPEAT
%END
!
!     HANDLE CALL CLOSED/ABORTED FROM GATE
!
!        MUST CLEAR DOWN QUEUES AND THROW OFF USERS
!
%ROUTINE CLOSEDOWN
      %INTEGER I
      %WHILE CONN_OUTPUT Q_LINK##NULL %CYCLE
         RELEASE BLOCK(POP(CONN_OUTPUT Q))
      %REPEAT
      CONN_STATE=UNALLOC
      %IF MONIT&1#0 %START
         PRINTSTRING("CABT "); WRITE(P_PORT,2); WRITE(I,2)
      %FINISH
      %FOR I=0,1,NITPS %CYCLE
         %IF ITPS(I)_CONN==CONN %START
            ITP==ITPS(I)
            TO TASK(LOGOFF) %IF ITP_TASK SER#0
            RESET ITP;      !RESET ITP RECORD
            %IF MONIT&1#0 %THEN WRITE(I,2)
         %FINISH
      %REPEAT
      %IF MONIT&1#0 %THEN NEWLINE
%END
!
!      SEND ITP MESSAGE
!
!         PUTS ITP HEADER ON AND PUTS IT ON NSI Q.
!         SENDS MESSAGE TO GATE IF TX ENABLED
!
%ROUTINE SEND ITP MESSAGE(%INTEGER HB1,HB2)
      NSL_CONSN=ITP_CONSNO
      NSL_HB1=HB1; NSL_HB2=HB2
      P_S0=0
      CONN==ITP_CONN
      PUSH(CONN_OUTPUT Q,P_MES);      !TO BE CHANGED...TESTING PUSH/POP
      %IF CONN_STATE=TX ENABLED %START
         P_MES==POP(CONN_OUTPUT Q)
         TO GATE(PUT OUTPUT)
         CONN_STATE=DATA GONE
      %FINISH
%END
!
!     RECEIVE MESSAGE FROM TASK
!
%ROUTINE FROM TASK
      %SWITCH FN(DATA OUT:CHANGE TASK)
      %IF MONIT&2#0 %START
         PRINTSTRING("FT "); WRITE(P_PORT,2)
         WRITE(P_FN,2); WRITE(P_REPLY,2); WRITE(P_S0,3)
         NEWLINE
      %FINISH
      ->ILLEG %IF P_PORT<0 %OR P_PORT>NITPS
      ITP==ITPS(P_PORT)
      ->ILLEG %IF ITP_TASK SER#P_REPLY
      ->ILLEG %IF P_FN<DATA OUT %OR P_FN>CHANGE TASK
      ->ILLEG %IF ITP_STATE#DATA ASKED FOR %AND ITP_STATE#TIMEDOUT
      NSL==P_MES_NSL %UNLESS P_FN=CHANGE TASK
      ->FN(P_FN)
   !*
   !**  DATA OUT
   !*
      FN(DATA OUT):
         SEND ITP MESSAGE(0,TERMBIT)
         GAHL: ITP_GAHS=ITP_GAHS-1
         %IF ITP_GAHS>0  %START;        !CAN SEND MORE
            TO TASK(SEND DATA)
            ITP_STATE=DATA ASKED FOR
         %FINISHELSE ITP_STATE=BLOCKED
         ITP_CLK=24
         %RETURN
   !*
   !**  SEND PROMPT
   !*
      FN(SEND PROMPT):
         SEND ITP MESSAGE(GAHBIT,PROMPTBIT)
         ITP_STATE=TASK PROMPT
         ITP_CLK=24
         %RETURN
   !*
   !**  LOGOFF
   !*
      FN(LOGOFF):
         SEND ITP MESSAGE(CONTROL!DISC,0)
         RESET ITP;               !RESET ITP RECORD
         %RETURN
   !*
   !**  SETMODE
   !*
      FN(SETMODE):
         SEND ITP MESSAGE(CONTROL,SETBIT)
         ->GAHL
   !*
   !**  CHANGE TASK
   !*
      FN(CHANGE TASK):
         ->ILLEG;                !NOT YET IMPLEMENTED
      ILLEG:   P_S1=P_FN
               TO TASK(ILLEGAL MESSAGE)
               %IF MONIT&2#0 %START
                  PRINTSTRING("ILLEG"); NEWLINE
               %FINISH
%END
!
!     DUMP ITP RECORD TO TTY
!
%ROUTINE DUMP ITP
      WRITE(ITP_ITPNO,3)
      WRITE(ITP_STATE,3); WRITE(ITP_TASK SER,3); WRITE(ITP_LENGO,3)
      WRITE(ITP_GAHS,3); WRITE(ITP_CLK,3); WRITE(ITP_CONSNO,3)
      NEWLINE
%END
!
!           ITP DATA IN
!
!     GETS ITP MESSAGE SENT IN, IDENTIFIES THE TYPE AND
! TAKES APPROPRIATE ACTION. CONN SET UP BEFORE ENTRY
!
%ROUTINE ITP DATA IN
      %CONSTINTEGER ITPLIM=28
      %INTEGER I
      NSL==P_MES_NSL
      %IF MONIT&4#0 %START
         PRINTSTRING("IN "); WRITE(NSL_CONSN,2)
         WRITE(NSL_HB1,3); WRITE(NSL_HB2,3)
         NEWLINE
      %FINISH
      %IF NSL_HB1&HELLOBIT#0 %START;    !LOGON
         %FOR I=1,1,NITPS %CYCLE
            %IF ITPS(I)_STATE=UNALLOC %START
               ITP==ITPS(I)
               ITP_CONSNO=NSL_CONSN
               ITP_CONN==CONN
               ITP_GAHS=0
               ITP_TASK SER=USER SER;   !ALWAYS START WITH USER
               ITP_STATE=BLOCKED
               RELEASE BLOCK(P_MES)
               P_B1=CONN_NODE;          !TELL USER TASK DETAILS
               P_B2=CONN_TERM
               P_C1=ITP_CONSNO
               TO TASK(LOGON)
               !
               %RETURN
            %FINISH
         %REPEAT
      %FINISHELSESTART
         %FOR I=0,1,NITPS %CYCLE;            !FIND ENTRY
            %IF ITPS(I)_CONN==CONN %AND %C
               ITPS(I)_CONSNO=NSL_CONSN %START
               ITP==ITPS(I)
               %IF MONIT&4#0 %THEN DUMP ITP
               %EXITIF ITP_STATE#TIMEDOUT
            %FINISH
            %IF I=NITPS %START;         !CONSOLE CLOSED DOWN
               RELEASE BLOCK(P_MES)
               %RETURN
            %FINISH
         %REPEAT
         %IF NSL_HB1&GAHBIT#0 %THEN ITP_GAHS=(ITP_GAHS+1)&3
         %IF NSL_HB1&DISC#0 %START;     !LOGOFF(SETMODE EOT!)
            RELEASE BLOCK(P_MES)
            %IF ITP_TASK SER#0 %START;  !TELL TASK
               TO TASK(LOGOFF)
            %FINISH
            RESET ITP;       !RESET ITP RECORD
            %RETURN
         %FINISH
         %IF NSL_HB1&CONTROL#0 %START;  !CONTROL MESSAGE
            RELEASE BLOCK(P_MES)
            %IF NSL_HB2&BREAKBIT#0 %START; !INT
               %IF ITP_TASK SER#0 %AND NSL_LENG>0 %THEN TO TASK(INT IN)
            %FINISH
         %FINISHELSESTART
            ! MUST BE DATA MESSAGE
            %IF ITP_STATE=TASK PROMPT %START
               TO TASK(DATA IN)
               ITP_STATE=BLOCKED
            %FINISHELSESTART;                         !SPECIAL TASKS TO BE DONE HERE!!!!
               RELEASE BLOCK(P_MES)
               PRINTSTRING("DATA SEQUENCE ERROR!")
               WRITE(ITP_STATE,3); NEWLINE
            %FINISH
         %FINISH
         %IF ITP_STATE=BLOCKED %AND ITP_GAHS>0 %START
            TO TASK(SEND DATA)
            ITP_STATE=DATA ASKED FOR
         %FINISH
      %FINISH
%END
!
!        FROM GATE
!
!     HANDLES MESSAGES FROM GATE--SEE DIEMOS NOTE 2
!
%ROUTINE FROM GATE
      %SWITCH S(INCOMMING CALL:CALL ABORTED)
      %ROUTINE FIND CONNECTION
         %INTEGER I
         CONN==NULL
         %FOR I=0,1,NCONS %CYCLE
            %IF CONNS(I)_PORT=P_PORT %THEN CONN==CONNS(I) %ANDEXIT
         %REPEAT
      %END
      !
      %IF MONIT&1#0 %START
         PRINTSTRING("FG "); WRITE(P_FN,2); WRITE(P_PORT,2); NEWLINE
      %FINISH
      %IF P_FN#INCOMMING CALL %THEN FIND CONNECTION
      ->S(P_FN)
  S(INCOMMING CALL): HANDLE CONNECTION; %RETURN
  S(INPUT RECD):     %IF P_MES_NSL_FLAG&128#0 %START
                        RELEASE BLOCK(P_MES); P_MES==NULL
                        TO GATE(CLOSE CALL); ->CL
                     %FINISH
                     ITP DATA IN
                     P_MES==NULL; TO GATE(ENABLE INPUT)
                     %RETURN
  S(OUTPUT TXD):     %IF CONN##NULL %START
                           %IF CONN_OUTPUT Q_LINK##NULL %START
                               P_MES==POP(CONN_OUTPUT Q)
                                TO GATE(PUT OUTPUT)
                                CONN_STATE=DATA GONE
                            %FINISHELSESTART
                                 CONN_STATE=TX ENABLED
                            %FINISH
                      %FINISH
                      %RETURN
  S(CALL CLOSED):     %RETURN
  S(CALL ABORTED):    TO GATE(ABORT CALL)
            CL:       CLOSEDOWN
%END
!
!           HANDLE INT
!
%ROUTINE HANDLE INT
      %INTEGER I
      %IF INT='G' %THEN MONIT=1;         !GATE MONITOR
!      %IF INT='T' %THEN MONIT=2;         !TASK MONITOR
!      %IF INT='P' %THEN MONIT=4;        !ITP MONITOR
      %IF INT='A' %THEN MONIT=7;        !ALL MONITORING
      %IF INT='O' %THEN MONIT=0;        !MONITOR OFF
!      %IF INT='C'% %OR INT='?' %START
!         %FOR I=0,1,NCONS %CYCLE
!            %IF CONNS(I)_STATE#UNALLOC %START
!               WRITE(CONNS(I)_STATE,3)
!              WRITE(CONNS(I)_PORT,3)
!               WRITE(I,3)
!              NEWLINE
!            %FINISH
!         %REPEAT
!      %FINISH
!      %IF INT='I' %OR INT='?' %START
!         %FOR I=0,1,NITPS %CYCLE
!            ITP==ITPS(I)
!            DUMP ITP %IF ITP_STATE#UNALLOC
!         %REPEAT
!      %FINISH
      %IF INT = 'S' %START;         ! STOP IT
         P_S1=18;                       ! FACILITY = ITP
         TO GATE(DISABLE FACILITY)
         %FOR I = 0, 1, NCONS %CYCLE
            CONN == CONNS(I)
            %IF CONN_STATE # UNALLOC %START
               CLOSEDOWN
               TO GATE(ABORT CALL)
            %FINISH
         %REPEAT
         %STOP;             ! WAIT FOR GATE REPLIES ???????
      %FINISH
      INT=0
%END
!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!                       PROGRAM STARTS HERE
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!           INITIALISATION
!
I=MAPVIRT(BUFFER MANAGER, 4, 3)
I=MAPVIRT(BUFFER MANAGER,5,4)
I=MAPVIRT(BUFFER MANAGER,6,5)
LINKIN(ITP SER)
ALARM(250);                             !FOR TIMEOUTS
%FOR I=0,1,NCONS %CYCLE
      CONNS(I)=0
%REPEAT
CONN==CONNS(0)
%FOR I=0,1,NITPS %CYCLE
      ITPS(I)=0
      ITPS(I)_ITPNO=I
%REPEAT
!
!           MAIN PROGRAM LOOP
!
->HORRIBLE
%CYCLE
      P_SER=0; POFF(P)
      %IF INT#0 %THEN HANDLE INT
      %IF P_REPLY=0 %START;          !CLOCK
         ALARM(250)
!         %FOR I=0,1,NITPS %CYCLE;      !CHECK FOR TIMEOUTS
!            %IF ITPS(I)_STATE=TASK PROMPT %START
!               ITPS(I)_CLK=ITPS(I)_CLK-1
!               %IF ITPS(I)_CLK=0 %START
!                  ITP==ITPS(I)
!                  ITP_STATE=TIMEDOUT
!                  TO TASK(TIMEOUT)
!               %FINISH
!            %FINISH
!         %REPEAT
      %FINISHELSEIF P_REPLY=GATE SER %START
         FROM GATE
      %FINISHELSEIF P_REPLY=USER SER %START
         FROM TASK
      %FINISHELSEIF P_REPLY=POLL SER %START
HORRIBLE:
         P_S1=18
         TO GATE(ENABLE FACILITY)
      %FINISHELSEIF P_REPLY=LOAD SER %START
         !TO BE IMPLEMENTED
      %FINISHELSESTART
            PRINTSTRING("** MESSAGE ?? ")
            WRITE(P_FN,3); WRITE(P_REPLY,3); NEWLINE
      %FINISH
      !
%REPEAT
!
%ENDOFPROGRAM