Console Communications

I include this one not so much because I have found it really useful but becuase I think it has a bit of a cool factor.  I first used this back many years ago when I was an operator and would write various utilities for us to use in operations.  Since we were in the computer room with the console it was pretty easy just  use WTOR to make the program interactive with the console.  Back in those days we were batch only and didn’t use TSO.  Using WTOR for communication through the operator console is pretty simple but lacks the cool factor associated with using the MODIFY console command.  So here is how to use MODIFY and STOP to communicate with a running program.

First we need to get the address of the Communications Parameter List (mapped by the IEZCOM macro).  The COM parameter list consists of two words.

COMECBPT DS    A       Address of ECB for STOP/MODIFY
COMCIBPT DS    A       Address of Command Input Buffer

To get the address of the COM parameter area we can use the EXTRACT macro.

         EXTRACT COMPTR,FIELDS=COMM    GET POINTER TO COMM FIELDS

COMPTR is a fullword where the address of the COM parameter area will be stored. We request the COM parameter area by specifying FIELDS=COMM.

         L     R1,COMPTR          POINTER TO COMM FIELDS 
         LA    R2,4(,R1)          CIB ORIGIN             
         L     R3,0(,R2)          PONTER TO FIRST CIB    
         LTR   R3,R3              ANY START CIB PRESENT  
         BZ    SETCIB             NO - CONTINUE

Next we load the address of the COM parm area into register 1. Now we have to check to see if there is a Command Input Buffer (CIB) related to a START command. If we are running as a Started Task there should be a CIB, otherwise there is no CIB and the pointer is zero.

         QEDIT ORIGIN=(R2),BLOCK=(R3)   FREE START CIB

If there is a CIB as the result of a START command we need to free the CIB. For this we use the QEDIT macro and pass two parameters. ORIGIN refers the the address of the COMCIBPT field (the second word in the COM parmameter list) and BLOCK points the the CIB we wish to free.

SETCIB   DS    0H                                                     
         QEDIT ORIGIN=(R2),CIBCTR=1     SET CIB LIMIT TO ONE AT A TIME

Now we set a limit on how many CIBs may be queued to our job at one time. Initially this value is zero which means that MODIFY commands will not be accepted by our job. We want to allow one CIB to be queued at a time so we set the limit using the QEDIT macro. Here we specify the ORIGIN (again the address of the COMCIBPT field) and specify a limit with the CIBCTR parameter.

LOOP     DS    0H                                    
         L     R1,COMPTR          COMM FIELDS        
         LA    R2,0(,R1)          ECB ADDRESS PTR    
         L     R3,0(,R2)          ECB ADDRESS        
*                                                    
         WAIT  1,ECB=(R3)         WAIT FOR A COMMAND

Now we will wait for a command from the console. We do this by waiting on the ECB pointed to by the COMECBPT field. We could also be doing some work and check to see if the ECB has been posted to interrupt whatever we are currenty doing. Here we just wait for a command.

         L     R1,COMPTR          POINTER TO COMM FIELD 
         LA    R2,4(,R1)          CIB ORIGIN            
         L     R3,0(,R2)          PONTER TO FIRST CIB

When the ECB is posted we resume execution and get the address of the CIB. The CIB is mapped by the IEZCIB macro and contains the following fields.

CIBNEXT  DS    A                  POINTER TO NEXT CIB ON CHAIN OR ZERO IF LAST
CIBVERB  DS    X                  VERB INDICATING TYPE OF COMMAND
*                                 X'04' - START, X'40' - STOP, X'44' - MODIFY
CIBLEN   DS    X                  LENGTH IN DOUBLEWORDS OF CIB
         DS    XL4                Reserved
CIBASID  DS    H  
CIBCONID DS    X                  CONSOLE ID - FROM WHERE COMMAND WAS ISSUED
         DS    X                  Reserved
CIBDATLN DS    H                  LENGTH, IN BYTES, OF CIB DATA
CIBDATA  DS    0C                 DATA FROM MODIFY COMMAND

The VERB tells us in the CIB was created as a result of a START, STOP, or MODIFY console command. CIBDATALN is the length of data associated with the command. CIBDATA is a variable length field that contains the data from the START or MODIFY command.

         CLI   4(R3),X'44'        IS IT A MODIFY COMMAND 
         BE    MODIFY                                    
*                                                        
         CLI   4(R3),X'40'        IS IT A STOP COMMAND   
         BE    STOP                                      
