Manuals >Reference >Drivers Print version of this Book (PDF file) |
![]() ![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Adding Instrument Drivers to IC-CAPMany instruments can measure a device or a circuit. While IC-CAP supports major HP/Agilent instruments, other instruments manufactured by HP/Agilent or other vendors could be used for characterization work within IC-CAP. The Open Measurement Interface (OMI) is part of IC-CAP's open system philosophy that allows the addition of new instrument drivers.
This section provides information about OMI and the basic form of an OMI driver. Alternatives to creating a new driver are also addressed. Using the Open Measurement InterfaceThe Open Measurement Interface enables you to add drivers for other instruments. User-added drivers can be full-featured, fully integrated, and indistinguishable from the Agilent-provided drivers. Like the Agilent-provided drivers, they are written using C++. OMI was designed to ensure that C Language programmers do not experience language barriers when creating new drivers. Much of the work necessary to lay out the required code is performed by a tool kit comprised of Driver Generation Scripts described in Adding a Driver. These scripts also write all necessary code for the Instrument Options editors for a new driver, and all necessary code for the driver to be included in the Instruments Library shown in the Hardware Setup window. The user is responsible for filling in the bodies of a set of functions that IC-CAP calls during measurements. A set of reusable software constructs is provided for accomplishing common programming tasks; refer to Programming with C++. With the first version of the Open Measurement Interface (IC-CAP version 4.00), only GPIB based instrument I/O is formally supported. OMI GuidelinesTo use the Open Measurement Interface, the following qualifications are recommended.
Driver Development ConceptsThe basic form of user-added drivers involves 1 file with declarations of data types and functions, and 1 file with implementations of functions. Because Driver Generation Scripts are provided, very few modifications to the declarations file are necessary; work is largely confined to the function implementations file. The separation of declarations and implementations is common practice, and has been used with User C Functions. The source directory $ICCAP_ROOT/src is used for OMI compilation, just as it is for User C Functions. The default source files for new drivers already contain example drivers:
Unless you choose to add files to optimize your compilation process, the $ICCAP_ROOT/src/Makefile permits the make(1) command to create an up-to-date IC-CAP executable file with your latest modifications. This Makefile accounts for the distinct compilation needs of the C++ and C source files by invoking the appropriate compiler. By default, make(1) understands a .cxx suffix to mean C++ compilation, and .c to mean C compilation; the Open Measurement Interface follows this convention. The process for building the shared libraries libicuserc.<ext> and libicusercxx.<ext> is demonstrated in the following figure. It is not necessary to know the details; the make(1) command can perform the entire process (provided the $ICCAP_ROOT/src/Makefile is correct). The user driver files, user_meas.hxx and user_meas.cxx, to which your driver is added by default, already contain an example driver. This keeps the facility simple but could slow your compilation. If you choose to add your code to other files, adjust the Makefile. Otherwise, do not modify the Makefile.
The pbench.o file is supplied since it is required to build the shared library. However, the source is not provided, so you cannot modify it. Example Drivers Three example drivers HP 4194, HP 4140, and HP 54510 can be seen in the Instrument Library in the Hardware Setup window.
The information provided by these example drivers should serve as valuable reference material for adding a new driver. Header Files Files that are normally modified and re-compiled, user_meas.hxx and user_meas.cxx, use include (or header) files. The most important header files are unit.hxx, user_unit.hxx, instr.hxx, and user_instr.hxx. These files declare all of the virtual functions for each driver, and provide information to write (or avoid writing) each function. Generated Code and Comments The driver generation scripts generate both code and comments. Generally, the comments state what each required function must return, when it is invoked, and its purpose. Code examples are often provided that you can use as the basis for the code you must provide. To access this information, run the scripts. For information, refer to Driver Generation Scripts. Binary Byte OrderFor information on transferring binary data between an instrument and IC-CAP, see the README.byteorder file in the source directory $ICCAP_ROOT/src. It contains important information with respect to the order of bytes in a multi-byte number. Adding a DriverThe basic steps (details are provided in the paragraphs that follow) for adding a driver are:
Driver Generation ScriptsThe driver generation scripts provide a framework of functions into which a user's driver code is placed. mk_unit This script generates code for units in an instrument. In the case of an HP 4141, for example, there are 8 units, including 4 DC SMUs, 2 VS and 2 VM units. The HP 4194 example has just 1 unit, which is typical for a CV driver. A transcript of the mk_unit session used for the HP 4194 driver is as follows: $ mk_unit Enter a name for the unit class for which you want code: cvu_4194 Enter a name for the instrument class that will use this unit class: hp4194 Enter the full name of the .hxx file that will declare hp4194 default: user_meas.hxx]: Enter a name of twelve characters or less; the emitted code will be appended to .cxx and .hxx files with this basename [default: user_meas]: Done. C++ code was added to user_meas.hxx and user_meas.cxx. You should re-run mk_unit if more unit types are needed. Otherwise, you probably need to run mk_instr now. You must supply the name of 2 C++ classes. A class is a name for a user-defined C++ type and is like a struct in C. The mk_unit script uses your chosen class names throughout the generated code. In this example a unit class name (cvu_4194) was chosen to denote CV Unit in a 4194, and an instrument class name (hp4194) was chosen to reflect the name of the instrument. Try to select class names in the same style. Class names should be meaningful and specific, since this helps to avoid name collisions during compilation. Use, for example, a suffix relating to the instrument or company. Do not hesitate to take advantage of the fact that the C and C++ compilers generally accept very long names. The use of long descriptive names helps prevent compilation or linking problems due to name collisions. If the instrument has more than 1 kind of unit to drive, like the HP 4141, run mk_unit repeatedly. If it has several identical units, do not re-run mk_unit. Identical units can be taken into account after running mk_instr. mk_instr This script generates code for instrument-wide functionality in a driver, such as calibration, self-test, and getting the instrument recognized during Rebuild (instrument list). A transcript of the mk_instr session used for the HP 4194 driver is: $ mk_instr Enter the name of the instrument class for which you want code: hp4194 Enter a name of twelve characters or less; the emitted code will be appended to .cxx and .hxx files with this basename [default: user_meas]: Done. C++ code was added to user_meas.hxx and user_meas.cxx. Now you can go take a look at user_meas.cxx, and start doing the real work. NOTE: in user_meas.cxx you may eventually need to add #include statements to ensure that user_meas.cxx sees the class declarations of any unit classes used by hp4194. Disregard this if the necessary unit declarations appear at the beginning of user_meas.hxx.(The mk_unit script should generally have put them there.) You WILL need to declare some units in the class declaration of hp4194 in user_meas.hxx (see comments therein). After running this script, you generally need to run mk_instr_ui next. This script requires the class name hp4194 to be repeated again, exactly as it was entered in mk_unit. (In your own driver, use another class name besides hp4194, but repeat the same instrument class name when each script asks for it.) The script mentions the need to declare some units, which is accomplished by manual edits to the user_meas.hxx file; for example cvu_4194* cv_unit ; accomplishes that for the HP 4194 driver in the file user_meas.hxx file. If the HP 4194 had 2 identical CV units available, this declaration might have been cvu_4194* cv_unit_1 ; cvu_4194* cv_unit_2 ; mk_instr_ui This script generates code that fully implements the Instrument Options tables appearing in Setups that use the instrument driver. Within these tables, an IC-CAP operator can specify such things as Delay Time, Integration Time, and other instrument-specific options. Because this script completely writes out the necessary C++ code for this user interface functionality, it asks more questions than the previous scripts. A transcript of the mk_instr_ui session used for the HP 4194 driver is: $ mk_instr_ui NOTE: valid types for editor fields are these: { real | int | char | boolean | string } Enter the name of the instrument class for which you want UI code: hp4194 Enter a name of twelve characters or less; the emitted code will be appended to .cxx and .hxx files with this basename [default: user_meas]: Enter the label for an editor field (or enter a null string if no more fields are desired): Use User Sweep Enter a type for editor field 'Use User Sweep' [h for help] : boolean Enter an initial value for this field [ 0 or 1 ] : 0 Enter the label for an editor field (or enter a null string if no more fields are desired): Hold Time Enter a type for editor field "Hold Time" [h for help] : real Enter the minimum legal value for this field: 0 Enter the maximum legal value for this field: HUGE Enter a granularity value (for rounding this field; 0 for no rounding): 0 Enter an initial value for this field: 0 Enter the label for an editor field (or enter a null string if no more fields are desired): Delay Time Enter a type for editor field "Delay Time" [h for help] : real Enter the minimum legal value for this field: 0 Enter the maximum legal value for this field: 3600 Enter a granularity value (for rounding this field; 0 for no rounding): 0 Enter an initial value for this field: 0 Enter the label for an editor field (or enter a null string if no more fields are desired): Meas Freq Enter a type for editor field "Meas Freq" [h for help] : Sorry, "" is not a valid type. The valid types are: { real | int | char | boolean | string } Enter a type for editor field "Meas Freq" [h for help] : real Enter the minimum legal value for this field: 100 Enter the maximum legal value for this field: 100e6 Enter a granularity value (for rounding this field; 0 for no rounding): 1 Enter an initial value for this field: 1e6 Enter the label for an editor field (or enter a null string if no more fields are desired): Integ Time Enter a type for editor field "Integ Time" [h for help] : char This field will force the user to enter one character, from within a set of valid characters you will specify now. Example set of valid characters: TFYN Enter the set of character values that this field can take on: SML Enter whether this field should force user input to uppercase [y/n]: y Enter an initial value for this field: S Enter the label for an editor field (or enter a null string if no more fields are desired): Osc Level [.01-1Vrms] Enter a type for editor field "Osc Level [.01-1Vrms]" [h for help] : real Enter the minimum legal value for this field: .01 Enter the maximum legal value for this field: 1 Enter a granularity value (for rounding this field; 0 for no rounding): 0 Enter an initial value for this field: .01 Enter the label for an editor field (or enter a null string if no more fields are desired): Averages [1-256] Enter a type for editor field "Averages [1-256]" [h for help] : int Enter the minimum legal value for this field: 1 Enter the maximum legal value for this field: 256 Enter an initial value for this field: 1 Enter the label for an editor field (or enter a null string if no more fields are desired): Delay for Timeouts Enter a type for editor field "Delay for Timeouts" [h for help] : real Enter the minimum legal value for this field: 0 Enter the maximum legal value for this field: HUGE Enter a granularity value (for rounding this field; 0 for no rounding): 0 Enter an initial value for this field: 0 Enter the label for an editor field (or enter a null string if no more fields are desired): Done. All necessary C++ UI code was added to user_meas.hxx and user_meas.cxx. From the nature of the questions in this script, this process defines an editor table for the instrument. The table offers some advanced features, such as constraining the type and the range of values that an operator can enter in each field. Running the Scripts on WindowsTo run the mk_instr, mk_unit, and mk_instr_ui scripts on Windows, first edit the file $ICCAP_ROOT/bin/icrun.bat. You must set ICCAP_ROOT accordingly by modifying the line: for example if you installed IC-CAP at C:\Agilent\ICCAP_2006B, edit the file to read Once this is set, simply change <name> below to mk_instr, mk_unit, or mk_instr_ui to run those scripts. Running the Scripts on UNIXThis section contains information about running the scripts, questions asked by the script, and the form of user responses.
The scripts require you to fill in functions in user_meas.cxx. They also require a few minor adjustments in user_meas.hxx. These adjustments are:
Filling in Necessary FunctionsAfter running the scripts, you must write the body portions of the functions added to user_meas.cxx. This section provides hints to help you accomplish this. For help filling in a function body, look at the declarations and functions generated by the scripts. These provide comments explaining the purpose, return value, and invocation time of each function. Next look at the declarations and functions of the HP 4194 example driver. This section contains examples of code accomplishing required tasks. The following manual sections may also be helpful.
You may want to proceed in stages. For example, start with Hardware Setup Operations to demonstrate that Rebuild (instrument list) can find the instrument and display the driver and instrument in the Hardware window. Then implement the functions that support Measure. Address those functions that support Calibrate, if desired. During the time your driver is partially implemented, compiler warnings serve as a rough indication of functions not yet implemented. The GPIB analyzer (Tools menu), and especially its macro features (described elsewhere in this chapter), are helpful when developing the appropriate sequence of commands to use with the instrument. Making a New Instrument Type Known to IC-CAPRunning the mk_instr script makes a new instrument type known to IC-CAP. The code involves an add_user_driver() function call, placed in user_meas.cxx by the mk_instr script. Creating a New Shared LibraryAfter any series of edits to the source files, you must generate 1 or 2 new shared libraries to pick up the modified files. The shared library names are libicuserc.<ext> and libicusercxx.<ext> where ext is a platform-specific extension. Use the extension .so for Solaris. The library libicuserc.<ext> holds C code and is used to add user C functions. The library libicusercxx.<ext> holds C++ code and is used to add instruments. The default location of these files on SUN Solaris 2.X is $ICCAP_ROOT/lib/sun2x. When you issue the make command, you will create a local version of the same file that includes your modifications. By setting an environment variable, you can direct IC-CAP to use your new shared library instead of the default library. To generate the new shared library:
If the drive you're copying to is NFS mounted, clock skews can result if the NFS drive's system has a slightly different system time than the local system. If you think this might apply to you, first, execute touch * then execute touch *.o. The first touch synchronizes all files to your local system's time; the following touch causes the make system to believe that all of the .o files were generated later than the source files, so it will not attempt to rebuild any unnecessary files.
Troubleshooting Compiler ErrorsThe definitive authority on compiler errors is your compiler documentation. This section offers assistance with some of the common messages you may encounter when compiling OMI drivers. CC: "user_meas.cxx", line 899: warning: outptr not used (117) usually indicates that you have not yet filled in a function, with the result that the function is not using all of its arguments. In some cases the function may not use all of its arguments, so the message may not be important. error 1299: some_unit_func cannot access some_instr_class_name::some_member: private member is discussed in Running the Scripts on Windows. CC: "user_meas.hxx", line 9: error: class x defined twice (1113) indicates that the Driver Generation Scripts were probably run twice. For help, refer to Running the Scripts on Windows. DebuggingThis section provides information about debugging driver code, after iccap.new has been compiled, including the xdb debugger and GPIB analyzer (Tools menu). Using the xdb DebuggerThe default Makefile arranges for debug information to be available after linking the executable file. This is done with the -g flag among the CFLAGS in the Makefile. The debugger commands described in the following table should be tried in the order presented.
GPIB Analyzer (Tools menu) and IC-CAP DiagnosticsIn addition to xdb, debugging capabilities are built into IC-CAP. The GPIB analyzer (Tools menu) in the Hardware Setup window includes the following features.
The generation of IC-CAP diagnostic messages can be activated by menu functions under Tools in the IC-CAP Main window. Alternatives to Creating New DriversIf you don't need an instrument driver to be as fully integrated as HP/Agilent-provided drivers, it may be worthwhile to consider controlling the instrument by means less formal than creating a driver using the Open Measurement Interface.
There is an important shortcoming with these suggestions. An IC-CAP measurement currently provides no mechanism for Program Transforms or Macros to be invoked at critical times in the interior of the measurement (for example, at the instant when DC bias levels have just been established by SMUs, and it is time for a main sweep instrument to stimulate the DUT and collect data). Use of the Open Measurement Interface overcomes such limitations.
! Steps 1, 2, and 3 are assumed to be implemented by PRINT. ! 1) Force next desired set point on temperature chamber. ! 2) Enable waveform generator. iccap_func("/opamp/time_domain/positive_slew","Measure") ! 3) Disable waveform generator. ! One way to control the values desired for temperature and ! frequency is to access IC-CAP system variables. What Makes up an IC-CAP DriverIn addition to measurement capabilities, each IC-CAP driver possesses other capabilities, such as the user interface functionality provided in Instrument Options folder and the ability to participate in Input, Output and Setup Checking prior to measuring. Each of these essential areas is discussed in this section. In each area, information is provided about the specific functions necessary to complete that part of a driver. In the tables throughout this section, the prefix unit:: means the class name(s) you provided for units when you ran the mk_unit script. The prefix instr:: should be considered to mean the class name you provided for the instrument when you ran the mk_instr script. The column Importance indicates whether you typically need to write any code for the function. Because of the inheritance features of C++, you must often rely on inherited default functions. Functions important to write, typical return values, and other information can be determined from the comments for the function in $ICCAP_ROOT/src/user_meas.cxx. Instrument OptionsThe Instrument Options folder provides a method for selecting certain instrument conditions for a measurement. Certain instrument conditions are separated into different groups of instrument options (rather than appearing in Input sweep editors) because they are highly instrument specific, and play no role in simulation. The options displayed in the Instrument Options folder typically vary with each setup that participates in the measurement involving a particular instrument. The Driver Generation Scripts, described in Procedure for Adding a Driver, can write all the C++ code that is necessary to establish appropriate instrument options tables for a new driver. The driver generation script named mk_instr_ui prompts for the desired contents of the instrument options tables, after which it proceeds to generate the necessary declarations and implementations in C++. The generated code will contain data structures in which options are stored, as well as the user interface linkages that display the options for editing. Input, Output and Setup CheckingWhen you initiate Measure or Calibrate for a Setup, IC-CAP first verifies the validity of the measurement Setup. This permits many operator errors to be detected and reported before IC-CAP undertakes instrument I/O. IC-CAP performs the following 3 kinds of checks:
The following table describes the functions related to input (sweep) checking. Table 52 shows a summary of the supported Input (Sweep) modes in IC-CAP. The column Character Used in Driver Functions shows the character passed when an Input Mode is passed to a function, such as unit::can_source. Table 53 describes the functions related to output checking. Table 54 shows a summary of the supported Output modes in IC-CAP. The column Character Used in Driver Functions shows the character passed when an Output Mode is passed to a function, such as unit::can_measure.
Setup checking is performed primarily by logic embedded in IC-CAP. A limited amount of the checking is accomplished with user-supplied functions. The following table describes the user functions related to overall Setup checking.
User-Defined Input and Output ModesMode U is a reserved user-defined mode that allows some flexibility for safely checking any new signal modes to be sourced or measured. This feature is for situations where it is not practical or safe to use existing Input or Output modes (such as voltage or capacitance). The following considerations apply:
CalibrationCalibration functions are associated with the instrument, not its units. To perform calibration procedures initiated from the IC-CAP program, implement the functions shown in the following table.
Several of the functions required for Measure are also used during Calibrate. Refer to Order in Which User-Supplied Functions are Called in this chapter for a list of functions called during Calibrate. Storage is provided in the instr_options class for limited calibration data for a particular instrument in a particular Setup. The instr_options class is declared in instr.hxx. The data members in instr_options for holding calibration results are:
Set calib_status during do_cal() and test it during recall_n_chk_calib(). Recall that cal_possible() and do_cal() are invoked (in that order) during Calibrate, while recall_n_chk_calib() is later called during Measure, with the purpose of enabling the desired calibration set. Derived from the class instr_options (declared in instr.hxx) is user_instr_options, declared in user_instr.hxx. For the new driver, a further derived class will have been declared in user_meas.hxx by the mk_instr_ui script. The section Class Hierarchy for User-Contributed Drivers clarifies the relationships of these classes. The class in user_meas.hxx that is derived from user_instr_options is an appropriate place to declare additional calibration data the workstation should retain, because a distinct object (or data structure) of this type exists in every situation where distinct instrument calibration data might be needed. In other words, an instrument has a distinct user_instr_options object in every Setup where the instrument is used. For the example of the HP 4194 driver, such data (if any) would be declared in the class named hp4194_table in user_meas.hxx. You might declare several double numbers, to keep a record of sweep limits that were in effect at the time of Calibrate, so that they can be verified during Measurement. (With many instruments, calibration is not valid unless measurements employ the same sweep limits that were in effect during calibration.)
To simplify an initial pass at implementing calibration, do not declare additional data structures for remembering sweep parameters, and do not perform much verification during recall_n_chk_calib().
If you choose to declare additional calibration-related data in the class derived from user_instr_options, it is possible for this data to be archived and re-loaded with IC-CAP Model(.mdl), DUT(.dut), and Setup(.set) files. Note that the archiving of user-defined calibration data is an advanced feature that most implementations can probably avoid considering. To archive user-defined calibration data, your class derived from user_instr_options must redeclare and implement 2 virtual functions. These functions are read_from_file and write_from_file, declared for the class instr_options, in the file instr.hxx. When called, these functions receive an open stdio FILE*, which provides read or write access to the IC-CAP archive file at the appropriate time during a Read From File or Write to File menu function. Measurement: Initialization, Control and Data AcquisitionThe functions in this area perform the real work of the instrument driver; this area accounts for the largest number of functions present in each driver. Initialization functions are listed in the following table.
Control and data acquisition functions are shown in the following table. Because many of the functions in this category must perform non-trivial work, such as instrument communication and error reporting, refer to Programming with C++, where such operations are explained. The examples for the cvu_4194 member functions and the hp4194 member functions in user_meas.cxx are also helpful. A few of the functions in this area are provided for the support of a particular instrument, for example, the HP 4145. The intermediate classes user_unit and user_instr do not redeclare some of these low-usage functions, though their declarations are inherited from the unit and instr classes, so they could be used in a new driver if needed. For example, instr::use_second_sweep() is re-declared and used only by the HP 4145 driver.
Hardware Setup OperationsThe Hardware Setup functions, listed in the following table, are used in the following operations:
* denotes a constructor or destructor function for which the actual name is the unit or instr class name chosen when the mk_unit and mk_instr scripts were run. For example, hp4194::hp4194, in user_meas.cxx. Programming with C++This section provides examples of code for common Open Measurement Interface programming tasks.
Access to Inputs (Sweeps) and OutputsIn user_meas.cxx the function cvu_4194::check_sweep demonstrates how to determine sweep properties like Mode (V, for example), Type (LOG, for example), compliance, and start and stop values. IC-CAP computes all necessary step values. Do not attempt to compute them from start, stop, and so on, because simulations will use the values IC-CAP computes. Instead, access individual sweep steps with the get_point function. Following are statements from cvu_4194::check_sweep that determine sweep properties and get sweep values. These statements are isolated examples and are not necessarily to be used in the order shown. int cvu_4194::check_sweep(sweep* swp) // header of the function used here sweep_def *swpdef = swp->get_sweep_def(); // a sweep uses sweep_def for values switch(swpdef->get_esweep_type()) // to see if it's CON, LOG, LIN, ... compval = swp->get_compliance(); // compliance case CON: val1 = ((con_sweep *)swpdef)->get_value(); // value of CON sweep case LIN: val1 = ((lin_sweep *)swpdef)->get_start(); // start value of LIN sweep val2 = ((lin_sweep *)swpdef)->get_stop(); // stop value ((lin_sweep *)swpdef)->get_stepsize() // step size // next 2 are taken from cvu_4194::set_internal_sweep: linswp = (lin_sweep*)swpdef ; // to enable lin_sweep functions numpoints = linswp -> get_num_points(); // number of points if (swp->get_sweep_order() == 1) // sweep order; 1 => main sweep switch (swp->get_mode()) // Mode: 'V', 'I', 'F', ... swp->get_size() // Number of points swp->get_point(step_num) // get one point (indexed from 0) The class named sweep is declared in sweep.hxx. Using a sweep often involves using functions it inherits from the class ds (data set), declared in ds.hxx. The function get_point is an example of a function inherited from ds. The sweep_type class is in sweep_type.hxx. To save measured data to an IC-CAP Output data set, employ the style in cvu_4194::get_data: dsptr -> keep_point (index++, datapoint, DATA_MEAS); // datapoint is a double In the example, dsptr points to a ds object. The class ds declares other forms of the keep_point function in ds.hxx. These can store complex or 2-port matrix data into the Output data set. Error and Warning MessagesThe IC-CAP error box appears after a measurement, displays one or more messages, and must be dismissed by clicking OK if you make one or more statements such as errbox << "ERROR: HP4194 unsupported internal sweep type." << EOL; errbox << "ERROR: HP4194 sweep produced " << num_points_kept << "when" << swp_num_points << " were requested" << EOL ; Warnings are displayed in the Status window: cerr << "WARNING: HP4194 frequency rounded up to 100Hz" << EOL ; The objects errbox and cerr accept any number of arguments, of various types, including double, String, char*, int, and char. Separate them with << . Reading from an InstrumentThe user_meas.cxx file demonstrates 2 styles. Writing and reading are done with separate calls. In hp4194::get_id a readstring function is used as follows: stat=ioport->readstring(ad,id_buf,255); // below is the code needed to call readstring from // a unit class function stat=get_io_port()->readstring(ad,id_buf,255); // because the instrument owns and maintains the ioport // object, the unit gets it this way before using it The first argument above is the GPIB address. The id_buf argument is a buffer guaranteed to be adjusted by readstring to hold 255 bytes, if the read produces that many. A function is also provided to write a query and then read an answer: if ( ioport->write_n_read(addr,"MKRB?", urbuf, 80) == -1 ) The first argument above is the GPIB address. The second argument is a char* to be written. The third argument is a buffer guaranteed to be adjusted by readstring to hold 80 bytes, if the read produces that many. The above functions are 2 of many available for an hpib_io_port. Complete declarations of its functions are in io_port.hxx. Serial Poll of an InstrumentThe following functions are 2 of many available for an hpib_io_port. Complete declarations of its functions are in io_port.hxx. Serial polling is done as follows: int status_byte = ioport->spoll(addr); // this example not from user_meas.cxx int status_byte = get_io_port()->spoll(addr); // call from a unit function To wait for a particular serial poll bit: // from cvu_4194::zero_supply: hpib_io_port *ioport = get_ioport(); // bit-weight 1 below is to await 'measurement complete bit' if ( ioport -> poll_wait(addr, 1, 0, 10.0) == -1 ) The arguments are: GPIB address, bit-weight to wait for, a flag reserved for future use, and maximum time that poll_wait should try (10 seconds). String HandlingC++ offers a substantial improvement over C for handling String type data. In the file String.h a number of String functions are declared. The following code demonstrates several.
In the final example, a char* is expected by writestring, and C++ automatically extracts it from the String. Do not pass a String to printf or scanf. The declarations of these functions in /usr/include/stdio.h use the ellipsis notation (...), so C++ does not know that a char* should be passed to them. Time DelayAn example of a time delay is: delay ( 10E-3 ) ; // 10 millisecond delay User Input with a Dialog BoxA number of functions for this purpose are declared in dialog.hxx. Examples to get data from dialog boxes are:
Writing to an InstrumentAn example of writing to an instrument is: if ( ioport->writestring(addr,"TRIG") == -1 ) // cvu_4194::zero_supply The arguments are the GPIB address and a char* string to send. You can also write a query and read a response with 1 call, write_n_read, discussed in Reading from an Instrument. Writestring and write_n_read are 2 of many functions available for an hpib_io_port. Complete declarations of its functions are in io_port.hxx. SyntaxThis section provides help with reading the IC-CAP source code in user_meas.hxx, user_meas.cxx, and the various include files. Follow the example code in user_meas.hxx and user_meas.cxx when implementing a new driver.
For best results when using the vi editor to browse the source files, execute the command :set tabstop=3
The C++ language introduces several keywords to help understand OMI programming, for example, class, new, delete, and virtual. Terms that are peculiar to OMI programming, for example, Measurer, sweep type, sweep order, main sweep, internal sweep, user sweep, unit function, and instrument data, are used in this chapter and in the source files. Function declarations in C++ use the improved function prototypes of ANSI/C. For example, int mult_by_2(int input); // style for forward declaration int y=2 ; int y = 2 ; int x = mult_by_2(y) ; // example of invocation int mult_by_2(int input) // style for implementation (SAME AS DECLARATION) { return 2*input ; } This is an area of incompatibility with original (Kernighan and Ritchie) C. However, it is easier to read, and write, and is the emerging new standard. It also gives the compiler information with which function call argument lists can be checked, saving run-time aggravation. Sometimes in class declarations you will see the function body present: const char *class_name() // this code from user_meas.hxx { return "cvu_4194" ; } These cases are called inline functions. They behave like normal functions, but the C++ compiler emits code inline, without normal function call overhead. For short functions this reduces both execution time and code size. New Symbols and OperatorsThis section defines new symbols and operators in C++. // A pair of slashes introduces an end-of-line comment. ( /* and */ can still be used for C-style comments.) & Appearing after a type name or class name, & usually indicates that an argument to a function is passed by reference. Although C can pass arguments by address, the C++ notion of reference arguments eliminates many error-prone uses of * (pointer de-reference) and & (address) operators used with pointer handling in C. In the following example, the called function increments the callers variable: // 'input' passed by reference: void increment(int& input) { input++ ; // need not use *input } int x=3; increment(x); // Need not pass &x // Now x is equal to 4 object. member_function( ) In C, the . operator is used to access data members in a struct object. In C++, . is also used to access (execute) function members. ptr_to_object->member_function() In C, the -> operator is used to access data members in a struct object to which one holds a pointer. In C++, -> is also used to access (execute) function members of a class type object to which you hold a pointer. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() ![]() |