10!OUTPUT 2 USING "#,K";"<lf>REN<cr>INDENT<cr>RE-STORE ""CNFG""<cr>"
20!EDIT Module_start
30    !**********************************************************************
40    !
50    !
60    !                           CNFG file
70    !
80    ! This is the CNFG file.  It is used to examine the hardware
90    ! configuration of an HP3565S system.  This file contains a configuration
100   ! spreadsheet.  This spreadsheet has a line for each hardware module
110   ! in the system (except the HP-IB module).  The line contains information
120   ! about the location and type of module, and allows the user to give the
130   ! module a name (such as 'Left Wing', or 'Reference').  It also allows
140   ! the user to make a module active or inactive.  Inactive modules are
150   ! treated by all files as though they are not in the system at all.
160   !
170   ! All files except the actual hardware driver file (HW) refer to modules
180   ! by their names rather than by their addresses.  Because of this, there
190   ! is a set of routines for talking to the hardware that accept module
200   ! names rather than addresses, find the address for that module, and
210   ! make the appropriate call to the HW file.
220   !
230   ! There are also some 'utility' subprograms, which do things like convert
240   ! module names to the corresponding address, return the type of module,
250   ! or determine whether a name is valid or not.
260   !
270   ! The following is a list of the subprograms which can be called by other
280   ! files.  Additional documentation can be found in-line at each
290   ! subprogram.
300   !
310   !
320   ! Subprograms available to the user :
330   !
340   !     Cnfg_cnfg                 - powerup initization
350   !     Cnfg_init                 - should be called when an application
360   !                                 is re-run, and after Cnfg_cnfg.
370   !     Cnfg_spread(Modified)     - the configuration spreadsheet
380   !          Output : Modified, 1 if the spreadsheet changed, otherwize 0
390   !     FNCnfg_get_modnum(Label$) - converts user label to module address
400   !     FNCnfg_get_label$(Modnum) - converts module address to user label
410   !     FNCnfg_get_global(Label$)
420   !          Returns the global class number for a given label.  If the
430   !          label is a module label rather than a global class label,
440   !          this function returns 0.
450   !     Cnfg_labels(Type$,Labels$(*),Num_labels)
460   !          Input :   Type$, a string that is one of
470   !                      "ALL"        - for all active modules
480   !                      "ALL INPUT"  - for all active inputs
490   !                      "ALL SOURCE" - for all active sources
500   !          Outputs : Labels$(*), a string array that is a list of the
510   !                      valid user labels for the class of modules
520   !                      specified by Type$.
530   !                    Num_labels, a number that tells how many valid
540   !                      labels there are in Labels$(*).  If this number
550   !                      is non-zero, Labels$(*) will have been REDIMed
560   !                      to this size.
570   !     FNCnfg_good_label(Label$) - Returns 1 if Label$ is one of the
580   !                      user labels for an active module.
590   !     FNCnfg_okay_label(Label$) - Returns 1 if Label$ is one of the
600   !                      user labels for an active or inactive module.
610   !     FNCnfg_type$(Label$)      - Returns what type of module is
620   !                      represented by Label$.  The response will be
630   !                      either "Source", "Input", or "Other".
640   !     Cnfg_cmd(Label$,Command$,OPTIONAL Timeout_time)
650   !          Inputs  : Label$ - if it is one of "ALL", "ALL SOURCE", or
660   !                      "ALL INPUT" it specified that a global command
670   !                      be sent to that class of (active) modules.
680   !                      Otherwise, the Label$ is interpreted as one of
690   !                      the user labels for a particular channel, and
700   !                      the command is sent to that channel.
710   !                    Command$ - the command string to be sent.
720   !                    Timeout_time - How long the hardware should wait
730   !                      before giving up trying.  If zero or not given,
740   !                      it means no timeout (wait forever).
750   !     FNCnfg_cmd_rsp$(Label$,Query$,OPTIONAL Timeout_time)
760   !          Exactly like Cnfg_cmd except that a response is looked
770   !          for after the command is sent.  It is illegal to use the
780   !          global labels.
790   !     FNCnfg_rsp$(Label$,OPTIONAL Timeout_time)
800   !          Exactly like FNCnfg_cmd_rsp$ except no command is sent
810   !          before the response is looked for.
820   !     Cnfg_wait_rdy(Label$,OPTIONAL Timeout_time)
830   !          Waits for the module specified by Label$ to have its ready
840   !          bit in the software status register set.  The Timeout-time,
850   !          if specified, says how long the maximum wait should be.  It
860   !          is illegal to use the global labels.
870   !     Cnfg_rst(Label$,OPTIONAL Timeout_time)
880   !          Resets the specified module.  It is illegal to use the global
890   !          labels.
900   !     FNCnfg_rmst(Label$,OPTIONAL Timeout_time)
910   !          Reads the module status register for the specified module.
920   !          It is illegal to use the global labels.
930   !     Cnfg_save(@File,Ok)
940   !          Attempts to save the current configuration in file @File.
950   !          Ok is returned 1 if successful, 0 otherwise.
960   !     Cnfg_load(@File,Ok)
970   !          Attempts to load a configuration from file @File.
980   !          Ok is returned 1 if successful, 0 otherwise.  Note
990   !          that a configuration can only be successfully loaded if
1000  !          the hardware present matches the hardware that was
1010  !          present when the save was done, including which kind of
1020  !          modules were present in which slots.
1030  !
1040  !
1050 Module_start:!
1060!LOADSUB ALL FROM "HW"
1070!LOADSUB ALL FROM "USER"
1080!LOADSUB ALL FROM "LIB"
1090!DELSUB Hw_hw TO END
1100  !
1110  FOR I=0 TO 23
1120    ON KEY I GOSUB Cnfg_test_dummy
1130  NEXT I
1140  Dummy=FNUser_get_key
1150  LOOP
1160    Cnfg_cnfg
1170    Cnfg_spread(Modified)
1180    PRINT "Modified = ";Modified
1190    WAIT .5
1200  END LOOP
1210 Cnfg_test_dummy:RETURN 
1220  END
1230  !************************************************************************
1240  !
1250  !     Start of subroutines
1260  !
1270  !************************************************************************
1280 Cnfg_cnfg:SUB Cnfg_cnfg
1290    !
1300    ! This should be called the first time this module is loaded.  It
1310    ! contains a definition of all the common variables, and calls
1320    ! Cnfg_powerup, which initializes the configuration spreadsheet.
1330    !
1340    COM /Cnfg_str/ Box$(1:8,1:64)[20],Title$(1:8,0:2)[20],Prompt$(1:8)[80]
1350    COM /Cnfg_num/ Col_width(1:8),Modify_col,INTEGER Num_mods,Max_col
1360    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
1370    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
1380    COM /Cnfg_types/ Input$[20],Source$[20],Other$[20]
1390    COM /Cnfg_globals/ All$[20],All_source$[20],All_input$[20]
1400    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(1:32),Hp_ib_address
1410    COM /Cnfg_rowcol/ Row,Col,Start_row
1420    COM /Cnfg_cfg/ Config_str$[255]
1430    !
1440    ! Box$ is an array of boxes for the configuration spreadsheet.
1450    ! Title$ is an array of titles for each column of the spreadsheet.
1460    ! Prompt$ is an array of prompts for each column of the spreadsheet.
1470    ! Col_width is an array of column widths for the spreadsheet.
1480    ! Modify_col is the first column in the spreadsheet that the user
1490    !    can change.
1500    ! Num_mods is the number of modules in the system.
1510    ! Max_col is the number of columns in the spreadsheet.
1520    ! Address_col through Active_col are variables assigned to the
1530    !    appropriate column number.
1540    ! Input$, Source$, and Other$ are the possible strings that can go in
1550    !    the module type column of the spreadsheet.
1560    ! All$, All_source$, and All_input$ are the reserved labels for global
1570    !    commands.
1580    ! Hp_ib_array is an array of the possible HP-IB locations where an
1590    !    HP3565S system has been found.
1600    ! Hp_ib_address is the currently selected HP-IB location.
1610    ! Row, Col and Start_row define the position of the cursor in the
1620    !    spreadsheet.  They are in common so that the position will be
1630    !    remembered.
1640    ! Config_str$ is used to remember the original configuration returned
1650    !    by the HP-IB module.
1660    !
1670    Cnfg_powerup
1680  SUBEND
1690 Cnfg_powerup:SUB Cnfg_powerup
1700    !
1710    ! This is called only by Cnfg_cnfg, the first time the CNFG file is
1720    ! loaded.  It picks a default HP-IB location, assigns default labels
1730    ! to all the hardware modules found there, and makes every module
1740    ! active.  Constant variables (like Address_col) are defined here.
1750    !
1760    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
1770    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
1780    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
1790    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
1800    COM /Cnfg_types/ Input$,Source$,Other$
1810    COM /Cnfg_globals/ All$,All_source$,All_input$
1820    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(*),Hp_ib_address
1830    COM /Cnfg_rowcol/ Row,Col,Start_row
1840    INTEGER Unchecked_array(1:32),Failed_once
1850    !
1860    ! Col width   Title1      Title2        Prompt
1870    !
1880    DATA   9,   "Module",   "Address",        ""
1890    DATA   9,   "MF,Slot",  "",               ""
1900    DATA   10,  "Product",  "ID",             ""
1910    DATA   14,  "Serial",   "Number",         ""
1920    DATA   9,   "Product",  "Type",           ""
1930    DATA   16,  "Channel",  "Name",    "Enter new name for channel"
1940    DATA   6,   "Active",   "",        "Is this an active channel (Yes/No)"
1950    !
1960    !     First, initialize global constants
1970    !
1980    Input$="Input"                  ! Used in the Type column
1990    Source$="Source"                ! Used in the Type column
2000    Other$="Other"                  ! Used in the Type column
2010    All$="ALL"                      ! Reserved label for global commands
2020    All_input$="ALL INPUT"          ! Reserved label for global commands
2030    All_source$="ALL SOURCE"        ! Reserved label for global commands
2040    Max_col=7                       ! Number of columns used
2050    Modify_col=6                    ! First column that the user can modify
2060    Address_col=1                   ! Column where address will be found
2070    Mf_add_col=2                    ! Column where mainframe,slot is
2080    Id_col=3                        ! Column for module id
2090    Serial_col=4                    ! Column for module serial number
2100    Type_col=5                      ! Column for module type
2110    Label_col=6                     ! Column for user-defined label
2120    Active_col=7                    ! Column for active/inactive
2130    Hp_ib_address=0                 ! Don't yet know HP-IB address
2140    Start_row=1                     ! Start row for cnfg_spread
2150    Row=2                           ! Initialize row for cnfg_spread
2160    Col=5                           ! Initialize col for cnfg_spread
2170    FOR I=1 TO Max_col              ! Read the above data statements
2180      READ Col_width(I),Title$(I,1),Title$(I,2),Prompt$(I)
2190    NEXT I
2200    Title$(1,0)="Configuration Menu"
2210    !
2220    Failed_once=0
2230    REPEAT
2240      REDIM Hp_ib_array(1:32)
2250      Hw_get_dev_sels(Hp_ib_array(*),Unchecked_array(*))
2260      IF Hp_ib_array(1)<=0 THEN 
2270        Failed_once=1
2280        User_clr_scr
2290        ON ERROR GOTO Cnfg_no_7
2300        ABORT 7         ! The most likely select code for HP-IB modules.
2310 Cnfg_no_7:ON ERROR GOTO Cnfg_no_8
2320        ABORT 8         ! The next most likely.
2330 Cnfg_no_8:OFF ERROR 
2340        OUTPUT CRT;""
2350        OUTPUT CRT;"No HP-IB Modules Found Yet, But I'll Try Again..."
2360        OUTPUT CRT;""
2370        BEEP 
2380        Cnfg_unchecked(Unchecked_array(*))
2390        WAIT .05        ! Give them a little time to recover
2400      END IF
2410    UNTIL Hp_ib_array(1)>0
2420    IF Failed_once THEN CALL User_clr_scr
2430    Hp_ib_address=Hp_ib_array(1)
2440    Hw_set_dev_sel(Hp_ib_address)
2450    Cnfg_init_boxes
2460    !
2470  SUBEND
2480 Cnfg_pick_hp_ib:SUB Cnfg_pick_hp_ib
2490    !
2500    ! Cnfg_pick_hp_ib sets up a spreadsheet for choosing the HP-IB location
2510    ! of the HP3565S system that you wish to use.  Each available location
2520    ! is given one line in the spreadsheet.  Just before the spreadsheet
2530    ! is entered, a message is printed on the screen telling which
2540    ! could not be checked to see if there was a system there.  Normally
2550    ! this subprogram should only be called by the configuration
2560    ! spreadsheet.
2570    !
2580    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(*),Hp_ib_address
2590    !
2600    !   The following variables are NOT the same as the global
2610    !   variables of the same name.  They are used only locally for
2620    !   picking the HP-IB address to be used.
2630    !
2640    DIM Box$(1:3,1:32)[20],Title$(1:3,0:2)[20],Prompt$(1:3)[80]
2650    DIM Col_width(1:3)
2660    INTEGER Unchecked_array(1:32),Done
2670    !
2680    ! Col Width    Title1               Title2           Prompt
2690    DATA  20,  "HP-IB Location",        "",              ""
2700    DATA  20,  "HP-IB Module",          "Serial Number", ""
2710    DATA  20,  "Current Selection",     ""
2720    DATA "Hit 'Select' To Select This System Or 'Abort' To Return To Old"
2730    INTEGER I,Hp_ib_col,Serial_col,Select_col,Dummy
2740    REDIM Hp_ib_array(1:32)
2750    Hw_get_dev_sels(Hp_ib_array(*),Unchecked_array(*))
2760    IF FNHw_io_error THEN 
2770      IF Hp_ib_array(1)<=0 THEN 
2780        User_error("No HP-IB Modules Found!")
2790      ELSE
2800        User_error("Too Many HP-IB Modules.  Using the first 32.")
2810      END IF
2820    END IF
2830    IF Hp_ib_array(1)>0 THEN 
2840      IF 0 THEN ! SIZE(Hp_ib_array,1)=1 THEN
2850        Hp_ib_address=Hp_ib_array(1)
2860      ELSE
2870        User_clr_scr
2880        Cnfg_unchecked(Unchecked_array(*))
2890        WAIT 2.5
2900        !
2910        REDIM Box$(1:3,1:SIZE(Hp_ib_array,1))
2920        FOR I=1 TO 3
2930          READ Col_width(I),Title$(I,1),Title$(I,2),Prompt$(I)
2940        NEXT I
2950        FOR I=1 TO 2
2960          Prompt$(I)=Prompt$(3)   ! prompts go with rows if one column
2970        NEXT I
2980        Title$(1,0)="Select HP-IB"
2990        Hp_ib_col=1
3000        Serial_col=2
3010        Select_col=3
3020        FOR I=1 TO SIZE(Hp_ib_array,1)
3030          Hw_set_dev_sel(Hp_ib_array(I))
3040          Box$(Hp_ib_col,I)=VAL$(Hp_ib_array(I))
3050          Box$(Serial_col,I)=FNHw_cmd_rsp$("SER?")
3060          Box$(Select_col,I)=""
3070        NEXT I
3080        !
3090        Col=3
3100        Row=1
3110        Start_row=1
3120        Modify_col=3
3130        ON KEY 5 LABEL FNUser_keylabel$("Abort") GOSUB Cnfg_hp_ib_dumm
3140        ON KEY 6 LABEL FNUser_keylabel$("Select") GOSUB Cnfg_hp_ib_dumm
3150        ON KEY 7 LABEL "" GOSUB Cnfg_hp_ib_dumm
3160        ON KEY 8 LABEL "" GOSUB Cnfg_hp_ib_dumm
3170        User_clr_scr
3180        REPEAT
3190          User_spread(Box$(*),Title$(*),Prompt$(*),New_entry$,Col_width(*),Modify_col,Col,Row,Start_row)
3200          SELECT FNUser_check_key
3210          CASE 5   ! Abort
3220            IF Hp_ib_address=0 THEN Hp_ib_address=Hp_ib_array(1)
3230            Done=1
3240          CASE 6   ! Select
3250            IF Row<=SIZE(Hp_ib_array,1) THEN 
3260              Hp_ib_address=Hp_ib_array(Row)
3270            ELSE
3280              User_error("You can't select that address.  Using old address.")
3290              IF Hp_ib_address=0 THEN Hp_ib_address=Hp_ib_array(1)
3300            END IF
3310            Done=1
3320          CASE ELSE
3330            BEEP 
3340          END SELECT
3350          Dummy=FNUser_get_key
3360        UNTIL Done
3370        User_clr_scr
3380      END IF
3390      !
3400      Hw_set_dev_sel(Hp_ib_address)
3410    END IF
3420    SUBEXIT
3430 Cnfg_hp_ib_dumm:RETURN 
3440  SUBEND
3450 Cnfg_init_boxes:SUB Cnfg_init_boxes
3460    !
3470    ! Cnfg_init_boxes initializes the boxes in the configuration
3480    ! spreadsheet.  Each module is given a default name, and every
3490    ! module (except unknown or unidentifiable ones) is made active.
3500    !
3510    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
3520    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
3530    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
3540    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
3550    COM /Cnfg_types/ Input$,Source$,Other$
3560    COM /Cnfg_cfg/ Config_str$
3570    DIM Temp_str$[255],Id$[20]
3580    INTEGER Hp_ib_slot,Modnum_array(1:63),I
3590    INTEGER Source_count,Input_count,Other_count
3600    !
3610    !     First, get module address array
3620    !
3630    Config_str$=FNHw_cmd_rsp$("CFG?",10)
3640    IF FNHw_io_error THEN 
3650      OUTPUT CRT;CHR$(12)
3660      User_clr_scr
3670      OUTPUT CRT;"CFG? command to HP-IB module timed out."
3680      OUTPUT CRT;"You probably have a fast-bus problem."
3690      SUBEXIT
3700    END IF
3710    ENTER Config_str$;Hp_ib_slot,Num_mods
3720    IF Num_mods>0 THEN 
3730      Hw_gbl_cmd(127,"RST;CLAS",10)                 ! Reset all modules
3740      Temp_str$=Config_str$[POS(Config_str$,",")+1] ! strip off 1st num
3750      Temp_str$=Temp_str$[POS(Temp_str$,",")+1]     ! strip off 2nd num
3760      REDIM Modnum_array(1:Num_mods)
3770      ENTER Temp_str$;Modnum_array(*)               ! get modnum array
3780    END IF
3790    REDIM Box$(1:Max_col,1:Num_mods+1)
3800    !
3810    !     Now, go through and initialize Box$
3820    !
3830    Box$(Address_col,1)="All"
3840    FOR I=Mf_add_col TO Active_col
3850      Box$(I,1)=""
3860    NEXT I
3870    !
3880    Source_count=0
3890    Input_count=0
3900    Other_count=0
3910    FOR I=2 TO Num_mods+1
3920      Mod_addr=Modnum_array(I-1)
3930      Box$(Address_col,I)=VAL$(Mod_addr)
3940      Box$(Mf_add_col,I)=VAL$(Mod_addr DIV 8)&" , "&VAL$(Mod_addr MOD 8)
3950      Id$=FNHw_mod_cmd_rsp$(Mod_addr,"ID?",10)
3960      Box$(Id_col,I)=Id$
3970      Box$(Serial_col,I)=TRIM$(FNHw_mod_cmd_rsp$(Mod_addr,"SER?",10))
3980      IF Id$="HP35652A" THEN 
3990        Box$(Type_col,I)=Input$
4000        Input_count=Input_count+1
4010        Box$(Label_col,I)="Input "&VAL$(Input_count)
4020        Hw_mod_cmd(Mod_addr,"CLAS 1,2",10)
4030        IF FNHw_io_error THEN 
4040          Box$(Type_col,I)=Other$
4050        ELSE
4060          Box$(Active_col,I)="*"
4070        END IF
4080      ELSE
4090        IF Id$="HP35653A" THEN 
4100          Box$(Type_col,I)=Source$
4110          Source_count=Source_count+1
4120          Box$(Label_col,I)="Source "&VAL$(Source_count)
4130          Hw_mod_cmd(Mod_addr,"CLAS 1,3",10)
4140          IF FNHw_io_error THEN 
4150            Box$(Type_col,I)=Other$
4160          ELSE
4170            Box$(Active_col,I)="*"
4180          END IF
4190        ELSE
4200          Box$(Type_col,I)=Other$
4210          Other_count=Other_count+1
4220          Box$(Label_col,I)="Other "&VAL$(Other_count)
4230          Hw_mod_cmd(Mod_addr,"CLAS",10)
4240          Box$(Active_col,I)=""
4250        END IF
4260      END IF
4270    NEXT I
4280  SUBEND
4290 Cnfg_spread:SUB Cnfg_spread(Modified)
4300    !
4310    ! This is the configuration spreadsheet.  The Modified parameter
4320    ! is set to zero if no changes are made to the spreadsheet, or
4330    ! to one if there are changes.  This subprogram brings up the
4340    ! spreadsheet, and stays in it until one of the four 'firmkeys'
4350    ! or the 'Done' softkey is pressed.  While in the spreadsheet,
4360    ! modules can be made active or inactive and can be given new
4370    ! names.
4380    !
4390    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
4400    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
4410    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
4420    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
4430    COM /Cnfg_types/ Input$,Source$,Other$
4440    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(*),Hp_ib_address
4450    COM /Cnfg_rowcol/ Row,Col,Start_row
4460    COM /Cnfg_cfg/ Config_str$
4470    DIM New_entry$[255],Ch$[10]
4480    INTEGER Done,Dummy,I,Old_address,Bool,Strt_row,Stop_row
4490    Modified=0
4500 Start:!
4510    User_clr_scr
4520    WHILE Hp_ib_address=0
4530      Cnfg_pick_hp_ib
4540      Modified=1
4550    END WHILE
4560    IF NOT Modified THEN 
4570      New_entry$=FNHw_cmd_rsp$("CFG?",10)
4580      IF FNHw_io_error THEN 
4590        Modified=1
4600      ELSE
4610        Modified=New_entry$<>Config_str$
4620        IF Modified THEN CALL User_error("Hardware Configuration Changed - Resetting CNFG")
4630      END IF
4640    END IF
4650    IF Modified THEN CALL Cnfg_init_boxes
4660    IF Num_mods<>0 THEN 
4670      ON KEY 5 LABEL FNUser_keylabel$("Select HP-IB") GOSUB Cnfg_dummy
4680      ON KEY 6 LABEL FNUser_keylabel$("EXIT") GOSUB Cnfg_dummy
4690      ON KEY 7 LABEL FNUser_keylabel$("Inputs Active") GOSUB Cnfg_dummy
4700      ON KEY 8 LABEL FNUser_keylabel$("Toggle") GOSUB Cnfg_dummy
4710      Done=0
4720      REPEAT
4730        User_spread(Box$(*),Title$(*),Prompt$(*),New_entry$,Col_width(*),Modify_col,Col,Row,Start_row)
4740        SELECT FNUser_check_key
4750        CASE 0         ! Not one of the softkeys or the firmkeys
4760          GOSUB Cnfg_new_entry
4770        CASE 5         ! Select HP-IB
4780          Dummy=FNUser_get_key
4790          Old_address=Hp_ib_address
4800          Cnfg_pick_hp_ib
4810          IF Hp_ib_address<>Old_address THEN 
4820            Cnfg_init_boxes
4830            Modified=1
4840          END IF
4850        CASE 6         ! Done
4860          Dummy=FNUser_get_key
4870          Done=1
4880        CASE 7         ! Inputs Active
4890          Dummy=FNUser_get_key
4900          GOSUB Cnfg_inp_active
4910        CASE 8         ! Toggle
4920          Dummy=FNUser_get_key
4930          GOSUB Cnfg_toggle
4940        CASE ELSE      ! One of the firmkeys, let someone else handle it
4950          Done=1
4960        END SELECT
4970      UNTIL Done
4980      User_clr_scr
4990    ELSE
5000      OUTPUT CRT;""
5010      OUTPUT CRT;"          No Modules In This System"
5020      OUTPUT CRT;""
5030      ON KEY 5 LABEL FNUser_keylabel$("Done"),5 GOTO Cnfg_done
5040      ON KEY 6 LABEL FNUser_keylabel$("Select HP-IB"),5 GOTO Cnfg_hp_ib
5050      ON KEY 7 GOSUB Cnfg_dummy
5060      ON KEY 8 GOSUB Cnfg_dummy
5070      LOOP
5080      END LOOP
5090    END IF
5100 Cnfg_done:!
5110    SUBEXIT
5120    !
5130 Cnfg_dummy:RETURN 
5140 Cnfg_new_entry:!
5150    New_entry$=TRIM$(New_entry$)
5160    IF New_entry$<>"" THEN 
5170      SELECT Col
5180      CASE Label_col
5190        IF Row=1 THEN 
5200          BEEP 
5210        ELSE
5220          New_entry$=New_entry$[1;16]                   ! Only 16 letters
5230          IF UPC$(Box$(Col,Row))<>UPC$(New_entry$) THEN ! Label changed
5240            IF NOT FNCnfg_okay_label(New_entry$) THEN   ! Label not used
5250              IF NOT FNCnfg_get_global(New_entry$) THEN ! Not reserved label
5260                Box$(Col,Row)=New_entry$                ! Assign new label!
5270                Modified=1                              ! Things changed
5280              END IF
5290            END IF
5300          ELSE
5310            IF Box$(Col,Row)<>New_entry$ THEN           ! Different cases
5320              Box$(Col,Row)=New_entry$                  ! Assign it
5330              Modified=1
5340            END IF
5350          END IF
5360        END IF
5370      CASE Active_col
5380        Ch$=UPC$(New_entry$[1;1])
5390        Bool=(Ch$="Y" OR Ch$="A" OR Ch$="*")
5400        Ch$=""
5410        IF Bool THEN Ch$="*"
5420        IF Row=1 THEN 
5430          Strt_row=2
5440          Stop_row=Num_mods+1
5450        ELSE
5460          Strt_row=Row
5470          Stop_row=Row
5480        END IF
5490        FOR I=Strt_row TO Stop_row
5500          Cnfg_set_active((I),Ch$,Modified)
5510        NEXT I
5520      END SELECT
5530    END IF
5540    RETURN 
5550 Cnfg_toggle:!
5560    IF Col=Active_col THEN 
5570      IF Row=1 THEN 
5580        Strt_row=2
5590        Stop_row=Num_mods+1
5600      ELSE
5610        Strt_row=Row
5620        Stop_row=Row
5630      END IF
5640      FOR I=Strt_row TO Stop_row
5650        Ch$=""
5660        IF Box$(Col,I)="" THEN Ch$="*"
5670        Cnfg_set_active((I),Ch$,Modified)
5680      NEXT I
5690    END IF
5700    RETURN 
5710 Cnfg_inp_active:!
5720    FOR I=2 TO Num_mods+1
5730      Ch$=""
5740      IF Box$(Type_col,I)=Input$ THEN Ch$="*"
5750      Cnfg_set_active((I),Ch$,Modified)
5760    NEXT I
5770    RETURN 
5780 Cnfg_hp_ib:!
5790    Old_address=Hp_ib_address
5800    Cnfg_pick_hp_ib
5810    IF Old_address<>Hp_ib_address THEN Modified=1
5820    GOTO Start
5830  SUBEND
5840  !**********************************************************************
5850  !
5860  !     The *real* configuration stuff
5870  !
5880  !**********************************************************************
5890 Cnfg_get_modnum:DEF FNCnfg_get_modnum(Label$)
5900    !
5910    ! Converts user name Label$ into the corresponding hardware address.
5920    !
5930    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
5940    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
5950    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
5960    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
5970    DIM Temp$[20]
5980    INTEGER I
5990    Temp$=TRIM$(UPC$(Label$))
6000    FOR I=2 TO Num_mods+1
6010      IF UPC$(Box$(Label_col,I))=Temp$ THEN 
6020        RETURN VAL(Box$(Address_col,I)) ! Slot address
6030      END IF
6040    NEXT I
6050    User_stop("Illegal call - FNCnfg_get_modnum("""&Label$&""")")
6060    RETURN 0
6070  FNEND
6080 Cnfg_get_label:DEF FNCnfg_get_label$(Modnum)
6090    !
6100    ! Converts hardware addres Modnum into the corresponding user label.
6110    !
6120    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
6130    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
6140    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
6150    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
6160    INTEGER I
6170    FOR I=2 TO Num_mods+1
6180      IF VAL(Box$(Address_col,I))=Modnum THEN RETURN Box$(Label_col,I)
6190    NEXT I
6200    User_stop("Illegal call - FNCnfg_get_label$("""&VAL$(Modnum)&""")")
6210    RETURN ""
6220  FNEND
6230 Cnfg_get_global:DEF FNCnfg_get_global(Label$)
6240    !
6250    ! If Label$ is not one of the reserved global labels, this function
6260    ! returns zero.  If it IS one of the reserved global labels, this
6270    ! function returns the global class number for that label.
6280    !
6290    COM /Cnfg_globals/ All$,All_source$,All_input$
6300    IF UPC$(Label$)=All$ THEN RETURN 1
6310    IF UPC$(Label$)=All_input$ THEN RETURN 2
6320    IF UPC$(Label$)=All_source$ THEN RETURN 3
6330    RETURN 0
6340  FNEND
6350 Cnfg_labels:SUB Cnfg_labels(Type$,Labels$(*),Num_labels)
6360    !
6370    ! Type$ is an input that must be one of :
6380    !            "ALL"        - for all active modules
6390    !            "ALL SOURCE" - for all active sources
6400    !            "ALL INPUT"  - for all active inputs
6410    ! Labels$ is returned as an array of the user labels for the class
6420    ! of modules specified by Type$.  Num_labels is the number of valid
6430    ! elements in the Labels$ array.  If Num_labels is not zero,
6440    ! Labels$ is REDIMed to this size.
6450    !
6460    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
6470    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
6480    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
6490    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
6500    COM /Cnfg_types/ Input$,Source$,Other$
6510    COM /Cnfg_globals/ All$,All_source$,All_input$
6520    DIM Temp1$[20],Temp2$[20]
6530    INTEGER I
6540    IF Num_mods<>0 THEN REDIM Labels$(1:Num_mods)
6550    Num_labels=0
6560    IF UPC$(Type$)=All_source$ THEN         ! Sources
6570      Temp1$=Source$
6580      Temp2$=""
6590    ELSE
6600      IF UPC$(Type$)=All_input$ THEN        ! Inputs
6610        Temp1$=Input$
6620        Temp2$=""
6630      ELSE
6640        IF UPC$(Type$)=All$ THEN            ! All modules
6650          Temp1$=Source$
6660          Temp2$=Input$
6670        ELSE                                ! Unknown module type
6680          Temp1$=""
6690          Temp2$=""
6700        END IF
6710      END IF
6720    END IF
6730    FOR I=2 TO Num_mods+1
6740      IF Box$(Type_col,I)=Temp1$ OR Box$(Type_col,I)=Temp2$ THEN 
6750        IF Box$(Active_col,I)<>"" THEN ! Module is active
6760          Num_labels=Num_labels+1
6770          Labels$(Num_labels)=Box$(Label_col,I)
6780        END IF
6790      END IF
6800    NEXT I
6810    IF Num_labels<>0 THEN REDIM Labels$(1:Num_labels)
6820  SUBEND
6830 Cnfg_good_label:DEF FNCnfg_good_label(Label$)
6840    !
6850    ! Returns 1 if Label$ is one of the user labels for active
6860    ! modules.  Otherwise returns zero.  Compare with Cnfg_okay_label.
6870    !
6880    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
6890    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
6900    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
6910    DIM Temp$[20]
6920    INTEGER I
6930    Temp$=TRIM$(UPC$(Label$))
6940    FOR I=2 TO Num_mods+1
6950      IF UPC$(Box$(Label_col,I))=Temp$ THEN 
6960        IF Box$(Active_col,I)="" THEN 
6970          RETURN 0
6980        ELSE
6990          RETURN 1
7000        END IF
7010      END IF
7020    NEXT I
7030    RETURN 0
7040  FNEND
7050  !********************************************************************
7060  !
7070  !     Stuff to pass through to HW
7080  !
7090  !********************************************************************
7100 Cnfg_cmd:SUB Cnfg_cmd(Label$,Command$,OPTIONAL Timeout_time)
7110    !
7120    ! Sends command Command$ to the module specified by Label$.
7130    ! If Label$ is a user label, the command goes just to that module.
7140    ! If Label$ is one of the reserved global labels, the command goes
7150    ! to all modules in that global class.  Timeout_time is how long
7160    ! the hardware should keep trying to send the command before giving
7170    ! up.  If it is zero or not given, the hardware will keep trying
7180    ! forever until it is successful.
7190    !
7200    Timeout=0
7210    IF NPAR>2 THEN Timeout=Timeout_time
7220    Global=FNCnfg_get_global(Label$)
7230    IF Global THEN 
7240      Hw_gbl_cmd(Global,Command$,Timeout)
7250    ELSE
7260      Hw_mod_cmd(FNCnfg_get_modnum(Label$),Command$,Timeout)
7270    END IF
7280  SUBEND
7290 Cnfg_cmd_rsp:DEF FNCnfg_cmd_rsp$(Label$,Query$,OPTIONAL Timeout_time)
7300    !
7310    ! This is exactly like Cnfg_cmd except that a response is looked for
7320    ! after the command is sent.  This function returns the response.
7330    ! It is illegal to use the global labels, since it is impossible to
7340    ! read a global response.
7350    !
7360    Timeout=0
7370    IF NPAR>2 THEN Timeout=Timeout_time
7380    IF FNCnfg_get_global(Label$) THEN 
7390      User_stop("Bad global call to FNCnfg_cmd_rsp$")
7400    ELSE
7410      RETURN FNHw_mod_cmd_rsp$(FNCnfg_get_modnum(Label$),Query$,Timeout)
7420    END IF
7430  FNEND
7440 Cnfg_rsp:DEF FNCnfg_rsp$(Label$,OPTIONAL Timeout_time)
7450    !
7460    ! This is exactly like FNCnfg_cmd_rsp$ except that no command is sent
7470    ! before the reponse is looked for.  Again, global labels are illegal.
7480    !
7490    Timeout=0
7500    IF NPAR>1 THEN Timeout=Timeout_time
7510    IF FNCnfg_get_global(Label$) THEN 
7520      User_stop("Bad global call to FNCnfg_rsp$")
7530    ELSE
7540      RETURN FNHw_mod_rsp$(FNCnfg_get_modnum(Label$),Timeout)
7550    END IF
7560  FNEND
7570 Cnfg_wait_rdy:SUB Cnfg_wait_rdy(Label$,OPTIONAL Timeout_time)
7580    !
7590    ! Waits for the module specified by Label$ to have its ready
7600    ! bit in the software status register set.  The Timeout-time,
7610    ! if specified, says how long the maximum wait should be.  It
7620    ! is illegal to use the global labels.
7630    !
7640    Timeout=0
7650    IF NPAR>1 THEN Timeout=Timeout_time
7660    IF FNCnfg_get_global(Label$) THEN 
7670      User_stop("Bad global call to Cnfg_wait_rdy")
7680    ELSE
7690      Hw_wait_mod_rdy(FNCnfg_get_modnum(Label$),Timeout)
7700    END IF
7710  SUBEND
7720 Cnfg_rst:SUB Cnfg_rst(Label$,OPTIONAL Timeout_time)
7730    !
7740    ! Does a hardware reset on the specified module.  Timeout_time is
7750    ! the maximum length of time to try to reset the module before
7760    ! giving up.  If it is zero or not there, the maximum length is
7770    ! infinite.  It is illegal to use the global labels.
7780    !
7790    Timeout=0
7800    IF NPAR>1 THEN Timeout=Timeout_time
7810    IF FNCnfg_get_global(Label$) THEN 
7820      User_stop("Bad global call to Cnfg_rst")
7830    ELSE
7840      Hw_mod_rst(FNCnfg_get_modnum(Label$),Timeout)
7850    END IF
7860  SUBEND
7870 Cnfg_rmst:DEF FNCnfg_rmst(Label$,OPTIONAL Timeout_time)
7880    !
7890    ! Reads the module status register for the specified module.  This
7900    ! is a hardware read (the module can't tell that it's even being
7910    ! done, so it doesn't disturb or slow down the module), and reads
7920    ! ONLY the BOTTOM 8 BITS of the status register.  Timeout_time is
7930    ! how long to keep trying to do the read before giving up.  If
7940    ! it is zero or not given, the maximum wait is infinite.
7950    !
7960    Timeout=0
7970    IF NPAR>1 THEN Timeout=Timeout_time
7980    IF FNCnfg_get_global(Label$) THEN 
7990      User_stop("Bad global call to FNCnfg_rmst")
8000    ELSE
8010      RETURN FNHw_rmst(FNCnfg_get_modnum(Label$),Timeout)
8020    END IF
8030  FNEND
8040  !****************************************************************
8050  !
8060  !     Misc Stuff
8070  !
8080  !****************************************************************
8090 Cnfg_set_active:SUB Cnfg_set_active(Row,Value$,Modified)
8100    !
8110    ! A subprogram used by the spreadsheet subprogram to set a module
8120    ! active or inactive.  Row specifies which row of the spreadsheet
8130    ! that we're in.  Value$ specifies whether to make the module
8140    ! active or inactive (a null string means inactive).  Modified
8150    ! is returned, and is set to one if the module has changed from
8160    ! active to inactive or inactive to active.
8170    !
8180    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
8190    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
8200    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
8210    COM /Cnfg_types/ Input$,Source$,Other$
8220    DIM Temp$[20]
8230    IF Box$(Active_col,Row)<>Value$ THEN 
8240      IF Box$(Type_col,Row)<>Other$ THEN 
8250        Modified=1
8260        Box$(Active_col,Row)=Value$
8270        IF Value$="" THEN 
8280          Temp$="RST;CLAS"
8290        ELSE
8300          IF Box$(Type_col,Row)=Input$ THEN 
8310            Temp$="CLAS 1,2"
8320          ELSE
8330            Temp$="CLAS 1,3"
8340          END IF
8350        END IF
8360        Hw_mod_cmd(VAL(Box$(Address_col,Row)),Temp$)
8370      END IF
8380    END IF
8390  SUBEND
8400 Cnfg_init:SUB Cnfg_init
8410    !
8420    ! This should be called when an application is re-run.  Cnfg_cnfg
8430    ! doesn't need to be called, but stopping and re-running a program
8440    ! undoes any REDIMS that were done to common variables.  At this
8450    ! time we also re-setup global classes, in case they were messed
8460    ! up by something (Diagnostics, for example).
8470    !
8480    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
8490    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
8500    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
8510    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
8520    COM /Cnfg_types/ Input$,Source$,Other$
8530    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(1:32),Hp_ib_address
8540    COM /Cnfg_cfg/ Config_str$
8550    INTEGER Row
8560    DIM Cmd$[10],Temp_str$[255]
8570    ! Re-tell the HW file what the HP-IB address is, in case it forgot.
8580    ! (A BASIC RESET makes it forget.)
8590    Hw_set_dev_sel(Hp_ib_address)
8591    Hw_sel_abort
8592    Hw_dev_clear
8600    ! Check configuration against old, restart if they don't match
8610    Temp_str$=FNHw_cmd_rsp$("CFG?",10)
8620    IF Temp_str$<>Config_str$ THEN 
8630      User_error("Hardware changed - starting CNFG from scratch.")
8640      Cnfg_init_boxes
8650      SUBEXIT
8660    END IF
8670    ! REDIM arrays that were un-REDIMed if a STOP and RUN were done
8680    REDIM Box$(1:Max_col,1:Num_mods+1)
8690    REDIM Title$(1:Max_col,0:2)
8700    REDIM Prompt$(1:Max_col)
8710    REDIM Col_width(1:Max_col)
8720    ! setup global classes in case DIAG destroyed them
8730    FOR Row=2 TO Num_mods+1
8740      SELECT Box$(Type_col,Row)
8750      CASE Source$
8760        Cmd$="CLAS 1,3"
8770      CASE Input$
8771        IF Box$(Active_col,Row)="*" THEN 
8780          Cmd$="CLAS 1,2"
8781        ELSE
8782          Cmd$="CLAS"
8783        END IF
8790      CASE ELSE
8800        Cmd$=""
8810      END SELECT
8820      Hw_mod_cmd(VAL(Box$(Address_col,Row)),Cmd$,10)
8830      IF FNHw_io_error THEN 
8840        User_error("Timeout in Cnfg_init - starting CNFG from scratch")
8850        Cnfg_init_boxes
8860        SUBEXIT
8870      END IF
8880    NEXT Row
8890  SUBEND
8900 Cnfg_unchecked:SUB Cnfg_unchecked(INTEGER Unchecked_array(*))
8910    !
8920    ! Used by Cnfg_pick_hp_ib to tell the user what HP-IB locations
8930    ! could not be checked to see if they had HP3565S sytems there.
8940    !
8950    INTEGER I
8960    FOR I=1 TO SIZE(Unchecked_array,1)
8970      IF Unchecked_array(I)<100 THEN 
8980        OUTPUT CRT;"Can't check location "&VAL$(Unchecked_array(I))&"XX";
8990        OUTPUT CRT;" - Host isn't HP-IB controller."
9000      ELSE
9010        OUTPUT CRT;"Can't check location "&VAL$(Unchecked_array(I));
9020        IF (Unchecked_array(I) MOD 100)=1 THEN 
9030          OUTPUT CRT;" - This is a printer address."
9040        ELSE
9050          OUTPUT CRT;" - The host HP-IB address."
9060        END IF
9070      END IF
9080    NEXT I
9090  SUBEND
9100 Cnfg_okay_label:DEF FNCnfg_okay_label(Label$)
9110    !
9120    ! Returns 1 if Label$ is one of the user defined labels for an
9130    ! active or inactive module.  Compare with Cnfg_good_label.
9140    !
9150    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
9160    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
9170    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
9180    DIM Temp$[20]
9190    INTEGER I
9200    Temp$=TRIM$(UPC$(Label$))
9210    FOR I=2 TO Num_mods+1
9220      IF UPC$(Box$(Label_col,I))=Temp$ THEN RETURN 1
9230    NEXT I
9240    RETURN 0
9250  FNEND
9260 Cnfg_type:DEF FNCnfg_type$(Label$)
9270    !
9280    ! Returns what type of module is represented by Label$.  The response
9290    ! will be one of "Source", "Input", or "Other".
9300    !
9310    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
9320    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
9330    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
9340    DIM Temp$[20]
9350    INTEGER I
9360    Temp$=TRIM$(UPC$(Label$))
9370    FOR I=2 TO Num_mods+1
9380      IF UPC$(Box$(Label_col,I))=Temp$ THEN RETURN Box$(Type_col,I)
9390    NEXT I
9400    User_error("Bad label sent to FNCnfg_type$ - "&Label$)
9410    RETURN ""
9420  FNEND
9430 Cnfg_save:SUB Cnfg_save(@File,Ok)
9440    !
9450    ! Attempts to save the current configuration in file @File.
9460    ! Ok is returned 1 if the save is successful, 0 if not.
9470    !
9480    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
9490    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(*),Hp_ib_address
9500    INTEGER File_format_rev
9510    File_format_rev=2621
9520    OUTPUT @File;File_format_rev
9530    OUTPUT @File;Hp_ib_address
9540    File_save_s(@File,Box$(*))
9550    Ok=1
9560  SUBEND
9570 Cnfg_load:SUB Cnfg_load(@File,Ok)
9580    !
9590    ! Attempts to load a configuration from file @File.
9600    ! Ok is returned 1 if successful, 0 otherwise.  Note
9610    ! that a configuration can only be successfully loaded if
9620    ! there is hardware present to match the hardware that was
9630    ! present and active when the save was done, including which kind of
9640    ! modules were present in which slots.  Inactive modules don't
9650    ! matter, but the loader will do its best to assign user labels
9660    ! to inactive modules.
9670    !
9680    COM /Cnfg_str/ Box$(*),Title$(*),Prompt$(*)
9690    COM /Cnfg_hp_ib/ INTEGER Hp_ib_array(*),Hp_ib_address
9700    COM /Cnfg_num/ Col_width(*),Modify_col,INTEGER Num_mods,Max_col
9710    COM /Cnfg_types/ Input$,Source$,Other$
9720    COM /Cnfg_col1/ INTEGER Address_col,Mf_add_col,Id_col,Serial_col
9730    COM /Cnfg_col2/ INTEGER Type_col,Label_col,Active_col
9740    DIM New_box$(1:8,1:64)[20],Label$[20]
9750    INTEGER File_format_rev,New_hp_ib,New_rows,Row,Temp_row,Address
9760    INTEGER Changed(2:64),Last_new_used
9770    ENTER @File;File_format_rev
9780    SELECT File_format_rev
9790    CASE 2620
9800      User_error("You're trying to use an old configuration save file.")
9810      Ok=0
9820    CASE 2621
9830      Ok=1
9840      ENTER @File;New_hp_ib
9850      File_load_s(@File,New_box$(*))
9860      !
9870      ! If only one HP-IB location available, use it.  Otherwise, try
9880      ! to find an HP-IB location at the SAME place as was saved.  If
9890      ! that's not found, die.
9900      !
9910      Max_hp_ib=SIZE(Hp_ib_array,1)
9920      IF Max_hp_ib>1 THEN 
9930        I=1
9940        WHILE Hp_ib_array(I)<>New_hp_ib AND I<Max_hp_ib
9950          I=I+1
9960        END WHILE
9970        IF Hp_ib_array(I)=New_hp_ib THEN 
9980          IF New_hp_ib<>Hp_ib_address THEN 
9990            Hw_set_dev_sel(New_hp_ib)
10000           Hp_ib_address=New_hp_ib
10010           Cnfg_init_boxes
10020         END IF
10030       ELSE
10040         User_error("ERROR in Cnfg_load - HP-IB module not found at address "&VAL$(New_hp_ib))
10050         Ok=0
10060       END IF
10070     END IF
10080     !
10090     ! HP-IB has been handled.  Now figure out Box$.
10100     ! For a loaded configuration to be valid, the number of sources
10110     ! and inputs must be at least as large as the number of active
10120     ! sources and inputs saved.  There must be modules of the same
10130     ! type as was saved at the location of each active module saved.
10140     ! Inactive modules don't matter, but we'll try to assign the correct
10150     ! labels to them if we can.
10160     !
10170     ! First pass - just see if there's an error
10180     !
10190     IF Ok THEN 
10200       New_rows=SIZE(New_box$,2)
10210       FOR Row=2 TO New_rows                   ! row is in New_box$
10220         IF New_box$(Active_col,Row)<>"" THEN  ! active
10230           Address=VAL(New_box$(Address_col,Row))
10240           Temp_row=2                          ! temp_row is in box$
10250           WHILE Address>VAL(Box$(Address_col,Temp_row)) AND Temp_row<=Num_mods
10260             Temp_row=Temp_row+1
10270           END WHILE
10280           IF Address=VAL(Box$(Address_col,Temp_row)) THEN 
10290             IF Box$(Id_col,Temp_row)<>New_box$(Id_col,Row) THEN 
10300               User_error("ERROR in Cnfg_load - Module ID isn't "&New_box$(Id_col,Row)&" at address "&VAL$(Address))
10310               Ok=0
10320             END IF
10330           ELSE
10340             User_error("ERROR in Cnfg_load - No module with ID "&New_box$(Id_col,Row)&" at location "&VAL$(Address))
10350             Ok=0
10360           END IF
10370         END IF
10380       NEXT Row
10390     END IF
10400     !
10410     ! Second pass - do it if no errors yet
10420     !
10430     IF Ok THEN 
10440       ! Take care of active modules
10450       FOR Row=2 TO Num_mods+1     ! row is in box$
10460         Address=VAL(Box$(Address_col,Row))
10470         Temp_row=2                ! temp_row is in new_box$
10480         WHILE Address>VAL(New_box$(Address_col,Temp_row)) AND Temp_row<New_rows
10490           Temp_row=Temp_row+1
10500         END WHILE
10510         IF Address=VAL(New_box$(Address_col,Temp_row)) THEN 
10520           IF New_box$(Active_col,Temp_row)<>"" THEN 
10530             Box$(Label_col,Row)=New_box$(Label_col,Temp_row)
10540             Box$(Active_col,Row)="*"
10550             Changed(Row)=1
10560             IF Box$(Type_col,Row)=Source$ THEN 
10570               Hw_mod_cmd((Address),"CLAS 1,3")
10580             ELSE
10590               IF Box$(Type_col,Row)=Input$ THEN 
10600                 Hw_mod_cmd((Address),"CLAS 1,2")
10610               END IF
10620             END IF
10630           END IF
10640         END IF
10650       NEXT Row
10660       ! Take care of inactive sources that are in New_box$
10670       Last_new_used=1
10680       FOR Row=2 TO Num_mods+1
10690         IF NOT Changed(Row) AND Last_new_used<New_rows THEN 
10700           IF Box$(Type_col,Row)=Source$ THEN 
10710             ! Look for another inactive row in New_box$
10720             REPEAT
10730               Last_new_used=Last_new_used+1
10740             UNTIL Last_new_used>=New_rows OR (New_box$(Active_col,Last_new_used)="" AND New_box$(Type_col,Last_new_used)=Source$)
10750             IF New_box$(Active_col,Last_new_used)="" AND New_box$(Type_col,Last_new_used)=Source$ THEN 
10760               Box$(Label_col,Row)=New_box$(Label_col,Last_new_used)
10770               Box$(Active_col,Row)=""
10780               Changed(Row)=1
10790             END IF
10800           END IF
10810         END IF
10820       NEXT Row
10830       ! Take care of inactive inputs that are in New_box$
10840       Last_new_used=1
10850       FOR Row=2 TO Num_mods+1
10860         IF NOT Changed(Row) AND Last_new_used<New_rows THEN 
10870           IF Box$(Type_col,Row)=Input$ THEN 
10880             ! Look for another inactive row in New_box$
10890             REPEAT
10900               Last_new_used=Last_new_used+1
10910             UNTIL Last_new_used>=New_rows OR (New_box$(Active_col,Last_new_used)="" AND New_box$(Type_col,Last_new_used)=Input$)
10920             IF New_box$(Active_col,Last_new_used)="" AND New_box$(Type_col,Last_new_used)=Input$ THEN 
10930               Box$(Label_col,Row)=New_box$(Label_col,Last_new_used)
10940               Box$(Active_col,Row)=""
10950               Changed(Row)=1
10960             END IF
10970           END IF
10980         END IF
10990       NEXT Row
11000       ! Clear the rest
11010       Counter=1
11020       FOR Row=2 TO Num_mods+1
11030         IF NOT Changed(Row) THEN 
11040           Box$(Label_col,Row)=""
11050           Box$(Active_col,Row)=""
11060         END IF
11070       NEXT Row
11080       ! Assign the rest
11090       FOR Row=2 TO Num_mods+1
11100         IF NOT Changed(Row) THEN 
11110           REPEAT
11120             Label$="Unused "&VAL$(Counter)
11130             Counter=Counter+1
11140           UNTIL NOT FNCnfg_okay_label(Label$)
11150           Box$(Label_col,Row)=Label$
11160         END IF
11170       NEXT Row
11180     END IF
11190   CASE ELSE
11200     User_error("ERROR Incompatible display file format in Cnfg_load.")
11210     Ok=0
11220   END SELECT
11230 SUBEND