*                                                        
         WTO   '***  UNKNOWN CIB TYPE ***',ROUTCDE=(1,11)
         B     FREECIB

Now we check the VERB to determine what type of command we are dealing with. We only expect to find either a STOP or a MODIFY command.

MODIFY   DS   0H                                                 
         WTO   '***  MODIFY COMMAND RECEIVED ***',ROUTCDE=(1,11) 
*                                                                
         LH    R5,14(,R3)         GET COMMAND LENGTH             
         LA    R6,16(,R3)         POINT TO COMMAND

Here we process a MODIFY command. We point to the data and get the data length from the CIB.

         LR    R1,R5              COPY LENGTH  
         BCTR  R1,0               SUBTRACT ONE 
         MVC   WORK(4),=C'*** '                
         EX    R1,MODMVC                       
MODMVC   MVC   WORK+4(1),0(R6)                 
         LA    R1,WORK+4                       
         AR    R1,R5                           
         MVC   0(4,R1),=C' ***'                
         LA    R1,WORK                         
         LA    R0,8(,R5)                       
         BAL   R14,WTO                         
*                                              
         B     FREECIB

Next we copy the data into a message area and BAL to a routine that will WTO the message to the console.

WTO      DS    0H                                  
         STM   R14,R12,12(R13)                     
         LA    R3,SAVEA2                           
         ST    R13,4(,R3)                          
         ST    R3,8(,R13)                          
         LR    R13,R3                              
*                                                  
         LR    R10,R0             SAVE LENGTH      
         LR    R11,R1             SAVE PTR TO TEXT 
*                                                  
         LA    R1,1                                
         CR    R10,R1                              
         BL    WTO020                              
*                                                  
         LA    R1,80              MAX LEN          
         CR    R10,R1                              
         BNH   WTO010
*                    
         LR    R10,R1

Here is the routine to issue the WTO. First we save the caller’s registers, set up a new save area, and then check the length of the message.

WTO010   DS    0H                      
         MVC   WTOWORK(4),=X'00008000' 
         LA    R1,4(,R10)              
         STH   R1,WTOWORK              
         BCTR  R10,0                   
         EX    R10,WTOMVC              
*WTOMVC  MVC   WTOWORK+4(1),0(R11)     
         LA    R1,WTOWORK              
         LA    R1,5(R10,R1)            
         MVC   0(4,R1),=X'00008020'

Now we build the SVC 35 parameter list.

LA    R1,WTOWORK      
         SVC   35              
*                              
WTO020   DS    0H              
         L     R13,4(,R13)     
         LM    R14,R12,12(R13) 
         BR    R14

Now we point to the parameter list, issue the WTO SVC, and then return to the caller.

STOP     DS   0H                                               
         WTO   '***  STOP COMMAND RECEIVED ***',ROUTCDE=(1,11) 
         B     EXIT

If the VERB indicates a STOP command we issue a WTO and exit.

FREECIB  DS    0H                                        
         L     R1,COMPTR          POINTER TO COMM FIELDS 
         LA    R2,4(,R1)          CIB ORIGIN             
         L     R3,0(,R2)          PONTER TO FIRST CIB    
*                                                        
         QEDIT ORIGIN=(R2),BLOCK=(R3)   FREE THE CIB     
*                                                        
         B     LOOP

Once we have processed a MODIFY command we need to free the CIB so our program can accept another modify command. We free it using QEDIT the same way we did with the START CIB.

JOB 6920  $HASP373 CIB01    STARTED - INIT 12 - CLASS A - SYS TCS3  
          f CIB01,HELLO                                             
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** HELLO ***                                            
          f cib01,This is a TEST                                    
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** THIS IS A TEST ***                                   
          f cib01,Parameters to pass to the program                 
JOB 6920  +***  MODIFY COMMAND RECEIVED ***                         
JOB 6920  +*** PARAMETERS TO PASS TO THE PROGRAM ***                
          p cib01                                                   
JOB 6920  +***  STOP COMMAND RECEIVED ***                           
JOB 6920  14.09.40   0.00.45   0.00.00  0000   CIB01     MVSSP      
JOB 6920  14.09.40   0.00.45   0.00.00  0000   CIB01     ########   
JOB 6920  $HASP395 CIB01    ENDED

And here is some sample output from running the program and communicating with it using MODIFY and STOP.