S N A N O T E 3-133 API/HLLAPI INFORMATION APPLIES TO: HLLAPI ------ All NetWare 3270 Workstations Products Low Level API ------------- Netware 3270 Workstation Token Ring Server Option Netware 3270 LAN Workstation (Not Netware 3270 CUT Mode Workstations) SUPERSEDES: 3-21, 3-25, 3-29, 3-30, 3-31, 3-34, 3-50, 3-51 which remain valid for CXI-PCOX products DATE: March 7, 1991 Novell's NetWare 3270 HLLAPI and API support enables PC programs developed for use with the Application Program Interface (API) host interaction functions to run in a Novell 3270 gateway/workstation environment. I. IBM Low Level API Support The IBM Low Level API is supported by NetWare 3270 Multi Workstation and LAN products but not by the NetWare 3270 CUT mode Workstations products. The API supported by IBM under Version 1 of the IBM 3270 PC Control Program contains three functional subsets: 1. Keyboard Input 2. Presentation Space Output 3. Structured field support Novell's API support under Version 2 of the IBM 3270 PC Control Program provides the above capability plus more. These additional aspects, however, are not directly relevant to micro-to-mainframe communication. NetWare SNA Workstation API support is limited to the IBM subsets appropriate for micro-to-mainframe communications. We support the IBM API by trapping IBM software interrupt 7A, and mapping the function requested to a corresponding NetWare 3270 API function call. This includes support for keyboard input, presentation space output, and structured fields. With Novell's IBM Low Level API support, it is possible to invade the SEND and RECEIVE commands that are part of the IBM API package. Novell will supply its' own TRANSFER command with Version 2.0 of the NetWare 3270 Multi and LAN Workstation. II. IBM HLLAPI Support IBM's 3270 PC High Level Language Applications Program Interface (HLLAPI) is a set of programs with associated functions which can be called from a DOS application program to interface with one or more mainframe sessions. Novell offers its own HLLAPI which is compatible with a subset of IBM's PC 3270 HLLAPI (version 3.0) and with all functions of IBM's 3270 PC EEHLLAPI (version 1.2). Both the IBM and the NetWare 3270 HLLAPI are implemented in two parts. 1. A Language Interface Module (LIM) that is specific to a given language. 2. A resident module (HLLAPI) that handles the actual interface functions between the application program and the control program. IBM HLLAPI provides language interfaces for both Compiled and Interpretive BASIC, IBM COBOL, and IBM PASCAL. Novell provides LIMs for IBM/Microsoft Compiled Basic, COBOL and for Computer Innovations C 86 only. NetWare 3270 HLLAPI has a built in LIM for Interpretive Basic. Programs written using the IBM MACRO Assembler can invade the resident module directly, and do not require a LIM. Since Novell's HLLAPI and IBM's HLLAPI are compatible at the assembler language interface level, IBM's LIMs can be used with Novell's HLLAPI. IBM and Novell HLLAPI function in a similar manner. After building a Parameter Control Block with the parameters needed for a specific function, the LIM invokes the resident module with DOS software interrupt 7F. The resident module must be loaded prior to its use and remains resident as an extension of PC DOS. The requested function is performed using the function code and other parameter data passed in the control block built by the LIM. After completion of the requested task, a return code is placed in the control block and control is returned to the LIM. The interface module then returns control to the calling program. The NetWare 3270 HLLAPI function calls are translated to corresponding NetWare 3270 API calls. The NetWare 3270 API calls interact with the Novell control program using Interrupt 6F (decimal 111). Novell supports all of the IBM E HLLAPI function calls, with some differences. At the present time, Novell does not support Workstation Control HLLAPI functions due to the lack of PC DOS concurrency. The lack of DOS concurrency also explains the functional differences in the Connect, Disconnect, Reserve, and Release calls. Novell offers as part of its HLLAPI products a unique High Level Language Command Processor (3270 CP). This program allows the user to execute, either interactively of in batch mode, a series of high level functions to perform specific host functions, such as logging b on to host applications, etc. The 3270 CP works in conjunction with the NetWare 3270 Workstation products. For additional information on the IBM HLLAPI, see the 3270-PC High Level Language Application Program Interface manual (z125-3301). III. ELIMINATING UNWANTED HOST SCREEN PRESENTATION A typical motivation for using the Novell Application Program Interface is that it permits the programmer/designer to insulate the end user of the application from the host computer environment. This permits sophisticated applications to be presented in a "friendly" manner. A commonly used technique would be to present all entry/display panels from the PC application, never displaying a true host screen. Developers using current releases of Novell control programs will find it easy to achieve this technique since function code 10 (Restore Display) causes the host presentation space to be displayed. IV. TIMING CONSIDERATIONS - ALTERNATIVE APPROACHES API permits PC based programs to interface directly with a mainframe computer environment by entering keystrokes and interrogating displayed data. As such, the API serves as the eyes and hands of a terminal operator. Through the API, a programmer can integrate the functions of a host computer with a PC application. Programers writing code to run with Netware SNA products must be aware of many details, the most important of which are timing related. For example, when entering successive terminal functions it is necessary to determine when the host computer is finished processing the last terminal transaction and is ready to service the next request. Similarly, programmers interested in extracting host data for a PC application must be able to determine with assurance when the desired data is available on the host screen. A common practice used to coordinate the timing of the application program and the host display is to use the XCLOCK X() on the status line of the terminal. A difficulty arises when using XCLOCK, however, since many systems do their processing in such a fashion that the XCLOCK status comes ON and OFF repeatedly during the processing of a request. This sporadic ON/OFF behavior makes it hard to determine when the host computer has actually completed processing. This type of interaction is common in many of the applications that have been written for 3278 terminal emulation packages. It presents a difficult programming problem. See below for a "pseudo code" example of XCLOCK timing techniques. A more efficient way of dealing with host timing peculiarities can be accomplished through the design of a custom application protocol. During the design of an application, the programmer can usually build into the application the ability to precede and end each transmission with a special character or signal. This ability to design transmission codes into an application can be thought of as designing an application protocol. This approach is also referred to as an 'end-to-end protocol; where the application does not depend on external factors when determining data transmission rules. The use of an 'end-to-end protocol' depends upon the programmer's having complete knowledge of the host environment, including terminal behavior and the possible host responses. This capability is often the results of the programmer's having designed the host program as well as the PC program. In any case, the designer must allocate a specific host screen area which can be reliably written to and queried. This area which may consist of several terminal lines or only a single byte, will be used by the designer to monitor the status of terminal interaction (e.g. when a transfer has successfully completed.) When the program can rely on some screen position for its signal of transfer completion, it does not have to worry about the many idiosyncracies of the XCLOCK. The following example further describes the difference between using the traditional approach of depending on the XCLOCK compared with using a custom 'end-to-end protocol' approach. Assume that a program has been designed which will send and receive data between a PC and a host system. It was designed to query the XCLOCK for all timing-related needs. Therefore a simple transfer would require the program to send the data and then look at the XCLOCK to see if it had come on, signalling host processing. Then the program needs to wait until the XCLOCK is off. At this point the data may be ready, but we still cannot be sure. We must either look for the data on screen, or decide to wait some amount of time longer to make sure that the XCLOCK does not come on again. This same process must occur until it is certain that the data is ready. At that point the program can query the screen for the data, read it and process it. If this program had been written using a protocol defined by the programmer, the process would be much less complex, and more reliable. The program would verify that the screen position defined for the protocol was in a state to receive data, then send the data and begin to wait for the protocol position to change to a transfer complete state. When the position changes, we know that either we have completed transmission successfully or else some error condition has occurred. There is no worry about how many times the XCLOCK has come ON/OFF and therefore no timing considerations which are affected by the host's use of the XCLOCK. This general example should illustrate the ease with which an application can interact with a host when using a programmer defined 'end- to-end Protocol' rather than relying on the host status line and XCLOCK parameter. PSEUDO CODE EXAMPLES A suggested approach is show below for using the Application Program Interface (API) to handle the timing concerns which occur while using a terminal emulator. It is first necessary to establish a host session connection, by executing a NetWare SNA control program, before executing any code which uses the API. In the following discussion, position 8 is referenced as the location to look at when checking for the XCLOCK. This is actually the 9th position on the status line (line 25 of a 3278 model 2 screen), but is referenced as position 8 through the API (using the IBM convention of referring to the first location as byte 0). SEND_DATA_TO_HOST() Send data to the host through normal processing means. Then wait for the host response by using the CHECK_STATUS routine. CHECK_STATUS wait for position 8 if (pos 8) modified CHECK_FOR_X() else WAIT_LOOP() The CHECK_STATUS routine will execute an API Function 8 call using the value 8 as its input. This will cause the program to wait until position 8 is modified or a time-out occurs. If the location is modified we then need to find out that value is not at the location, and, therefore, must execute the CHECK_FOR_X() routine. If the location is not modified, a time-out has occurred and we need to examine the screen to check if there is an error or if our data is ready. CHECK_FOR_X() read position 8 if (pos 8) = 'x' CHECK_STATUS() else if (pos 8) = NULL (00) WAIT_LOOP() else if (pos 8) = other char CHECK_FOR_ERROR() This routine will interrogate position 8 on the screen and take action based on the results received. If position 8 is an 'X' then XCLOCK is on and we need to wait for it to go off. If it is a NULL then XCLOCK is off and we need to wait a little longer to verify that XCLOCK does not come on again. If pos 8 is anything else, then an error condition exists, which must be identified and invoke the proper processing. WAIT_LOOP() wait for position 8 if result = success CHECK_FOR-X() else if (pos 8) = 'X' CHECK_FOR_ERROR() else if (pos 8) = NULL DATA_READY() else CHECK_FOR_ERROR() This waiting routine is necessary since in various environments the XCLOCK can and will come ON and OFF many times during a host response. Upon entry into the routine we wait for position 8 to be modified. If there is a successful status, then XCLOCK has probably come back on, so we need to CHECK_FOR_X(). If the return is unsuccessful a time-out has occurred and we need to check to see if position 8 is either 'X' or NULL. If it is an 'X' then we probably have an error condition like XPROGxxx, etc. If position 8 is a NULL then the screen is done processing and we can begin to interrogate the screen for valid data. Any other character in position 8 indicates an error condition. CHECK_FOR_ERROR() read OIA to see if PROG or other error read screen for errors This will be the error processing routine. Depending upon the various messages that your host may return as errors, you need to investigate all possibilities and take corrective action as necessary. V. STACK CONSIDERATIONS - LATTICE 'C' COMPILER When using the NetWare 3270 API with the Lattice 'C' compiler in the large memory model, it is necessary to make some program changes to handle differences in the stack. When the stack is set up after calling the assembly language interface program, the OLD-BP valve is 4 bytes rather that 2 bytes, as in the small model. This affects the entire stack, so the difference must be accommodated. Also, the variable NULL, which is defined by Lattice, takes up 2 bytes in the small memory model and 4 bytes in the large memory model. The difference must be considered. VI. NETWARE 3270 API FUNCTION CODE SUMMARY FUNCTION CODE & NAME INPUT/OUTPUT --------------------- ----------- 0 Enter Terminal Mode Input: (AX)=0 Output:(AX)=0 No action requested (AX)=1 Screen save 1 Reset Interface & Input: (AX)=1 Set Config Parms (DX) [2-0] Model # (DX) [4-3] I/O Address (DX) [6-5] DMA Channel Output:No returned value 2 Set Display Parameters Input: (AX)=2 (DX) [1-0] OIA Mode (DX) [4-2] Monitor Support Output:No returned value 3 Read Status Input: (AX)=3 Output:(AX)=Status Word 4 Read Cursor Position Input: (AX)=4 Output:(AX)=Cursor Position 5 Get Character From Input: (AX)=5 Device Buffer (DX)=Cursor Position Output:(AL)=Data or Attribute char (AH)=0 - data; 1 - attribute 6 Send Character Input: (AX)=6 (DH)=0-ASCII; 1-extended code (DL)=ASCII char or extended code Output:No returned value 7 Set Time-out Input: (AX)=7 (DX)=Timeout Value (seconds) Output:No returned value 8 Wait for Location to be Input: (AX)=8 Modified (DX)=Cursor Position Output:(AX) =0-location modified =non-zero - time-out expired 9 No-operation Input: (AX)=9 Output:No returned value 0 Restore Display Input: (AX)=10 Output:No returned value 11 Update Device Buffer Input: (AX)=11 Output:(AX)=Cursor Position 12 Write String to add Input: (AX)=12 Information Area (DX)=Offset of String Output:No returned value 13 Maintenance Operations Input: (AX)=13 (DX)=Maint. operation code Output:(AX)=Operation status 14 Return Control Prog. Rel Input: (AX)=14 Output:(AH)= Release number (major) (AL)= Level number (minor) 15 Return Microcode Rel # Input: (AX)=15 Output:(AH)=Release number (major) (AL)=Level number (minor) 16 Save or Display Graphics Input: (AX)=16 (BX)=Length of caller's buffer (CX)=Subfunction request code (DX)=Pointer of caller buffer Output:(AX)=Return Code (CX)=Length of PIF data 17 Perform Structured Field Input: (AX)=17 Operation (CX)=Request number (DX)=Address of parameter list Output:(AX)=Status Word (CX)=Error number 18 Set Cursor Position for Input: (AX)=18 Direct Write Buffer (DX)=Cursor Position Output:(AX)=Status Word 19 Write Direct to Buffer Input: (AX)=19 (DL)=Character to be written (DH)=Translation option Output:(AX)=Status Word 20 Write Direct to Buffer Input: (AX)=20 With No Echo (DL)=Character to be written (DH)=Translation option Output:(AX)=Status Word 21 Set Direct Write String Input: (AX)=21 Length (DX)=String value Output:No returned value 22 Write String Direct to Input: (AX)=22 Buffer (DX)=Address of string Output:(AX)=Status Word 23 Write String Direct to Input: (AX)=23 Buffer Untranslated (DX)=Address of string Output:(AX)=Status Word 24 Read Direct-Write Input: (AX)=24 Cursor Position Output:(AX)=Cursor Position 25 Convert Row/Column to Input: (AX)=25 Cursor Position (DH)=Display Row (1-43) (DL)=Display Column (1-132) Output:(AX)=Cursor Position 26 Convert Cursor Position Input: (AX)=26 Row/Column (DX)=Cursor Position Output:(AH)=Display Row (AL)=Display Column 27 Find Next Field Input: (AX)=27 (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 28 Find Previous Field Input: (AX)=28 (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 29 Find Next Unprotected Input: (AX)=29 Field (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 30 Find Previous Input: (AX)=30 Unprotected Field (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 31 Find Next Protected Input: (AX)=31 Field (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 32 Find Previous Protected Input: (AX)=32 Field (DX)=Initial Cursor Position Output:(AX)=Field Cursor Position 33 Masked Search Forward Input: (AX)=33 (DH)=Mask (DL)=Search Pattern Output:(AX)=Cursor Position or 0 34 Masked Search Backward Input: (AX)=34 (DH)=Mask (DL)=Search Pattern Output:(AX)=Cursor Position or X'OFFF' 35 Find Field Length Input: (AX)=35 (DX)=Cursor Position Output:(AX)=Field Length 36 Read Field Input: (AX)=36 (DX)=Address (offset) of buffer Output: (AX)=Status Word 37 Read Screen Input: (AX)=37 (DX)=Address (offset) of buffer Output:(AX)=Status Word 38 Read Buffer Untranslated Input: (AX)=38 (DX)=Cursor Position Output:(AX)=Buffer Code (BX)=Pointer to 3278/79 device buffer image (CX)=Segment address to device buffer image 39 Enable/Disable Keyboard Input: (AX)=39 (DL)=0 to enable keyboard breaks 1 to disable keyboard breaks Output:No return value 40 Select Host Session Input: (AX)=40 (DL)=Session short name Output:(AX)=Session Information 41 Retrieve Host Session Input: (AX)=41 Name Output:(AX)=0-Function N/A (CUT mode) Non-zero - Short Name (DFT) 42 Return Current Device Input: (AX)=42 Buffer Size and Pointer to Output: (AX)=Device buffer size (CX)=Segment address of EAB 43 Arm Modified Location Input: (AX)=43 Trigger (DX)=Cursor Position Output:(AX)= 0 Function N/A (CUT mode) 1 Operation Successful (DFT) VII. STATUS WORD FORMAT Bits 00-01 Cursor Type Bit 02 Cursor inhibited Bit 03 Display inhibited Bit 04 Feature step inhibited Bit 05 480-character format code Bit 06-07 Spare Bits 08-10 Model number (2,3,4 or 5) Bit 11* Unit has been reset by controller Bit 12* Buffer has been written into Bit 13* Alarm has been sounded Bits 14-15 Monitor type (1-mono, 2-color, 3-hybrid) * reset after status is returned VIII. IBM 3270 PC API Function Subset Supported by Novell 3270 Products The low level API function calls we have implemented are marked with an 'x'. IBM 3270 PC API FUNCTIONS IMPLEMENTED -------------------------- ----------- 3270 KEYSTROKE EMULATION SERVICE CONNECT FOR 3270 KEYSTROKE EMULATION DISCONNECT FOR 3270 KEYSTROKE EMULATION READ AID KEY COPY SERVICE REQUEST COPY STRING X COPY BLOCK CONNECT FOR COPY TO PC SESSION DISCONNECT FOR COPY TO PC SESSION ENVIRONMENT MANAGER SERVICES IDENTIFY RESOURCES MANAGER ADD RESOURCE DELETE RESOURCE QUERY RESOURCE SUSPEND/RESUME ENVIRONMENT STOP/RESET ENVIRONMENT QUERY TASK'S ENVIRONMENT ID QUERY ENVIRONMENT FIXED-LENGTH QUEUE MANAGEMENT ENQUEUE DATA X DEQUEUE DATA X PURGE QUEUE DATA X HOST INTERACTIVE SERVICE REQUESTS CONNECT TO HOST SESSION X DISCONNECT FROM HOST SESSION X READ STRUCTURED FIELD X WRITE STRUCTURED FIELD X DEFINE BUFFER X INTERRUPT HANDLER MANAGEMENT INSTALL A HARDWARE INTERRUPT HANDLER INSTALL AN INTERRUPT HANDLER QUERY INTERRUPT VECTOR CONTENTS REMOVE AN INTERRUPT HANDLER KEYBOARD SERVICE CONNECT TO KEYBOARD X DISCONNECT FROM KEYBOARD X READ INPUT X WRITE KEYSTROKE X DISABLE INPUT X ENABLE INPUT X POST STATUS CODE LOGICAL TIMER MANAGEMENT GET LOGICAL TIMER SET LOGICAL TIMER RELEASE LOGICAL TIMER MULTIPLE DOS SUPPORT SERVICE QUERY ENVIRONMENT SIZE ASYNCHRONOUS DOS/FUNCTION REQUESTS GET STORAGE FREE STORAGE SET STORAGE ALLOCATION OPERATOR INFORMATION AREA SERVICE REQUESTS READ OPERATOR INFORMATION AREA IMAGE X READ OPERATOR INFORMATION AREA GROUP X PRESENTATION SPACE SERVICE DEFINE PRESENTATION SPACE DELETE PRESENTATION SPACE DISPLAY PRESENTATION SPACE SET CURSOR POSITION SWITCH PRESENTATION SPACE REQUEST SERVICES MAKE A REQUEST X GET A REQUEST REPLY TO REQUEST GET REQUEST COMPLETION SEND A SIGNAL TO A TASK SEMAPHORE MANAGEMENT CLAIM A SEMAPHORE X RELEASE A SEMAPHORE X QUERY A SEMAPHORE X SESSION INFORMATION QUERY SESSION ID X QUERY SESSION PARAMETERS X DETACH SESSION ID ATTACH SESSION ID QUERY WINDOWS IN ENVIRONMENT QUERY ENVIRONMENT OF WINDOW QUERY PC SESSION PIF INFORMATION QUERY BASE WINDOW QUERY SESSION CURSOR X SUPERVISOR SERVICES NAME RESOLUTION X GET REQUEST COMPLETION X CREATE FIXED-LENGTH QUEUE ENTRY X DEQUEUE DATA X DELETE ENTRY X SUPERVISORY OBJECT SERVICES CREATE TASK ENTRY X CREATE COMPONENT ENTRY X CREATE SEMAPHORE ENTRY X CREATE FIXED-LENGTH QUEUE ENTRY X CREATE GATE ENTRY X CREATE USER EXIT TABLE ENTRY INSTALL USER EXIT TABLE ENTRY NAME RESOLUTION X ID RESOLUTION X DELETE ENTRY X TASK STATE MODIFIER QUERY ACTIVE TASK X SET TASK "READ" SET TASK "UNREADY" SET TASK "PREEMPTABLE" CHANGE TASK'S PRIORITY RETURN TO DISPATCHER TRANSLATE SERVICE TRANSLATE DATA WINDOW MANAGEMENT SERVICES CONNECT TO WORK STATION CONTROL DISCONNECT FROM WORK STATION CONTROL ADD WINDOW CHANGE WINDOW POSITION ON SCREEN CHANGE WINDOW SIZE CHANGE WINDOW COLOR CHANGE WINDOW POSITION ON PRESENTATION SPACE CHANGE HIDDEN STATE CHANGE ENLARGE STATE CHANGE SCREEN BACKGROUND QUERY WINDOW POSITION ON SCREEN QUERY WINDOW SIZE QUERY WINDOW COLORS QUERY WINDOW POSITION ON PRESENTATION SPACE QUERY HIDDEN STATE QUERY ENLARGE STATE QUERY SCREEN BACKGROUND COLOR QUERY WINDOW NAMES CLEAR SCREEN SELECT ACTIVE WINDOW REDRAW SCREEN REDRAW WINDOW DELETE WINDOW QUERY ACTIVE WINDOW QUERY ACTIVE SCREEN QUERY WINDOW ATTRIBUTES CHANGE WINDOW ATTRIBUTES SELECT ACTIVE SCREEN