![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
14.5 Writing modules for pulsers
Modules for pulsers are a bit more difficult to write than drivers for
other devices. The reason is that pulsers play a rather important role
in modern spectrometers and thus setting the pulses should be made as
easy as possible for the user. Of course, it would be possible to deal
with pulsers in exactly the same way as normal devices, i.e. to define
just a set of functions for setting different pulse properties etc.
but this would make the programs much harder to write and understand.
Instead many aspects of dealing with pulses and pulsers are integrated
directly into the EDL language. While this makes it easier for
the user writing EDL scripts it requires more work by the
writer of the module for a pulsers.
If, for example, the user defines a new pulse in the PREPARATIONS
section the relevant part of the EDL file will similar look to
this:
P3: FUNCTION = MW,
START = P1.START + 200 ns,
LENGTH = 140 ns;
|
When fsc2 finds these lines it will have to call several
functions that must be defined within the module. First it needs to call
a function that allows it to inform the module that there is a new pulse
numbered 3. Next it will inform the module that the pulse function the
new pulse 3 is associated with is the function for microwave pulses.
Next it detects that the start position of the new pulse is defined in
terms of the values that (hopefully) have been already set for the pulse
1 and must ask the module for the start position of pulse 1. Using the
returned value fsc2 now can calculate the start position of
the new pulse 3 and must then call another function in the module to
tell the module about this position. Finally, another function in the
module must exist so that fsc2 can inform it about the length
of the new pulse. Using these (and a lot more) functions the module will
be able to set up an internal representation of the pulser state and to
bring the pulser into this state at the start of the experiment.
To make it possible to integrate handling of pulsers in this way
directly into EDL the module for a pulser must obviously
define quite a lot of non-EDL functions and some additional
variables. Pointers to all of these needed functions are collected in one
structure, Pulser_Struct:
struct {
const char * name;
bool needs_phase_pulses;
bool has_pods;
bool ( * assign_channel_to_function )( int function, long channel );
bool ( * assign_function )( int function, long connector );
bool ( * set_function_high_level )( int function, double high_voltage );
bool ( * set_function_low_level )( int function, double low_voltage );
bool ( * invert_function )( int function );
bool ( * set_function_delay )( int function, double delay );
bool ( * set_timebase )( double timebase );
bool ( * set_timebase_level )( int level );
bool ( * set_trigger_mode )( int mode );
bool ( * set_repeat_time )( double rep_time );
bool ( * set_trig_in_level )( double voltage );
bool ( * set_trig_in_slope )( int slope );
bool ( * set_trig_in_impedance )( int state );
bool ( * set_phase_reference )( int phase, int function );
bool ( * phase_setup_prep )( int func, int type, int pod, long val );
bool ( * phase_setup )( int func );
bool ( * new_pulse )( long pulse_number );
bool ( * set_pulse_function )( long pulse_number, int function );
bool ( * set_pulse_position )( long pulse_number, double ptime );
bool ( * set_pulse_length )( long pulse_number, double ptime );
bool ( * set_pulse_position_change )( long pulse_number, double ptime );
bool ( * set_pulse_length_change )( long pulse_number, double ptime );
bool ( * set_pulse_phase_cycle )( long pulse_number, long cycle );
bool ( * get_pulse_function )( long pulse_number, int * function );
bool ( * get_pulse_position )( long pulse_number, double * ptime );
bool ( * get_pulse_length )( long pulse_number, double * ptime );
bool ( * get_pulse_position_change )( long pulse_number, double * ptime );
bool ( * get_pulse_length_change )( long pulse_number, double * ptime );
bool ( * get_pulse_phase_cycle )( long pulse_number, long * cycle );
long ( * ch_to_num )( long channel );
/* The following entries are deprecated and exist for backward
compatibility only */
bool ( * set_max_seq_len )( double seq_len );
bool ( * keep_all_pulses )( void );
bool ( * set_phase_switch_delay )( int function, double del_time );
bool ( * set_grace_period )( double gp_time );
} Pulser_Struct;
|
At the start all the pointers in this structure are set to NULL
(fsc2 has still no idea which functions it actually has to
call), name is also a NULL pointer and the boolean
variable needs_phase_pulses is set to false. Now, when the
init_hook of the pulser module gets run it has to fill in values
for all the function pointers it supplies functions for - only this will
allow fsc2 to figure out where the relevant functions to call
are. When the module does not define a function it must leave the
corresponding entry in the structure unchanged, i.e. leave it a
NULL pointer. Most of the following text will try to explain in
detail what the different functions are supposed to do and the meaning
of the arguments of the functions.
But first the three variables to be set will be discussed. The first
variable, name, is simply the name of the pulser that will be
used in error messages etc. When setting this variable within the
init_hook function it should first be checked if it is still a
NULL pointer. If not the module should print an error message and
quit immediately - when name is not NULL a different
pulser module has already been loaded and currently it is not possible
to deal with more than one pulser.
The second variable, needs_phase_pulses, must be set to a true
value only if the experiment the pulser is connected to has phase
switches that need their own pulses and if the module is prepared to
create these phase pulses automatically. Currently, this is only the
case for the Frankfurt S-band spectrometer.
The third variable, has_pods, must be set when the pulser has
internal channels for storing pulse sequences which get mapped to
certain output connectors (pods), like the Sony/Tektronix DG2020.
Per default the variable is set to false.
| • Pulse Functions |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
14.5.1 Pulse Functions
Now follows a list of all functions that can be defined within a pulser
module and advertised to fsc2 by assigning a pointer to the
function in the pulsers structure. All functions are supposed to return
a boolean value. Please remember that not all functions must exist, if
they don't exist and you don't supply a pointer for some of the
functions in the pulser structure fsc2 will tell the user
automatically that the ability associated with the function is not
available with the driver. You can be sure that all time values that
these function receive are integer multiples of one nanosecond.
With the exception of the functions for setting pulse properties
set_pulse_position() set_pulse_length() set_pulse_position_change() set_pulse_length_change() |
and the functions for asking pulse properties, i.e. the functions with
names starting with get_pulse_, all functions will only be called
before the experiment is started, i.e. in the time between the calls of
the init_hook() and the test_hook() function.
During the test run. i.e. between the test_hook() and the
exp_hook() function call (while the global variable
TEST_RUN is set) functions to change pulse positions and lengths
will be called. In this functions the internal representation of the
pulser state has to be updated and the consistency of the state has to
be checked (i.e. do the pulses stay separated, don't they overtake
each other, do the lengths remain larger than zero, do the positions
stay larger than zero and don't exceed the maximum channel length,
etc.). The driver also might choose to store the longest duration of a
pulse sequence during the test run to be used later in the calculation
of the padding needed to set a fixed repeat time for the experiment.
- `bool assign_channel_to_function(int function, long channel)'
This function is called when in the
ASSIGNMENTSsection in the description of a pulse function theCHANNEL(orCH) keyword is found, i.e.ASSIGNMENTS: MW: CH = 1, ....
There are two types of pulsers, pulsers (like the Sony/Tektronix DG2020 that have some internal channels, that can be freely assigned to output connector (and for which the variable
needs_phase_pulsesin the pulser structure must be set), and pulsers (like the Tektronix HFS9000 that just have output channels. For the first type of pulsers this function is called to assign a pulse function to one of the internal channels (and not the output connector, this is what the next function is for, see below), while for the second type of pulsers th function is for assigning a pulse function to one of the output connectors.As discussed in the chapter about pulsers (see Channel setup) there are currently 15 different types of pulse functions. To avoid having to change your module in case the numbering of the functions changes you should only use symbolic names for functions. These symbolic names are defined in `src/global.h':
enum { PULSER_CHANNEL_MW = 0, PULSER_CHANNEL_TWT, PULSER_CHANNEL_TWT_GATE, PULSER_CHANNEL_DET, PULSER_CHANNEL_DET_GATE, PULSER_CHANNEL_DEFENSE, PULSER_CHANNEL_RF, PULSER_CHANNEL_RF_GATE, PULSER_CHANNEL_PULSE_SHAPE, PULSER_CHANNEL_PHASE_1, PULSER_CHANNEL_PHASE_2, PULSER_CHANNEL_OTHER_1, PULSER_CHANNEL_OTHER_2, PULSER_CHANNEL_OTHER_3, PULSER_CHANNEL_OTHER_4 };You also better don't rely on the number of pulse functions, instead of using a hardcoded value of 15 use instead the
PULSER_CHANNEL_NUM_FUNC.Beside the definition of pulse function numbers there is also an array with the full names for the functions (to be used in error messages).
const char * Function_Names[ ] = { "MW", "TWT", "TWT_GATE","DETECTION", "DETECTION_GATE", "DEFENSE", "RF", "RF_GATE", "PULSE_SHAPE", "PHASE_1", "PHASE_2", "OTHER_1", "OTHER_2", "OTHER_3", "OTHER_4" };The functions
PULSER_CHANNEL_PHASE_1andPULSER_CHANNEL_PHASE_2are a bit different from the rest because these functions are reserved for automatically created phase pulses, so the user should never be able to create pulses with both these functions.The second argument of
assign_channel_to_function()obviously is either the number of channel (for pulsers with no pods) or the output connector (for pulsers with pods). Please note that for pulsers of the first type several channels may be assigned to one function (e.g. when automatically created phase pulses are used, i.e. the variableneeds_phase_pulsesis set).- `bool assign_function(int function, long connector)'
For pulsers of the second type, i.e. pulsers that have internal channels and independent output pods this function is used to associate a pulse function to one of the output functions, i.e. if in the function description the
PODkeyword is found:ASSIGNMENTS: MW: POD = 3, ...
Only one function should be assignable to an output connector.
- `bool set_function_high_level(int function, double high_voltage)'
This function is called to set the high voltage level to be output for a certain pulse function, i.e. when the
V_HIGHkeyword is found in the function description. Obviously,high_voltageis the voltage to be used for the high voltage level in Volts.- `bool set_function_low_level(int function, double low_voltage)'
This function is called to set the low voltage level to be output for a certain pulse function, i.e. when the
V_LOWkeyword is found in the function description. To stay compatible with other pulser modules I would recommend not to accept low voltage levels that are actually higher than the high voltage level and to tell the user to use the functioninvert_function()instead.- `bool invert_function(int function)'
This function is called to tell the pulser module that the output for a certain pulse function has to be reversed polarity, i.e. that a high voltage is to be output for a pulse off state while a high voltage has to be output while a pulse with this function is switched on. The function is automatically called for the
INVorINVERTkeyword in the pulse function description.- `bool set_function_delay(int function, double delay)'
This function is called to tell the pulser to use a delay for one of the pulse function, i.e. when the
DELAYkeyword is found in the description of a function. When possible you should be prepared also to accept negative delays (which of course requires that the pulser is triggered internally).- `bool set_timebase(double timebase)'
This function gets called when the
TIMEBASEkeyword is found in theASSIGNMENTSsection, i.e.ASSIGNMENTS: TIMEBASE: 10 ns;
You will have to check that this is an acceptable timebase value and you will also have to check later that all pulse positions, lengths etc. are integer multiples of this timebase.
- `bool set_timebase_level(int level)'
This function gets called when the
TIMEBASEkeyword is found in theASSIGNMENTSsection, followed by eitherTTLorECL, i.e.ASSIGNMENTS: TIMEBASE: 16 ns, TTL;
This indicates that the timebase is derived from external input with either TTL or ECL levels. The argument the function gets passed is an integer, either
TTL_LEVELorECL_LEVEL.- `bool set_trigger_mode(int mode)'
This function gets called when a trigger mode description is found in the assignments section, i.e.
ASSIGNMENTS: TRIGGER_MODE: EXTERNAL;
There are two possible values for the trigger mode, either external or internal. In `src/global.h' an enumeration is already defined for the values of
modewithEXTERNAL(set to1) andINTERNAL(set to0). In order to avoid problems if the values should ever get changed you should use these predefined values.- `bool set_repeat_time(double rep_time)'
The function gets called for setting the repetition time or frequency of an pulsed experiment, i.e. when either the
REPETITION_TIMEorREPETITION_FREQUENCYkeyword is found in the trigger mode description in theASSIGNMENTSsection. Obviously, to be able to set a repetition time or frequency the trigger mode must be internal and the module has to check that this is the case.- `bool set_trig_in_level(double voltage)'
This function is called when the
LEVELkeyword is found in the trigger mode description in theASSIGNMENTSsection to set the trigger level for external trigger mode. The module should tell the user that setting a trigger level doesn't make sense in the case that the user specified internal trigger mode.- `bool set_trig_in_slope(int slope)'
This function is called when the
SLOPEkeyword is found in the trigger mode description in theASSIGNMENTSsection to set the trigger slope for external trigger mode. In `src/global.h' an enumeration is already defined for the values ofslopewithPOSITIVE(for triggering on the trigger input signal crossing the trigger level coming from a lower voltage and set to1) andNEGATIVE(set to0). In order to avoid problems if the values should ever get changed you should use these predefined values. The module should tell the user that setting a trigger slope doesn't make sense in the case that the user specified internal trigger mode.- `bool set_trig_in_impedance(int state)'
This function gets called to set the input impedance of the trigger input channel when the
IMPEDANCEkeyword is found in the trigger mode description in theASSIGNMENTSsection. In `src/global.h' an enumeration is already defined for the values ofstatewithHIGH(set to1) andLOW(set to0). In order to avoid problems if the values should ever get changed you should use these predefined values - this could be the case when a pulser has to be integrated that has more than two different trigger input impedances. The module should tell the user that setting a trigger input impedance doesn't make sense in the case that the user specified internal trigger mode.- `bool set_phase_reference(int phase, int function)'
This again a function that gets called under somewhat different circumstances, depending on how the pulser module is supposed to work. If you are writing a module that has to create phase pulses automatically (and thus you have set the variable
needs_phase_pulsesin the pulser structure), this function will be called when in the definition of a phase function the function the phase pulses will be used with is set. That means if theEDLscript contains a line likeASSIGNMENTS: PHASE_2: MICROWAVE, POD = 2, 3, ....
Obviously, this is meant for a pulser module that automatically creates phase pulses (otherwise the use of a phase function would not be allowed) and this statement is intended to tell the module that the function
PHASE_2(with its pulses appearing on the output connectors 2 and) is to be used to create phase pulses for the microwave pulses. To tell the module the functionset_phase_reference()gets called with the number of the phase function (i.e.PULSER_CHANNEL_PHASE_1orPULSER_CHANNEL_PHASE_1) as the first argument and the number of the pulse function (in the example theMICROWAVEphase function) as the second argument.In contrast, for modules that don't have to create phase pulses this function is called from within the
ASSIGNMENTSsection when lines of the formASSIGNMENTS: PHASE_SETUP_2: MICROWAVE, ...
are found. In this case
MICROWAVEis again the function that is to be phase cycled and is passed to the function as the second argument. The first argument is either0or1, depending on if this pertains to the first phase cycled function (i.e. when the command inEDLscript starts with eitherPHASE_SETUPorPASE_SETUP_1) or the second phase cycled function (i.e. forPHASE_SETUP_2).- `bool phase_setup_prep(int func, int type, int pod, long val)'
Again this function is called under slightly different circumstances, i.e. depending on if you have set the variable
needs_phase_pulsesin the pulser structure (meaning that phase pulses have to be created) or not. In the first case a syntax ofPHASE_1: MICROWAVE, POD = 2, 3; PHASE_SETUP_1: +X: POD_1 = ON, POD2 = OFF, +Y: POD1 = ON, POD_2 = 1, -X: POD2 = 0, 0, -Y: 1, 1;is expected in the
EDLscript. The first line indicates that the phase function 1 is to be used to control phase pulses for microwave pulses and the output pods to be used are the pods 2 and 3. The following lines are supposed to tell the module that in order to create a+Xphase pulse the first output pod set in the definition of the first phase function (PHASE_1) (i.e. pod 2) must be in the high state, while the second pod (i.e. pod 3) must be low.For this kind of phase setup the function
phase_setup_prep()will be called exactly 8 times in a row, 2 times for each phase type (i.e.+X,+Y,-Xand-Y). It will be called always with the first argument set to0to indicate thatPHASE_SETUP_1is currently done (wherePHASE_SETUPwithout a number is just a short form for this), in forPHASE_SETUP_2the first parameter would be1.The second argument is type of phase, in `src/global.h' an enumeration defining
PHASE_PLUS_Xfor a phase of+X,PHASE_PLUS_Yfor+Y,PHASE_MINUS_Xfor-XandPHASE_MINUS_Yfor-Yis defined and should be used in your module. There is also aPHASE_CWpseudo phase type defined in case your module has to support a special cw-mode configuration.The third argument is the output pod to use, where
0stands for the first pod defined previously for the phase function, i.e. in our example a0would represent the pod numbered 2. In contrast, an argument of1indicates the second output pod, i.e. in our example the pod numbered 3. Finally, you also have to expect an argument of-1, meaning "the first of the two pods" if none of both the pods has been set yet for this phase type or "the other one" if already one one the two pods has been set.The fourth and final argument is the state of the output for the put when the pulse is output. In our example this means that it will be
1when a1orONis found in theEDLscript and0forOFFor0.Accordingly, the
EDLcode for the phase setup given above will lead to the following sequence of calls of the functionphase_setup_prep():/* PHASE_SETUP_1: +X: POD_1 = ON, POD2 = OFF, */ phase_setup_prep( 0, PHASE_PLUS_X, 0, 1 ); phase_setup_prep( 0, PHASE_PLUS_X, 1, 0 ); /* +Y: POD1 = ON, POD_2 = 1, */ phase_setup_prep( 0, PHASE_PLUS_Y, 0, 1 ); phase_setup_prep( 0, PHASE_PLUS_Y, 1, 1 ); /* -X: POD2 = 0, 0, */ phase_setup_prep( 0, PHASE_MINUS_X, 1, 0 ); phase_setup_prep( 0, PHASE_MINUS_X, -1, 0 ); /* -Y: 1, 1; */ phase_setup_prep( 0, PHASE_MINUS_Y, -1, 1 ); phase_setup_prep( 0, PHASE_MINUS_Y, -1, 1 );
If you are writing a module that does not create phase pulses (and you accordingly set the variable
needs_phase_pulsesin the pulser structure to false) the phase setup command looks a bit different:PHASE_SETUP_1: MICROWAVE, +X: POD = 1, +Y: POD = 2, -X: POD = 4, -Y: 5, CW: 3;For these
EDLcode the functionphase_setup_prep()gets called five times in a row. Again the first and second parameter the function will receive is the phase setup number (i.e. either0or1, for our example it would be0because we're dealing with the first phase setup), and the second is the phase type (i.e.PHASE_PLUS_X,PHASE_PLUS_Y,PHASE_MINUS_X,PHASE_MINUS_YandPHASE_CW). The third parameter has in this case no meaning at all and its value should be discarded. The fourth and final is the output pod or channel to be used for a pulse with the current phase. Thus, the function would be called in the following sequence (without any other intervening calls except possiblyset_phase_reference()):phase_setup_prep( 0, PHASE_PLUS_X, (discard), 1 ); phase_setup_prep( 0, PHASE_PLUS_Y, (discard), 2 ); phase_setup_prep( 0, PHASE_MINUS_X, (discard), 1 ); phase_setup_prep( 0, PHASE_MINUS_Y, (discard), 2 ); phase_setup_prep( 0, PHASE_CW, (discard), 1 );
Here
(discard)stands for an arbitrary value that has to be discarded.- `bool phase_setup(int func)'
This function is called to tell the module that a phase setup sequence is finished and no further commands of
phase_setup_prep()for the phase setup with numberfunction(i.e. either0for the first phase setup or1for the second) should happen. The module can now do some sanity checks on the data it received from the previousphase_setup_prep()calls or whatever else it needs to do.- `bool new_pulse(long pulse_number)'
This function is called when a new pulse definition is found in the
PREPARATIONSsection, i.e. for lines starting like thisPULSE_13: ...
For this the function will called (with
13as thepulse_numberargument) to tell the module that there's a new pulse to be dealt with. Pulse numbers are always non-negative, so negative pulse numbers can be used for pulses generated internally by the module.- `bool set_pulse_function(long pulse_number, int function)'
This function is called when the function of a new pulse is set in the
PREPARATIONSsection, i.e. forPULSE_13: FUNCTION = MICROWAVE, ...
The first argument is the pulse number (you can be sure that the function
new_pulse()will have been called before with this pulse number as argument) and the pulse function number as the second argument (see the discussion of pulse function numbers above in the description of the functionassign_channel_to_function()). If you don't have a god reason to do otherwise I would recommend to allow neitherPULSER_CHANNEL_PHASE_1norPULSER_CHANNEL_PHASE_2as pulse functions because these functions are usually reserved for internally generated phase pulses.- `bool set_pulse_position(long pulse_number, double ptime)'
This is the function that gets called to tell the module about the start position of a pulse, i.e. for lines like
PULSE_13: START = 100 ns, ...
within the
PREPARATIONSsection or when during the experiment the position of a pulse is changed directly by assigning a new start position i.e. for lines likeP13.START = 260 ns;
If you need different handling of both situations you can assign a new function pointer to the corresponding structure entry at the start of the
EXPERIMENTsection, for example in theexp_hookfunction (or at any other time it is convenient).As in the case of the
set_pulse_function()function the first argument is the pulse number, the second the start position of the pulse in seconds (but guaranteed to be an integer multiple of 1 ns, you still will have to check if it's not negative and also that it isn't an integer multiple of the pulsers timebase).- `bool set_pulse_length(long pulse_number, double ptime)'
The function gets called when the length of a pulse is set in the
EDLfile, i.e. for lines likePULSE_13: ... LENGTH = 2 us, ...within the
PREPARATIONSsection or, within theEXPERIMENTsection, to directly change the length of a pulse, e.g.P13_LENGTH = 2.1 us;
If you need different handling of both situations you can assign a new function pointer to the corresponding structure entry whenever you want.
Obviously, the first argument to the function is the pulse number, the second is the new length of the pulse in seconds. You will have to check yourself within the module that the pulse length hasn't an invalid value. If the length of the pulse is zero you must treat the pulse as switched off for the time being.
- `bool set_pulse_position_change(long pulse_number, double ptime)'
This function is used to tell the module about the start position change of a pulse (i.e. when a pulse definition line containing the
DELTA_STARTkeyword is found in thePREPARATIONSsection or a new value is assigned to theDELTA_STARTvalue of a pulse during the experiment), with the first argument being the pulse number, the second the start position change for the pulse (which might be negative).- `bool set_pulse_length_change(long pulse_number, double ptime)'
This function is used to tell the module about the length change of a pulse (i.e. when a pulse definition line containing the
DELTA_LENGTHkeyword is found in thePREPARATIONSsection or a new value is assigned to theDELTA_LENGTHvalue of a pulse during the experiment), with the first argument being the pulse number, the second the length change for the pulse.- `bool set_pulse_phase_cycle(long pulse_number, long cycle)'
This function is called to set the phase sequence to be used for phase cycling the pulse indexed by the first argument, i.e. when commands like
PULSE_13: PHASE_CYCLE = PHASE_SEQUENCE_1, ...
are found in the
PREPARATIONSsection of theEDLfile. The second argument is either the number1or2, indicating one of the currently allowed two phase sequences. But to avoid the necessity of changes of the module it is probably a good idea to test this value within the function.- `bool get_pulse_function(long pulse_number, int * function)'
This function is called by
fsc2to find out about the function of a pulse from the module. If a pulse with the number passed to the function exists (if it doesn't the module should print out an error message and throw an exception), it should set the variable pointed to by the second argument to the number of the pulses function and return a true value. If no function has been set for the pulse an error message should be printed out and an exception has to be thrown.- `bool get_pulse_position(long pulse_number, double * ptime)'
This function is called by
fsc2to find out about the current position of a pulse (not including function delays) from the module. If a pulse with the number passed to the function exists (otherwise the module should print out an error message and throw an exception), it should set the variable pointed to by the second argument to the start position (in seconds) of the pulse. If no start position has been set for the pulse an error message should be printed out and an exception has to be thrown.- `bool get_pulse_length(long pulse_number, double * ptime)'
This function in the module is called to determine the current length of a pulse. If a pulse with the number passed as the first argument exists the variable the second argument points to has to be set to the length of the pulse (in seconds). If no length has been set for the pulse an error message should be printed out and an exception has to be thrown.
- `bool get_pulse_position_change(long pulse_number, double * ptime)'
This function should return the current setting of the position change setting for the pulse indexed by the argument in the variable pointed to by the second argument. If no start position change vale has been set for the pulse an error message should be printed out and an exception has to be thrown.
- `bool get_pulse_length_change(long pulse_number, double * ptime)'
This function should return the current setting of the length change setting for the pulse indexed by the argument in the variable pointed to by the second argument. If no length change value has been set for the pulse an error message should be printed out and an exception has to be thrown.
- `bool get_pulse_phase_cycle(long pulse_number, long * cycle)'
The function should return the number of the phase sequence (i.e.
1or2) associated with the pulse associated with pulse with the number passed to the function as the first argument. If a phase sequence has been set for the pulse the number has to be written into the variable pointed to bycycle, otherwise (or if no pulse with the number of the first argument exists) an error message has to be printed out and an exception should be thrown.- `long ch_to_num(long channel)'
Different pulser modules have different internal numbering schemes for their channels. On the other hand,
fsc2does only know about all the possible names of channels (as defined in `global.h' and `global.c'). So forfsc2being able to pass channel numbers to the pulser module with the channel numbers the module expects the pulser module must support this function. It gets a channel number in the "global" numbering system according to the definitions in `global.h' and `global.c' and has to translate this number into the internally used channel number. If no translation is possible the module should throw an exception and print out an error message, stating that it has no channel of the nameChannel_Names[channel].- `bool set_max_seq_len(double seq_len)'
This function is called when the
MAXIMUM_SEQUENCE_LENGTHis found in theASSIGNMENTSsection, i.e.ASSIGNMENTS: MAXIMUM_SEQUENCE_LENGTH: 10 us;
If you determine the maximum length of the pulser pattern in your module during the test run the value you get can be plain wrong if the
EDLscript contains e.g.FOREVERloops,IF/ELSEconstructs etc. because it is not possible to determine during the test run which branches of theEDLscript will be run in the real experiment. TheMAXIMUM_SEQUENCE_LENGTHcommand should allow the user to correct the possible wrong value when necessary.The obvious question is why bother at all to determine the maximum length of the pulse pattern and not use instead the maximum pattern length all the time? The reason is that clearing the whole pattern at the start of the experiment for some pulsers can take a rather long time. E.g. for the Sony/Tektronix DG2020 for each of the internal channels that are going to be used more than 64 kB of data would have to be send to the pulser, probably taking several minutes, while in most experiments only a small fraction of the maximum pattern length is really needed.
The use of the keyword
MAXIMUM_SEQUENCE_LENGTHis deprecated. Instead, the pulser module should supply, if necessary, a functionpulser_maximum_sequence_length()that can be used in thePREPARATIONSsection and has the same effect. Assigning anything else thenNULLto theset_max_seq_lenmember of the pulser structure is only for backward compatibility.- `bool bool keep_all_pulses(void)'
This function is called when the
KEEP_ALL_PULSESkeyword is found in theASSIGNMENTSsection. If this function is called your module may not delete pulses that it found during the test run never to be used.The question, of course, is why delete pulses at all that are never used and not keep them? The reason is that when doing phase cycling it can happen that for each additional pulse lots of channels in the digitizer are needed, even to the point that the number of channels is exceeded. Therefor, as a default, pulses that are found to be never used during the test run are removed (after printing out a message to the user).
The use of the keyword
KEEP_ALL_PULSESis deprecated. Instead, the pulser module should supply, if necessary, a functionpulser_keep_all_pulses()that can be used in thePREPARATIONSsection and has the same effect. Assigning anything else thenNULLto thekeep_all_pulsesmember of the pulser structure is only for backward compatibility.- `bool set_phase_switch_delay(int function, double del_time)'
This function is called when in the
ASSIGNMENTSsection a line likePHASE_SWITCH_DELAY: 40 ns;
is found. The module must use the value of the second argument
del_timeas the time that pulses of the phase function indicated by the first argument (which currently can be only either1or2) start before the 'real' pulses of the pulse function the phase function is associated with. Of course, if the module is not prepared to create phase pulses at all, this function does not need to exist and the corresponding entry in the pulsers structure should be left aNULLpointer. If no phase switch delay is set for a phase-cycled function it should (but that's not a necessity but just a recommendation) use a default value of 20 ns.The use of the keyword
PHASE_SWITCH_DELAYis deprecated. Instead, the pulser module should supply, if necessary, a functionpulser_phase_switch_delay()that can be used in thePREPARATIONSsection and has the same effect. Assigning anything else thenNULLto theset_phase_switch_delaymember of the pulser structure is only for backward compatibility.- `bool set_grace_period(double gp_time)'
This function is called when in the
ASSIGNMENTSsection a line likeGRACE_PERIOD: 20 ns;
is found. The module must use the value of the second argument
gp_timeas the time that pulses of the phase function indicated by the first argument remain switched on after the 'real' pulses of the pulse function the phase function is associated with already ended. If these 'real' pulses get to near to each other to allow having both a phase switch delay as well as the 'grace period' the later may be reduced below the value set by the user. If the module is not prepared to create phase pulses at all, this function does not need to exist and the corresponding function pointer entry in the pulsers structure should remain aNULLpointer.The use of the keyword
GRACE_PERIODis deprecated. Instead, the pulser module should supply, if necessary, a functionpulser_grace_period()that can be used in thePREPARATIONSsection and has the same effect. Assigning anything else thenNULLto theset_grace_periodmember of the pulser structure is only for backward compatibility.
![]() |
![]() |
![]() |
![]() |
![]() |
This document was generated by Jens Thoms Toerring on September 6, 2017 using texi2html 1.82.








