summaryrefslogtreecommitdiff
path: root/device-functions.c
diff options
context:
space:
mode:
authorMichael J. Chudobiak <mjc@avtechpulse.com>2012-08-24 10:15:36 -0400
committerMichael J. Chudobiak <mjc@avtechpulse.com>2012-08-24 10:15:36 -0400
commitc116bc537041827e438cec9d49c5249c33f0377e (patch)
treeb60d09aa46abcdfe3fa63a293d1fb4398c9f54a9 /device-functions.c
parent3764cf19983e58a471ac0359509ca81b60526ce3 (diff)
fix attempt at full set of device functions
Diffstat (limited to 'device-functions.c')
-rw-r--r--device-functions.c4346
1 files changed, 4271 insertions, 75 deletions
diff --git a/device-functions.c b/device-functions.c
index 5f3ebc4..002bfe8 100644
--- a/device-functions.c
+++ b/device-functions.c
@@ -1,14 +1,15 @@
#include "device-functions.h"
+#include "dummy_functions.h"
#include "globals.h"
#include "version.h"
#include "error_utils.h"
+#include "i2c.h"
+#include "bus.h"
+#include "lcd.h"
+#include <math.h>
#include <glib.h>
-/*** BeginHeader idn_string */
-void idn_string(gchar** response);
-/*** EndHeader */
-/*----------------------------------------------------------------------------------------------------------*/
void idn_string(gchar** response)
{
*response = g_strdup_printf ("AVTECH ELECTROSYSTEMS,%s,%s,%s",
@@ -18,41 +19,11 @@ void idn_string(gchar** response)
}
-/*----------------------------------------------------------------------------------------------------------*/
-int Set_frequency(int check_possible_only,int word_override,int range_override,int channel,float set_freq)
-{
- // keep, but ignore, the first 3 parameters for now
-
- // all this does right now is check the frequency range,
- // and store the set value.
-
- /* abandon if high channel selected by user but not enabled by firmware */
- if (channel && !globals.Flash.ChanKey_frequency) {
- return InvalidChannel;
- }
-
- if (!check_possible_only) {
- int i, check_valid;
- for (i=0; i<max_channels; ++i) {
- TestState[i]=globals.ChannelState[i];
- }
- TestState[channel].frequency=set_freq;
- if ((check_valid=Error_check(TestState))) {
- return check_valid;
- }
- }
-
- globals.ChannelState[channel].frequency=set_freq;
-
- return OK;
-}
-
-
void Main_Rst (void)
{
int i;
- globals.extended_ampl_min_max=NO;
+ globals.Flags.extended_ampl_min_max=NO;
// go backwards, so channel 0 overrides everything
for (i=globals.Flash.channels-1; i>=0; --i) {
@@ -99,55 +70,4280 @@ void Main_Rst (void)
globals.ChannelState[i].vlogic = 0.0;
globals.ChannelState[i].slew = globals.Flash.min_slew[i];
- globals.do_check_settings=NO; /* don't check for conflicting settings */
- /* FIXME - implement Set_* functions!
- Set_Pw(0,0,0,i,globals.ChannelState[i].pw,0);
-
- Set_Route(i,ROUTE_PRIMARY,globals.ChannelState[i].route_primary);
- Set_Route(i,ROUTE_SECONDARY,globals.ChannelState[i].route_secondary);
-
- Set_frequency(0,0,0,i,globals.ChannelState[i].frequency);
- Set_Delay(0,0,0,i,globals.ChannelState[i].delay);
- Set_Double(i,globals.ChannelState[i].double_pulse);
- Set_Pwmode(i,globals.ChannelState[i].ab_mode);
- Set_Func(i,globals.ChannelState[i].func_mode);
- Set_Pol(i,globals.ChannelState[i].polarity);
- Set_Gate_Sync(i,globals.ChannelState[i].gate_type);
- Set_Gate_Level(i,globals.ChannelState[i].gate_level);
- Set_EA(i,globals.ChannelState[i].amp_mode);
- Set_EO(i,globals.ChannelState[i].os_mode);
- if (globals.Flash.switchable_zout[i]) {
- Set_zout(i,globals.ChannelState[i].zout,1);
+ globals.Flags.do_check_settings=NO; /* don't check for conflicting settings */
+ Set_Pw(0,0,0,i,globals.ChannelState[i].pw,0);
+
+ Set_Route(i,ROUTE_PRIMARY,globals.ChannelState[i].route_primary);
+ Set_Route(i,ROUTE_SECONDARY,globals.ChannelState[i].route_secondary);
+
+ Set_frequency(0,0,0,i,globals.ChannelState[i].frequency);
+ Set_Delay(0,0,0,i,globals.ChannelState[i].delay);
+ Set_Double(i,globals.ChannelState[i].double_pulse);
+ Set_Pwmode(i,globals.ChannelState[i].ab_mode);
+ Set_Func(i,globals.ChannelState[i].func_mode);
+ Set_Pol(i,globals.ChannelState[i].polarity);
+ Set_Gate_Sync(i,globals.ChannelState[i].gate_type);
+ Set_Gate_Level(i,globals.ChannelState[i].gate_level);
+ Set_EA(i,globals.ChannelState[i].amp_mode);
+ Set_EO(i,globals.ChannelState[i].os_mode);
+ if (globals.Flash.switchable_zout[i]) {
+ Set_zout(i,globals.ChannelState[i].zout,1);
+ }
+
+ Set_Load(i,globals.ChannelState[i].load_type);
+ Set_Logic_Level(i,globals.ChannelState[i].logic_level);
+ Set_rise_time(0,0,0,i,globals.ChannelState[i].rise_time);
+ Set_slew(0,0,0,i,globals.ChannelState[i].slew);
+ Set_current_limit(0,i,globals.ChannelState[i].soft_current_limit);
+
+ if (globals.Flash.max_burst_count[i]>1) {
+ Set_Burst_Count(i,globals.ChannelState[i].burst_count,globals.ChannelState[i].burst_time);
+ }
+
+ Set_Trig_Source(i,globals.ChannelState[i].trigger_source);
+
+ Set_Amplitude(0,0,0,0,0,0,i,globals.ChannelState[i].amplitude,0);
+ Set_Offset(0,0,0,0,i,globals.ChannelState[i].offset);
+ Set_Output_State(i,globals.ChannelState[i].output_state);
+
+ Set_current_limit(0,i,globals.ChannelState[i].soft_current_limit);
+
+ Set_avrq_ampl(0,0,0,2,globals.ChannelState[i].vcc1);
+ Set_avrq_ampl(0,0,0,3,globals.ChannelState[i].vcc2);
+ Set_avrq_ampl(0,0,0,4,globals.ChannelState[i].vlogic);
+ globals.Flags.do_check_settings=YES; /* check for conflicting settings */
+ }
+
+ // establishes min/max values for queries, but reports no errors
+ Error_check(globals.ChannelState);
+ globals.Changes.update_whole_main_menu=YES;
+
+ Ctrl_PRF_Limiter(1);
+
+ globals.Timers.normal_relay_bounce_time_in_milliseconds=1.0e3 * globals.Flash.relay_delay_in_sec;
+ globals.Timers.Relay_Switching_Delay_in_Milliseconds=globals.Timers.normal_relay_bounce_time_in_milliseconds;
+
+ // FIXME - check which misc globals should be reset here!
+
+ Menu_Clear_Buttons();
+}
+
+
+int set_dac(int dac, int word)
+{
+ /* allows dacs to be disabled (using dac=-1, for example) */
+ if ((dac >= 0) && (dac < 8)) {
+ globals.Registers.parallel_DAC_reg[dac]=word;
+ }
+}
+
+
+int Set_Amplitude(int check_possible_only,int pol_override,int override_on,int word_override,int range_override,
+ int switch_range_only,int channel,float new_ampl,int called_from_set_pw)
+{
+ int word_out; /* what is sent to the DAC */
+ int relay_range,old_range,old_actual_pol; /* selects relay range */
+ int i;
+ int error_num;
+ int UseNegData; /* if polarity is negative and separate piece-wise linear data is available for neg */
+ int point_found;
+ long mask;
+ int entry;
+ int status;
+ int actual_pol;
+
+ if (globals.Flash.enable_avrq_extra_ampls && channel) {
+ return Set_avrq_ampl(check_possible_only,word_override,range_override,channel,new_ampl);
+ }
+ if (globals.Flash.enable_avrq_extra_ampls && !channel) {
+ if ((new_ampl>=0.0) && (new_ampl<globals.Flash.ampl_zero_equiv[channel])) {
+ new_ampl=globals.Flash.ampl_zero_equiv[channel];
+ }
+ if ((new_ampl<0.0) && (new_ampl>-globals.Flash.ampl_zero_equiv[channel])) {
+ new_ampl=-globals.Flash.ampl_zero_equiv[channel];
+ }
+ }
+
+ if (!globals.Flash.voltage_enabled[channel] && !globals.Flash.current_enabled[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_amplitude) {
+ return InvalidChannel;
+ }
+
+ /* keep "-0" in negative area, to avoid using zeroed positive data */
+ if ( new_ampl<=smallest_allowed_number
+ && new_ampl>=-smallest_allowed_number
+ && !(globals.Flash.max_ampl[channel]>0) ) {
+ new_ampl=-smallest_allowed_number;
+ }
+
+ /* Check for min abs value, step size */
+ if (globals.Flash.ampl_min_abs_value[channel] > 0.0) {
+ if ((new_ampl < 0.0) &&
+ (new_ampl > -globals.Flash.ampl_min_abs_value[channel])) {
+ new_ampl = -globals.Flash.ampl_min_abs_value[channel];
+ }
+ if ((new_ampl >= 0.0) &&
+ (new_ampl < globals.Flash.ampl_min_abs_value[channel])) {
+ new_ampl = globals.Flash.ampl_min_abs_value[channel];
+ }
+ }
+
+ /* For units with large amplitude step sizes (AVRQ-2-B-PN-EVE) */
+ if (globals.Flash.ampl_step_size[channel] > 0.0) {
+ new_ampl = ((int) (new_ampl / globals.Flash.ampl_step_size[channel])) * globals.Flash.ampl_step_size[channel];
+ }
+
+ if (!check_possible_only) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].amplitude=new_ampl;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ /* determine the previous relay range */
+ Set_VI_Control(pwl_ampl_values,channel,globals.ChannelState[channel].amplitude,&point_found,
+ &old_range,&UseNegData,&entry,&word_out,&old_actual_pol);
+ }
+
+ word_out = -1;
+ relay_range = 0;
+
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+
+ if (override_on) {
+ word_out=word_override;
+ relay_range=range_override;
+ actual_pol=pol_override;
+ } else {
+ /* set the amplitude controls now. */
+ if ((status=Set_VI_Control(pwl_ampl_values,channel,new_ampl,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ /* when switching to EA mode, need to switch range but keep DAC voltage zero */
+ if (switch_range_only) {
+ word_out=0;
+ }
+
+
+ /* if switching to a higher range with the same polarity, an extended delay may be needed to allow */
+ /* capacitor banks to discharge (1011, 1015 series especially) */
+ if ((relay_range>old_range) && (actual_pol==old_actual_pol) ) {
+ globals.Timers.Relay_Switching_Delay_in_Milliseconds=(long) (1000L * globals.Flash.extended_relay_delay_in_sec);
+ }
+
+
+ set_dac(globals.Flash.ampl_DAC[channel],word_out);
+
+
+ if (!channel) {
+ if (!globals.Flash.ampl_ranges_for_ch2_only) {
+ if ((globals.Flash.ChanKey_amplitude?globals.Flash.channels:1)<=1) {
+ /* for regular, single-channel units use AMPL RANGE pins 0-4 */
+ globals.Registers.shift_reg_out[3] = ((long)(globals.Registers.shift_reg_out[3] & 0xff07f)) | ((long)(1<<(relay_range+7)));
+ } else {
+ /* for CH1 of dual-channel units, use AMPL RANGE pin 0-2 for CH1, and 3-4 for CH2 */
+ globals.Registers.shift_reg_out[3] = ((long)(globals.Registers.shift_reg_out[3] & 0xffc7f)) | ((long)(1<<(relay_range+7)));
+ }
+ }
+
+ if ( (!actual_pol && globals.Flash.pol_relay_high_for_pos[channel])
+ || (actual_pol && !globals.Flash.pol_relay_high_for_pos[channel]) ) {
+ globals.Registers.shift_reg_out[3] |= (long)(0x02000); /* set O.POL line high to switch pol relay to +, normally */
+ } else {
+ globals.Registers.shift_reg_out[3] &= (long)(0xfffff-0x02000); /* set O.POL line low to switch pol relay to -, normally */
+ }
+
+ } else {
+
+ if (!globals.Flash.ampl_ranges_for_ch2_only) {
+ /* for CH2 of dual-channel units, use AMPL RANGE pin 2-3 */
+ globals.Registers.shift_reg_out[3] = ((long)(globals.Registers.shift_reg_out[3] & 0xff3ff)) | ((long)(1<<(relay_range+10)));
+ } else {
+ /* sometimes CH2 can use pins 0-4 */
+ globals.Registers.shift_reg_out[3] = ((long)(globals.Registers.shift_reg_out[3] & 0xff07f)) | ((long)(1<<(relay_range+7)));
+ }
+
+ mask = ((long) 1) << (globals.Flash.polarity_xtra_rly[channel]+14);
+ if (new_ampl<0.0) {
+ globals.Registers.shift_reg_out[2] &= (long)(0xfffff-mask); /* set O.POL line low to switch pol relay to - */
+ } else {
+ globals.Registers.shift_reg_out[2] |= mask; /* set O.POL line high to switch pol relay to + */
+ }
+ }
+
+ globals.Changes.update_amp=YES;
+
+ globals.ChannelState[channel].amplitude=new_ampl;
+ Set_Update_Chans();
+
+ if ((relay_range!=old_range) && (globals.ChannelState[channel].output_state==output_on)) {
+ globals.Flags.force_output_fully_off=YES;
+ }
+
+ /* update offset */
+ if (globals.Flash.ampl_os_ranges_related[channel] && !globals.Changes.update_os) {
+ Set_Offset(0,0,0,0,channel,globals.ChannelState[channel].offset);
+ }
+
+ /* ampl / pw tweaks */
+ if (!called_from_set_pw) {
+ Set_Pw(0,0,0,channel,globals.ChannelState[channel].pw,1);
+ }
+
+ /* ampl / delay tweaks */
+ Set_Delay(0,0,0,channel,globals.ChannelState[channel].delay);
+ Set_rise_time(0,0,0,channel,globals.ChannelState[channel].rise_time);
+
+ return OK;
+}
+
+
+int Set_Pw(int check_possible_only,int word_override,int range_override,int channel,float set_pw,int called_from_set_ampl)
+{
+ int word_out; /* what is sent to the DAC */
+ int cap_range_control;
+ int point_found,relay_range,UseNegData,entry;
+ int i;
+ int check_valid;
+ int status,actual_pol;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_pw) {
+ return InvalidChannel;
+ }
+
+ /* for fixed PW units, set actual trigger PW to a reasonable minimum */
+ if (globals.Flash.fixed_pw[channel]
+ && !check_possible_only
+ && !word_override
+ && !range_override
+ && (globals.Flash.fully_programmed==All_Programmed)) {
+ set_pw=globals.Flash.min_pw[channel];
+ }
+
+ if (!check_possible_only) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].pw=set_pw;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ /* set the pw controls now. */
+ if ((status=Set_VI_Control(pwl_pw_values,channel,set_pw,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ if (relay_range==0) {
+ cap_range_control=0;
+ } else {
+ cap_range_control = 1 << (relay_range-1);
+ }
+
+ /* if this is for CH1, use the standard output chain */
+ if (channel==0) {
+ if (globals.Flash.special_pw_range_minimum[channel] > 0.0) {
+ if (set_pw > globals.Flash.special_pw_range_minimum[channel]) {
+ globals.Registers.shift_reg_out[2] = ((long) (globals.Registers.shift_reg_out[2] & 0xeffff)) | (long) 1<<16;
+ } else {
+ globals.Registers.shift_reg_out[2] = ((long) (globals.Registers.shift_reg_out[2] & 0xeffff));
+ }
+ }
+
+ /* AVPP-style: lower PW range is voltage-controlled */
+ if (globals.Flash.volt_ctrl_pw[channel]) {
+ /* use DAC8420 to control PW in lowest PW range */
+ if (!relay_range) {
+ set_dac(globals.Flash.pw_dac[channel],word_out);
+ word_out=globals.Flash.fix_pw_dac_val[channel];
+ /* Set to fixed value. */
+ /* Isn't actually used to control PW in this mode, but may trigger following stages */
+
+ /* Zout hardware/software is used in AVPP to control PW ranges, not Zout */
+ Set_zout(channel,globals.Flash.zout_min[channel],0);
+ } else {
+ Set_zout(channel,globals.Flash.zout_max[channel],0);
+
+ /* In AVPP units, the bottom range is voltage-controlled, and the upper range(s) are
+ PWin=PWout. Therefore, shift the relay used by the upper ranges by one, to avoid
+ changing capacitors. */
+
+ if (relay_range==1) {
+ cap_range_control=0;
+ } else {
+ cap_range_control = 1 << (relay_range-2);
+ }
+ }
+ }
+
+ /* set fine controls */
+ set_dac(4,word_out);
+
+ /* set ranges */
+ globals.Registers.shift_reg_out[3] = ((long)(globals.Registers.shift_reg_out[3] & 0xfff80)) | ((long)(cap_range_control));
+ }
+
+ if (channel==1) {
+ /* if this is for CH2, use the standard 1021D dual-PW board, which has a PCF8574 for I/O, */
+ /* unless it is a voltage-controlled scheme like the ISI units. */
+ if (!globals.Flash.volt_ctrl_pw[channel]) {
+ control_pcb107(Second_PW_Port,globals.Flash.pw_dac[channel],word_out,relay_range);
+ } else {
+ /* ISI-style units have voltage-controlled PW and two ranges */
+ set_dac(globals.Flash.pw_dac[channel],word_out);
+
+ /* two ranges controlled by XTRA-RLY2 line */
+ globals.Registers.shift_reg_out[2] = ((long) (globals.Registers.shift_reg_out[2] & 0xeffff)) | (long) (((long) (relay_range&1))<<16);
+ }
+ }
+
+ /* need a center-frequency control voltage for monocycle generators, to space the + and - parts of the monocycle. */
+ /* use CH2 calibration to do this */
+ if (globals.Flash.is_monocycle[0] && channel==0) {
+ if ((status=Set_VI_Control(pwl_pw_values,1,set_pw,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ set_dac(globals.Flash.monocycle_dac[0],word_out);
+ }
+
+ if (set_pw!=globals.ChannelState[channel].pw) {
+ globals.Changes.update_pw=YES;
+ }
+
+ globals.ChannelState[channel].pw=set_pw;
+ Set_Update_Chans();
+
+ if (!called_from_set_ampl) {
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude,1);
+ }
+
+ return OK;
+}
+
+
+int Set_Offset(int check_possible_only,int override_on,int word_override,int range_override,int channel,float new_offset)
+{
+ int word_out; /* what is sent to the DAC */
+ int i;
+ int error_num;
+ int point_found;
+ int entry,dummy1,dummy2,dummy3;
+ int status,actual_pol;
+ int old_range,relay_range;
+
+ if (!globals.Flash.voltage_offset_enabled[channel] && !globals.Flash.current_offset_enabled[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_offset) {
+ return InvalidChannel;
+ }
+
+ word_out = -1;
+ point_found = 0;
+
+ if (!check_possible_only) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].offset=new_offset;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ /* determine the previous relay range */
+ Set_VI_Control(pwl_os_values,channel,globals.ChannelState[channel].offset,&point_found,
+ &old_range,&dummy1,&dummy2,&word_out,&dummy3);
+ }
+
+ if (override_on) {
+ relay_range=range_override;
+ word_out=word_override;
+ } else {
+ if ((status=Set_VI_Control(pwl_os_values,channel,new_offset,&point_found,
+ &relay_range,&dummy2,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ set_dac(globals.Flash.os_DAC[channel],word_out);
+
+ globals.Changes.update_os=YES;
+
+ globals.ChannelState[channel].offset=new_offset;
+ Set_Update_Chans();
+
+ if ((relay_range!=old_range) && (globals.ChannelState[channel].output_state==output_on)) {
+ globals.Flags.force_output_fully_off=YES;
+ }
+
+ if ((globals.Flash.ampl_coupled_to_os[channel] || globals.Flash.ampl_os_ranges_related[channel]) && !globals.Changes.update_amp) {
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude,0);
+ }
+
+ /* change amplitude range if required for calibration */
+ if (override_on) {
+ Set_Amplitude(0,0,1,0,relay_range,0,channel,0.0,0);
+ }
+
+ /* increase PW if required to compensate for series output diode turn-on time */
+ if (globals.Flash.distort_Y[channel] != 0.0) {
+ Set_Pw(0,0,0,channel,globals.ChannelState[channel].pw,0);
+ }
+
+ return OK;
+}
+
+
+int Set_frequency(int check_possible_only,int word_override,int range_override,int channel,float set_freq)
+{
+ int cap_range_control; /* what's actually sent to SR */
+ int i;
+ int check_valid;
+ float new_pw;
+ int status;
+ int point_found,relay_range,UseNegData,entry,actual_pol,old_range;
+ int word_out; /* what is sent to the DAC */
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_frequency) {
+ return InvalidChannel;
+ }
+
+ word_out = -1;
+
+ /* check new duty cycle, if pw fixed */
+ if (globals.ChannelState[channel].hold_setting==hold_width) {
+ new_pw=globals.ChannelState[channel].pw;
+ } else {
+ new_pw=globals.ChannelState[channel].pw * globals.ChannelState[channel].frequency/set_freq;
+ }
+
+ if (!check_possible_only) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].pw=new_pw;
+ TestState[channel].frequency=set_freq;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+
+ /* added Feb 23/05 */
+ /* determine the previous relay range */
+ Set_VI_Control(pwl_period_values,channel,1.0/globals.ChannelState[channel].frequency,&point_found,
+ &old_range,&UseNegData,&entry,&word_out,&actual_pol);
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ /* set the amplitude controls now. */
+ if ((status=Set_VI_Control(pwl_period_values,channel,1.0/set_freq,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ if (globals.Flash.is_func_gen[channel]) {
+ set_dac(globals.Flash.freq_dac[channel],word_out);
+
+ /* Function generator PRF range controlled by XTRA-RLY 1-3 lines. */
+ /* Range=0 disables oscillator, for amplifier mode. */
+
+ if (globals.ChannelState[channel].func_mode==amp_mode_on) {
+ relay_range=0;
+ }
+
+ globals.Registers.shift_reg_out[2] = ((long) (globals.Registers.shift_reg_out[2] & 0xc7fff)) | (long) (((long) (relay_range & 0x07))<<15);
+
+ if ((relay_range!=old_range) && (globals.ChannelState[channel].output_state==output_on)) {
+ globals.Flags.force_output_fully_off=YES;
+ }
+ }
+
+ else {
+ if (relay_range==0) {
+ cap_range_control=0;
+ } else {
+ cap_range_control = 1 << (relay_range-1);
+ }
+
+ set_dac(globals.Flash.freq_dac[channel],word_out);
+ globals.Registers.shift_reg_out[2] = ((long)(globals.Registers.shift_reg_out[2] & 0xfff00)) | ((long)cap_range_control); /* bottom 8 bits of 20 bits */
+ }
+
+ if (set_freq!=globals.ChannelState[channel].frequency) {
+ globals.Changes.update_freq=YES;
+ }
+
+ globals.ChannelState[channel].frequency=set_freq;
+
+ Set_Pw(0,0,0,channel,new_pw,0);
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Delay(int check_possible_only,int word_override,int range_override,int channel,float set_delay)
+{
+ int word_out; /* what is sent to the DAC */
+ int cap_range_control; /* what is actually sent to shift register */
+ float setting;
+ int i;
+ int check_valid;
+ int status;
+ int point_found,relay_range,UseNegData,entry,actual_pol;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_delay) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].delay=set_delay;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ setting=set_delay-globals.Flash.propagation_delay[channel];
+
+ /* tweak depending on polarity */
+ if (globals.ChannelState[channel].amplitude<0.0) {
+ setting -= globals.Flash.delay_pol_tweak[channel][1];
+ } else {
+ setting -= globals.Flash.delay_pol_tweak[channel][0];
+ }
+
+ if (setting >= 0.0) {
+ Set_AdvDel(channel,to_Advance);
+ } else {
+ Set_AdvDel(channel,to_Delay);
+ setting *= -1;
+ }
+
+ setting=setting+globals.Flash.delay_shrink[channel];
+
+ /* protect against impossible settings during first turn-on */
+ if (setting<zero_equiv_timing) {
+ return HardwareError;
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ /* set the amplitude controls now. */
+ if ((status=Set_VI_Control(pwl_delay_values,channel,setting,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+
+ if (relay_range==0) {
+ cap_range_control=0;
+ } else {
+ cap_range_control = 1 << (relay_range-1);
+ }
+
+ if (channel==0) {
+ set_dac(globals.Flash.delay_dac[channel],word_out);
+ globals.Registers.shift_reg_out[2] = ((long)(globals.Registers.shift_reg_out[2] & 0xf80ff)) | ((long)cap_range_control<<8);
+ }
+
+ if (channel==1) {
+ control_pcb107(Second_Dly_Port,globals.Flash.delay_dac[channel],word_out,relay_range);
+ }
+
+ if (set_delay!=globals.ChannelState[channel].delay) {
+ globals.Changes.update_delay=YES;
+ }
+
+ globals.ChannelState[channel].delay=set_delay;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Double(int channel,int new_setting)
+{
+ int error_num;
+ int i;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_double_pulse) {
+ return InvalidChannel;
+ }
+
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].double_pulse=new_setting;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (new_setting == double_off) {
+ globals.Registers.shift_reg_out[0] &= 0xdf; /* turn double-pulse off */
+ } else {
+ globals.Registers.shift_reg_out[0] |= 0x20; /* turn double-pulse on */
+ }
+
+ if (globals.ChannelState[channel].double_pulse!=new_setting) {
+ globals.Changes.update_delay=YES;
+ }
+
+ globals.ChannelState[channel].double_pulse=new_setting;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+void Ctrl_PRF_Limiter(int enable)
+{
+ if (enable && globals.Flash.prf_limiter) {
+ globals.Registers.shift_reg_out[0] |= 0x80; /* turn prf limiter on */
+ } else {
+ globals.Registers.shift_reg_out[0] &= 0x7f; /* turn prf limiter off */
+ }
+
+ Main_update_shift_registers();
+
+ return;
+}
+
+
+int Set_Mux(int channel)
+{
+ int mux_out;
+
+ if (globals.ChannelState[channel].func_mode==dc_mode_on && globals.ChannelState[channel].polarity==pol_norm) {
+ mux_out=4;
+ } else if (globals.ChannelState[channel].func_mode==dc_mode_on && globals.ChannelState[channel].polarity!=pol_norm) {
+ mux_out=5;
+ } else if (globals.ChannelState[channel].ab_mode==pw_normal && globals.ChannelState[channel].polarity==pol_norm) {
+ mux_out=2;
+ } else if (globals.ChannelState[channel].ab_mode==pw_normal && globals.ChannelState[channel].polarity!=pol_norm) {
+ mux_out=3;
+ } else if (globals.ChannelState[channel].polarity==pol_norm) {
+ mux_out=0;
+ } else if (globals.ChannelState[channel].polarity!=pol_norm) {
+ mux_out=1;
+ }
+
+ if (globals.ChannelState[channel].test_delay_mode==YES) {
+ mux_out=6;
+ }
+
+ globals.Registers.shift_reg_out[1] = (globals.Registers.shift_reg_out[1] & 0xf8) + mux_out;
+}
+
+
+int Set_Func(int channel,int mode)
+{
+ int i;
+ int check_valid;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_func_mode) {
+ return InvalidChannel;
+ }
+
+ if ( (mode==dc_mode_on) && !globals.Flash.dc_mode_allowed[channel]) {
+ return SyntaxError;
+ }
+
+ /* some modes are for function generators only */
+ if ( ((mode==sin_mode_on) || (mode==squ_mode_on) || (mode==tri_mode_on) || (mode==amp_mode_on))
+ && !globals.Flash.is_func_gen[channel]) {
+ return SyntaxError;
+ }
+
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].func_mode=mode;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+
+ if (globals.Flash.is_func_gen[channel]) {
+ /* set sin, tri, squ lines */
+ globals.Registers.shift_reg_out[3] = ((long) (globals.Registers.shift_reg_out[3] & 0x1ffff))
+ | (long) (((long) (mode & 0x07))<<17);
+
+ /* set amplify mode line */
+
+ globals.Registers.shift_reg_out[2] = ((long) (globals.Registers.shift_reg_out[2] & 0xbffff))
+ | (long) (((long) (mode & 0x08)) << (globals.Flash.ext_amplify_xtra_rly[channel]+11));
+
+ globals.Changes.update_func=YES;
+ }
+
+
+ /* reset pulse width and delay to safe values */
+ if (globals.ChannelState[channel].func_mode!=mode) {
+ globals.ChannelState[channel].func_mode=mode;
+
+ Set_Pw(0,0,0,channel,globals.Flash.min_pw[channel],0);
+ Set_Delay(0,0,0,channel,globals.Flash.min_delay[channel]);
+
+ /* update frequency, to reset func gen control lines */
+ Set_frequency(0,0,0,channel,globals.ChannelState[channel].frequency);
+
+ Set_current_limit(0,channel,globals.ChannelState[channel].soft_current_limit);
+ }
+
+ Set_Mux(channel);
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Pol(int channel,int mode)
+{
+ int error_num, i;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_polarity) {
+ return InvalidChannel;
+ }
+
+ /* duty cycle check */
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].polarity=mode;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (globals.ChannelState[channel].polarity!=mode) {
+ globals.Changes.update_inv=YES;
+ }
+
+ globals.ChannelState[channel].polarity=mode;
+
+ Set_Mux(channel);
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Hold(int channel,int mode)
+{
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_hold_setting) {
+ return InvalidChannel;
+ }
+
+ if (globals.ChannelState[channel].hold_setting!=mode) {
+ globals.Changes.update_pw=YES;
+ }
+
+ globals.ChannelState[channel].hold_setting=mode;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Output_State(int channel,int mode)
+{
+ int i, error_num;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_output_state) {
+ return InvalidChannel;
+ }
+
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].output_state=mode;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ /* suppress triggering during relay bounce */
+ /* set gate bit high, if not already high */
+
+ for (i=0; i<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++i)
+ if (globals.ChannelState[i].trigger_source!=source_hold) {
+ bus_setpin(O_GATE, 1);
+ }
+
+ if (mode==output_on || !globals.Flash.on_off_used) {
+ /* do not permit enabling of output during overload condition */
+ if ( (I2C_Read(PCF8574A+Button_Press_Port) & 0x40) == 0) {
+ return Overload_Detected;
+ }
+
+ bus_setpin(OUTPUT_RELAY, 1); /* turn output on */
+ bus_setpin(PW_ENABLE, 1); /* enable PW circuit */
+ globals.Timers.last_activity_at[channel] = sec_timer();
+ } else {
+ bus_setpin(PW_ENABLE, 0); /* disable PW circuit */
+ bus_setpin(OUTPUT_RELAY, 0); /* turn output off */
+ globals.Timers.last_activity_at[channel] = 0L;
+ }
+
+ if (globals.ChannelState[channel].output_state!=mode) {
+ globals.Changes.update_output=YES;
+ }
+
+ globals.ChannelState[channel].output_state=mode;
+ Set_Update_Chans();
+
+
+ /* keep trigger suppressed during output relay update */
+ /* trigger gate will be released at end of following Main_update_shift_registers(); */
+
+ return OK;
+}
+
+
+int Set_Trig_Source(int channel,int mode)
+{
+ int gate_mode;
+ int i;
+ int error_num;
+ int use_ab_mode;
+ int reset_freq;
+ float use_freq;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_trigger_source) {
+ return InvalidChannel;
+ }
+
+ use_ab_mode = globals.ChannelState[channel].ab_mode;
+ use_freq = globals.ChannelState[channel].frequency;
+ reset_freq = 0;
+
+ if (globals.ChannelState[channel].trigger_source!=mode) {
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].trigger_source = mode;
+
+ if ((globals.ChannelState[channel].trigger_source != source_hold) && (mode != source_hold)) {
+ reset_freq = 1;
+ use_freq = globals.Flash.min_freq[channel];
+ use_ab_mode = pw_normal;
+ }
+
+ TestState[channel].ab_mode = use_ab_mode;
+ TestState[channel].frequency = use_freq;
+
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (reset_freq) {
+ Set_frequency(0,0,0,channel,use_freq);
+ Set_Pwmode(channel,use_ab_mode);
+ }
+
+ globals.Changes.update_freq=YES;
+ }
+
+ globals.ChannelState[channel].trigger_source=mode;
+ Set_Update_Chans();
+
+
+ /* Function generator operate in the "external" mode only. The internal oscillator is never used. */
+ if (globals.Flash.is_func_gen[channel]) {
+ mode=source_external;
+ }
+
+
+ if (mode==source_internal) {
+ gate_mode=0;
+ /* frequency is automatically lowered if pw or delay have been changed to conflicting */
+ /* settings while in a non-internal mode */
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 0;
+ } else if (mode==source_external) {
+ gate_mode=0;
+ globals.ChannelState[channel].hold_setting=hold_width;
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 3<<2;
+ } else if (mode==source_manual) {
+ gate_mode=0;
+ globals.ChannelState[channel].hold_setting=hold_width;
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 1<<2;
+ } else if (mode==source_hold) {
+ gate_mode=1;
+ } else if (mode==source_immediate) {
+ if (gate_mode==1) {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 4<<2;
+ Main_update_shift_registers();
+ gate_mode=0; /* allow triggering */
+ bus_setpin(O_GATE, gate_mode);
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 7<<2;
+ } else {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 4<<2;
+ Main_update_shift_registers();
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xe3) | 7<<2;
+ }
+ }
+
+ Main_update_shift_registers();
+ bus_setpin(O_GATE, gate_mode); /* change gate only after new source set */
+
+ return OK;
+}
+
+
+int Set_Gate_Sync(int channel,int mode)
+{
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_gate_type) {
+ return InvalidChannel;
+ }
+
+ if (mode==gate_sync) {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xfe) | 0;
+ } else {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xfe) | 1;
+ }
+
+ if (globals.ChannelState[channel].gate_type!=mode) {
+ globals.Changes.update_gate=YES;
+ }
+
+ globals.ChannelState[channel].gate_type=mode;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Gate_Level(int channel,int mode)
+{
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_gate_level) {
+ return InvalidChannel;
+ }
+
+ if (mode==0) {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xfd) | 0x02;
+ } else {
+ globals.Registers.shift_reg_out[0] = (globals.Registers.shift_reg_out[0] & 0xfd) | 0;
+ }
+
+ if (globals.ChannelState[channel].gate_level!=mode) {
+ globals.Changes.update_gate=YES;
+ }
+
+ globals.ChannelState[channel].gate_level=mode;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int start_gate_override ()
+{
+ /* just set gate bit high, if not already high */
+ int i;
+ for (i=0; i<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++i)
+ if (globals.ChannelState[i].trigger_source!=source_hold) {
+ bus_setpin(O_GATE, 1);
+ }
+}
+
+
+int stop_gate_override ()
+{
+ /* release gate (if not in hold mode) */
+ int i;
+ for (i=0; i<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++i)
+ if (globals.ChannelState[i].trigger_source!=source_hold) {
+ bus_setpin(O_GATE, 0);
+ }
+}
+
+
+int Set_zout(int channel,int setting,int really_for_zout)
+{
+ int update_zout_slowly;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_zout) {
+ return InvalidChannel;
+ }
+
+ update_zout_slowly=NO;
+
+ /* The Zout hardware and software is controlled by PW commands in the AVPP. */
+ /* This mode is signalled by really_for_zout=0 */
+
+ /* first channel uses dedicated Zout line */
+ if (channel==0) {
+ if (setting!=globals.Flash.zout_max[channel]) {
+ globals.Registers.shift_reg_out[3] |= (long)0x01000; /* power zout relay */
+ } else {
+ globals.Registers.shift_reg_out[3] &= (long)0xfefff; /* de-power zout relay */
+ }
+ }
+
+ /* second channel uses dedicated xtra-rly2 line */
+ if (channel==1) {
+ if (setting!=globals.Flash.zout_max[channel]) {
+ globals.Registers.shift_reg_out[2] |= (long)0x10000; /* power zout relay */
+ } else {
+ globals.Registers.shift_reg_out[2] &= (long)0xeffff; /* de-power zout relay */
+ }
+ }
+
+ if (setting!=globals.ChannelState[channel].zout) {
+ globals.Changes.update_zout=YES;
+
+ /* allow extra time for cap banks to discharge if going from
+ 50 Ohms to 2 Ohm Zout */
+ if (setting<globals.ChannelState[channel].zout) {
+ update_zout_slowly=YES;
+ }
+ }
+
+ globals.ChannelState[channel].zout=setting;
+ Set_Update_Chans();
+
+ /* Skip this stuff if this is actually for AVPP PW control */
+ if (really_for_zout) {
+ if (globals.Changes.update_zout) {
+ /* change of Zout may require change in amplitude controls */
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude,0);
+ }
+
+ if (update_zout_slowly) {
+ globals.Timers.Relay_Switching_Delay_in_Milliseconds=(long) (1000L * globals.Flash.extended_relay_delay_in_sec);
+ }
+ }
+
+ return OK;
+}
+
+
+int Set_Load(int channel, float value)
+{
+ int error_num;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_load_type) {
+ return InvalidChannel;
+ }
+
+ if (globals.Flash.enable_avrq_extra_ampls) {
+ return Set_avrq_res(0,0,0,channel,value);
+ }
+
+ /* duty cycle check */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].load_type=value;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (globals.ChannelState[channel].load_type!=value) {
+ globals.Changes.update_load=YES;
+ }
+
+ globals.ChannelState[channel].load_type=value;
+ Set_Update_Chans();
+
+ if (globals.Changes.update_load) {
+ /* change of load may require change in amplitude controls */
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude,0);
+ }
+
+ return OK;
+}
+
+
+int Set_EA(int channel,int mode)
+{
+ long amplify_mask, ea_mask;
+ char set_DAC_to_zero;
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_amplitude) {
+ return InvalidChannel;
+ }
+
+ if (!(globals.Flash.ea_enabled[channel]) && (mode==amp_mode_ea) ) {
+ return SyntaxError;
+ }
+ if (!(globals.Flash.ext_amplify_enabled[channel]) && (mode==amp_mode_amplify) ) {
+ return SyntaxError;
+ }
+
+ set_DAC_to_zero=YES;
+ if (mode==amp_mode_amplify) {
+ set_DAC_to_zero=NO;
+ }
+
+ /* set to max amplitude range when switching from normal to EA or Ext Amplify */
+ if ( (globals.ChannelState[channel].amp_mode==amp_mode_normal) && (mode!=amp_mode_normal) ) {
+ if (globals.ChannelState[channel].amplitude<0.0)
+ Set_Amplitude(0,0,0,0,0,set_DAC_to_zero,channel,
+ globals.ChannelState[channel].amplitude=globals.Flash.min_ampl[channel],0); /* most negative */
+ else
+ Set_Amplitude(0,0,0,0,0,set_DAC_to_zero,channel,
+ globals.ChannelState[channel].amplitude=globals.Flash.max_ampl[channel],0); /* most positive */
+ }
+
+
+ /* protect when switching from EA or Ext Amplify back to normal */
+ if ( (globals.ChannelState[channel].amp_mode!=amp_mode_normal) && (mode==amp_mode_normal) ) {
+ if (globals.ChannelState[channel].amplitude<0.0) {
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude=-smallest_allowed_number,0);
+ } else {
+ Set_Amplitude(0,0,0,0,0,0,channel,globals.ChannelState[channel].amplitude=smallest_allowed_number,0);
+ }
+ }
+
+
+ if (globals.Flash.ea_enabled[channel]) {
+ int ea_reg;
+
+ if (!channel) {
+ ea_mask = 0x10000;
+ ea_reg = 3;
+ } else {
+ ea_mask = ((long) 1) << (globals.Flash.ea_xtra_rly[channel]+14);
+ ea_reg = 2;
+ }
+
+ if (mode==amp_mode_ea) {
+ globals.Registers.shift_reg_out[ea_reg] |= ea_mask;
+ } else {
+ globals.Registers.shift_reg_out[ea_reg] &= ((long)(0xfffff - ea_mask));
+ }
+ }
+
+
+ if (globals.Flash.ext_amplify_enabled[channel]) {
+ amplify_mask = ((long) 1) << (globals.Flash.ext_amplify_xtra_rly[channel]+14);
+
+ if (mode==amp_mode_amplify) {
+ globals.Registers.shift_reg_out[2] |= amplify_mask;
+ } else {
+ globals.Registers.shift_reg_out[2] &= ((long)(0xfffff - amplify_mask));
+ }
+ }
+
+
+ if (globals.ChannelState[channel].amp_mode!=mode) {
+ globals.Changes.update_amp=YES;
+ }
+
+ globals.ChannelState[channel].amp_mode=mode;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_AdvDel(int channel,int setting)
+{
+ if (setting==to_Advance) {
+ globals.Registers.shift_reg_out[0] |= 64L; /* turn advance on */
+ } else {
+ globals.Registers.shift_reg_out[0] &= 255L-64L; /* turn delay on */
+ }
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Pwmode(int channel,int mode)
+{
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_pw) {
+ return InvalidChannel;
+ }
+
+ if (!(globals.Flash.ab_mode_allowed[channel]) && (mode==pw_in_out)) {
+ return SyntaxError;
+ }
+
+ if ((mode==pw_in_out) && (globals.ChannelState[channel].trigger_source!=source_external)) {
+ return AB_Mode_Error;
+ }
+
+ if (globals.ChannelState[channel].ab_mode!=mode) {
+ globals.Changes.update_pw=YES;
+ }
+
+ globals.ChannelState[channel].ab_mode=mode;
+
+ Set_Mux(0);
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_Update_Chans(void)
+{
+ int num_of_chan;
+
+ num_of_chan=globals.Flash.channels;
+ if (num_of_chan==0) {
+ num_of_chan=1;
+ }
+
+ if (num_of_chan>1) {
+ int i;
+ if (!globals.Flash.ChanKey_frequency) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].frequency=globals.ChannelState[0].frequency;
+ }
+ if (!globals.Flash.ChanKey_delay) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].delay=globals.ChannelState[0].delay;
+ }
+ if (!globals.Flash.ChanKey_pw) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].pw=globals.ChannelState[0].pw;
+ }
+ if (!globals.Flash.ChanKey_amplitude) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].amplitude=globals.ChannelState[0].amplitude;
+ }
+ if (!globals.Flash.ChanKey_offset) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].offset=globals.ChannelState[0].offset;
+ }
+
+ if (!globals.Flash.ChanKey_Curr_Mon_value) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].Curr_Mon_value=globals.ChannelState[0].Curr_Mon_value;
+ }
+ if (!globals.Flash.ChanKey_Curr_Mon_offset) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].Curr_Mon_offset=globals.ChannelState[0].Curr_Mon_offset;
+ }
+
+ if (!globals.Flash.ChanKey_zout) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].zout=globals.ChannelState[0].zout;
+ }
+ if (!globals.Flash.ChanKey_hold_setting) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].hold_setting=globals.ChannelState[0].hold_setting;
+ }
+ if (!globals.Flash.ChanKey_double_pulse) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].double_pulse=globals.ChannelState[0].double_pulse;
+ }
+ if (!globals.Flash.ChanKey_ab_mode) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].ab_mode=globals.ChannelState[0].ab_mode;
+ }
+ if (!globals.Flash.ChanKey_func_mode) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].func_mode=globals.ChannelState[0].func_mode;
+ }
+ if (!globals.Flash.ChanKey_polarity) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].polarity=globals.ChannelState[0].polarity;
+ }
+ if (!globals.Flash.ChanKey_output_state) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].output_state=globals.ChannelState[0].output_state;
+ }
+ if (!globals.Flash.ChanKey_gate_type) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].gate_type=globals.ChannelState[0].gate_type;
+ }
+ if (!globals.Flash.ChanKey_trigger_source) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].trigger_source=globals.ChannelState[0].trigger_source;
+ }
+ if (!globals.Flash.ChanKey_amp_mode) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].amp_mode=globals.ChannelState[0].amp_mode;
+ }
+ if (!globals.Flash.ChanKey_gate_level) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].gate_level=globals.ChannelState[0].gate_level;
+ }
+ if (!globals.Flash.ChanKey_load_type) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].load_type=globals.ChannelState[0].load_type;
+ }
+ if (!globals.Flash.ChanKey_test_delay_mode) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].test_delay_mode=globals.ChannelState[0].test_delay_mode;
+ }
+ if (!globals.Flash.ChanKey_os_mode) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].os_mode=globals.ChannelState[0].os_mode;
+ }
+ if (!globals.Flash.ChanKey_Burst_Count) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].burst_count=globals.ChannelState[0].burst_count;
+ }
+ if (!globals.Flash.ChanKey_Burst_Time) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].burst_time=globals.ChannelState[0].burst_time;
+ }
+ if (!globals.Flash.ChanKey_rise_time) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].rise_time=globals.ChannelState[0].rise_time;
+ }
+ if (!globals.Flash.ChanKey_slew) for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].slew=globals.ChannelState[0].slew;
+ }
+
+ for (i=1; i<num_of_chan; ++i) {
+ globals.ChannelState[i].vcc1=globals.ChannelState[0].vcc1;
+ globals.ChannelState[i].vcc2=globals.ChannelState[0].vcc2;
+ globals.ChannelState[i].vlogic=globals.ChannelState[0].vlogic;
+ }
+
+ }
+
+ return OK;
+}
+
+
+int Set_Amp_Calib(int channel,float meas_ampl)
+{
+ float change_ratio;
+ int i,status;
+ int point_found,relay_range,UseNegData,entry,word_out,actual_pol;
+ int eprom_loc;
+
+ /* use for all channels */
+
+ /* get current range and polarity settings */
+ Set_VI_Control(pwl_ampl_values,channel,globals.ChannelState[channel].amplitude,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol);
+
+ if (fabs(globals.ChannelState[channel].amplitude)<globals.Flash.ampl_zero_equiv[channel]) {
+ return NeedNonZeroAmpl;
+ }
+
+ change_ratio = meas_ampl/globals.ChannelState[channel].amplitude;
+
+ if (change_ratio>1.3 || change_ratio < 0.7) {
+ return CalibrationPercentError;
+ }
+
+ for (i=0; i<10; ++i)
+ globals.Flash.ampl_pwl_amp[channel][relay_range][UseNegData][i]=
+ globals.Flash.ampl_pwl_amp[channel][relay_range][UseNegData][i]*change_ratio;
+
+
+ /* see if new data prevents min/max from being obtained */
+ status=Check_MinMax_Cal(channel,pwl_ampl_values);
+
+ if (status) {
+ /* revert to original calibration */
+ for (i=0; i<10; ++i)
+ globals.Flash.ampl_pwl_amp[channel][relay_range][UseNegData][i]=
+ globals.Flash.ampl_pwl_amp[channel][relay_range][UseNegData][i]/change_ratio;
+ }
+
+ eprom_loc = (char *) &(globals.Flash.ampl_pwl_amp) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.ampl_pwl_amp));
+
+ return status;
+}
+
+
+int Set_Mon_Calib(int channel,float meas_ampl)
+{
+ float change_ratio;
+ int point_found,relay_range,UseNegData,entry,word_out,actual_pol,eprom_loc;
+
+ /* use for all channels */
+
+ /* get current range and polarity settings */
+ Set_VI_Control(pwl_ampl_values,channel,globals.ChannelState[channel].amplitude,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol);
+
+ if (fabs(globals.ChannelState[channel].Curr_Mon_value)< (5.0 * globals.Flash.monitor_step[channel])) {
+ return NeedNonZeroAmpl;
+ }
+
+ if (globals.Flash.sep_posneg_mon_ratio[channel] && globals.ChannelState[channel].amplitude<0.0) {
+ UseNegData=1;
+ } else {
+ UseNegData=0;
+ }
+
+ change_ratio = meas_ampl/globals.ChannelState[channel].Curr_Mon_value;
+
+ if (change_ratio>1.3 || change_ratio < 0.7) {
+ return CalibrationPercentError;
+ }
+
+ globals.Flash.mon_vi_ratio[channel][relay_range][UseNegData]=globals.Flash.mon_vi_ratio[channel][relay_range][UseNegData]/change_ratio;
+
+ eprom_loc = (char *) &(globals.Flash.mon_vi_ratio) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.mon_vi_ratio));
+
+ return OK;
+}
+
+
+int Set_Logic_Level(int channel,int mode)
+{
+ /* first channel uses dedicated Zout line */
+ if (channel==0) {
+ if (mode==logic_ecl) {
+ globals.Registers.shift_reg_out[3] |= (long)0x04000; /* power zout relay */
+ } else {
+ globals.Registers.shift_reg_out[3] &= (long)0xfbfff; /* de-power zout relay */
+ }
+ }
+
+ /* second channel uses xtra-rly3 */
+ if (channel==1) {
+ if (mode==logic_ecl) {
+ globals.Registers.shift_reg_out[2] |= (long)0x20000; /* power zout relay */
+ } else {
+ globals.Registers.shift_reg_out[2] &= (long)0xdffff; /* de-power zout relay */
+ }
+ }
+
+
+ if (globals.ChannelState[channel].logic_level!=mode) {
+ globals.Changes.update_logic_level=YES;
+ }
+
+ globals.ChannelState[channel].logic_level=mode;
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_OS_Calib(int channel,float meas_ampl)
+{
+ float change_ratio;
+ int i,status,eprom_loc;
+
+ if (fabs(globals.ChannelState[channel].offset)<globals.Flash.ampl_zero_equiv[channel]) {
+ return NeedNonZeroAmpl;
+ }
+
+ change_ratio = meas_ampl/globals.ChannelState[channel].offset;
+
+ if (change_ratio>1.3 || change_ratio < 0.7) {
+ return CalibrationPercentError;
+ }
+
+ for (i=0; i<10; ++i) {
+ globals.Flash.os_pwl_amp[channel][0][0][i]=globals.Flash.os_pwl_amp[channel][0][0][i]*change_ratio;
+ }
+
+
+ /* see if new data prevents min/max from being obtained */
+ status=Check_MinMax_Cal(channel,pwl_os_values);
+
+ if (status) {
+ /* revert to original calibration */
+ for (i=0; i<10; ++i) {
+ globals.Flash.os_pwl_amp[channel][0][0][i]=globals.Flash.os_pwl_amp[channel][0][0][i]/change_ratio;
+ }
+ }
+
+ eprom_loc = (char *) &(globals.Flash.os_pwl_amp) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.os_pwl_amp));
+
+ return status;
+}
+
+
+float Get_PW_shift(int channel)
+{
+ int UseNegData;
+
+ UseNegData = 0;
+ if (globals.ChannelState[channel].amplitude < 0.0) {
+ UseNegData = 1;
+ }
+
+ return globals.Flash.pulse_width_pol_tweak[channel][UseNegData];
+}
+
+
+int Set_PW_shift(int channel,float new_shift)
+{
+ float orig_shift;
+ int UseNegData, status, eprom_loc;
+
+ UseNegData = 0;
+ if (globals.ChannelState[channel].amplitude < 0.0) {
+ UseNegData = 1;
+ }
+
+ orig_shift = globals.Flash.pulse_width_pol_tweak[channel][UseNegData];
+ globals.Flash.pulse_width_pol_tweak[channel][UseNegData] = new_shift;
+
+ status=Check_MinMax_Cal(channel,pwl_pw_values);
+
+ if (status) {
+ globals.Flash.pulse_width_pol_tweak[channel][UseNegData] = orig_shift;
+ return status;
+ }
+
+ eprom_loc = (char *) &(globals.Flash.pulse_width_pol_tweak[channel][UseNegData]) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.pulse_width_pol_tweak[channel][UseNegData]));
+
+ return Set_Pw(0,0,0,channel,globals.ChannelState[channel].pw,0);
+}
+
+
+int Set_Route(int channel, int module, int mode)
+{
+ int error_num;
+ int word_out;
+
+ if (channel && !globals.Flash.ChanKey_route) {
+ return InvalidChannel;
+ }
+
+ if (!globals.Flash.routing_required[channel]) {
+ return Unrecognized;
+ }
+
+ if (module >= globals.Flash.routing_required[channel]) {
+ return IllegalParameter;
+ }
+
+ if ((mode < 1) || (mode > globals.Flash.routing_max_pins[channel])) {
+ return OutOfRange;
+ }
+
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+
+ if (globals.Flash.routing_max_pins[channel] > 2) {
+ if (module == ROUTE_PRIMARY) {
+ TestState[channel].route_primary=mode;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (mode!=globals.ChannelState[channel].route_primary) {
+ globals.Changes.update_routes=YES;
+ globals.ChannelState[channel].route_primary=mode;
+ }
+ }
+
+ if (module == ROUTE_SECONDARY) {
+ TestState[channel].route_secondary=mode;
+ if ((error_num=Error_check(TestState))) {
+ return error_num;
+ }
+
+ if (mode!=globals.ChannelState[channel].route_secondary) {
+ globals.Changes.update_routes=YES;
+ globals.ChannelState[channel].route_secondary=mode;
+ }
+ }
+ word_out = (globals.ChannelState[channel].route_primary-1) |
+ ((globals.ChannelState[channel].route_secondary-1) << 4);
+ I2C_Write(PCF8574+Second_PW_Port,word_out);
+ } else {
+ /* AVD-D2-B */
+ if (mode==2) {
+ globals.Registers.shift_reg_out[2] |= (long)0x08000; /* power zout relay */
+ } else {
+ globals.Registers.shift_reg_out[2] &= (long)0xf7fff; /* de-power zout relay */
+ }
+ globals.ChannelState[channel].route_primary=mode;
+ }
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_EO(int channel,int mode)
+{
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_offset) {
+ return InvalidChannel;
+ }
+
+ if (!globals.Flash.eo_enabled[channel]) {
+ return SyntaxError;
+ }
+
+ if (globals.ChannelState[channel].os_mode != mode) {
+ Set_Offset(0,0,0,0,channel,0.0);
+ }
+
+ if (mode) {
+ globals.Registers.shift_reg_out[2] |= (long)0x40000;
+ } else {
+ globals.Registers.shift_reg_out[2] &= ((long)(0xfffff - 0x40000));
+ }
+
+ if (globals.ChannelState[channel].os_mode!=mode) {
+ globals.Changes.update_os=YES;
+ }
+
+ globals.ChannelState[channel].os_mode=mode;
+ Set_Update_Chans();
+ Main_update_shift_registers();
+
+ return OK;
+}
+
+
+int Set_Dly_Shr_Nom(int channel,int calibration_point_number)
+{
+ float temp1, temp2, ampl;
+
+ Main_Rst();
+ Main_update_shift_registers();
+
+ Set_frequency(0,0,0,globals.Flash.ChanKey_frequency?channel:0,5.0e0);
+
+ if (globals.Flash.max_ampl[channel] > 0.0) {
+ ampl = globals.Flash.max_ampl[channel];
+ } else {
+ ampl = globals.Flash.min_ampl[channel];
+ }
+ Set_Amplitude(0,0,0,0,0,0,channel,ampl,0);
+
+
+ /* Set delay constants to zero, temporarily, for nulling purposes. */
+ /* Restore the constants after the delay is set, so that the unit */
+ /* will not suffer from an interrupted calibration. */
+
+ temp1=globals.Flash.propagation_delay[channel];
+ temp2=globals.Flash.delay_shrink[channel];
+ globals.Flash.propagation_delay[channel]=0.0;
+ globals.Flash.delay_shrink[channel]=0.0;
+
+ if (calibration_point_number==1) {
+ Set_Delay(0,0,0,channel,75e-9);
+ } else {
+ Set_Delay(0,0,0,channel,-75e-9);
+ }
+
+ /* user must set output on, when ready */
+
+ globals.Flash.propagation_delay[channel]=temp1;
+ globals.Flash.delay_shrink[channel]=temp2;
+
+ Main_update_shift_registers();
+
+ Menu_Update_Display();
+
+ return OK;
+}
+
+
+int Set_Dly_Shr_Cal(int channel,int calibration_point_number,float cal_point)
+{
+ int eprom_loc;
+ float delay1,delay2;
+
+ delay1=globals.Flash.propagation_delay[channel]-globals.Flash.delay_shrink[channel]+75e-9;
+ delay2=globals.Flash.propagation_delay[channel]+globals.Flash.delay_shrink[channel]-75e-9;
+
+ if (calibration_point_number==1) {
+ delay1=cal_point;
+ } else {
+ delay2=cal_point;
+ }
+
+ if (delay1>50e-6 || delay2>50e-6) {
+ return CalibrationPercentError;
+ }
+
+ globals.Flash.propagation_delay[channel]=(delay1+delay2)/2;
+ globals.Flash.delay_shrink[channel]=( (150e-9)-delay1+delay2)/2;
+
+ eprom_loc = (char *) &(globals.Flash.propagation_delay) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.propagation_delay));
+
+ eprom_loc = (char *) &(globals.Flash.delay_shrink) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.delay_shrink));
+
+ return OK;
+}
+
+
+
+int Set_Cal_Nom(int channel,int calibration_point_number,int parameter, float *nom_val)
+{
+ int nominal_wordout,polarity,range,entry,status,num_in_range,num_of_ranges;
+ float nominal_val,other_setting,temp1,temp2;
+ int reset_state;
+ int disable_errors;
+ int true_channel;
+
+ true_channel=channel;
+
+ Get_VI_Rng_Info(parameter,channel,calibration_point_number,&range,&polarity,&entry,&num_in_range,&num_of_ranges);
+ status=reset_state=disable_errors=0;
+
+ switch (parameter) {
+ case (pwl_ampl_values):
+ nominal_val=globals.Flash.ampl_pwl_amp[channel][range][polarity][entry];
+ if (polarity) {
+ nominal_val=-nominal_val;
+ }
+ nominal_wordout=globals.Flash.ampl_pwl_Vc_norm4095[channel][range][polarity][entry];
+ if (Set_Amplitude(0,0,0,0,0,0,channel,globals.Flash.min_ampl[channel],0) || Set_Amplitude(0,0,0,0,0,0,channel,globals.Flash.max_ampl[channel],0)) {
+ /* confirm that timing settings can support min/max ampl settings */
+ return CalibrationTimingProblem;
+ }
+ /* auto-set output impedance, as required */
+ if (globals.Flash.switchable_zout[channel]) {
+ /* if the cal point is in the top used range, then set Zout to min */
+ if (range==num_of_ranges) {
+ Set_zout(channel,globals.Flash.zout_min[channel],1);
+ } else {
+ Set_zout(channel,globals.Flash.zout_max[channel],1);
+ }
+ }
+ break;
+ case (pwl_os_values):
+ nominal_val=globals.Flash.os_pwl_amp[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.os_pwl_Vc_norm4095[channel][range][polarity][entry];
+ break;
+ case pwl_pw_values:
+ nominal_val=globals.Flash.pw_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.pw_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=disable_errors=1;
+ break;
+ case pwl_delay_values:
+ nominal_val=globals.Flash.delay_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.delay_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=disable_errors=1;
+ break;
+ case pwl_period_values:
+ nominal_val=globals.Flash.period_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.period_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=disable_errors=1;
+ break;
+ case pwl_burst_values:
+ nominal_val=globals.Flash.burst_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.burst_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=disable_errors=1;
+ break;
+ case pwl_rise_time_values:
+ nominal_val=globals.Flash.rise_time_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.rise_time_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=disable_errors=1;
+ break;
+ case pwl_slew_values:
+ nominal_val=globals.Flash.slew_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.slew_pwl_Vc_norm4095[channel][range][polarity][entry];
+ break;
+ case pwl_vcc1_values:
+ nominal_val=globals.Flash.vcc1_pwl_amp[0][0][0][entry];
+ nominal_wordout=globals.Flash.vcc1_pwl_Vc_norm4095[0][0][0][entry];
+ true_channel=0;
+ break;
+ case pwl_vcc2_values:
+ nominal_val=globals.Flash.vcc2_pwl_amp[0][0][0][entry];
+ nominal_wordout=globals.Flash.vcc2_pwl_Vc_norm4095[0][0][0][entry];
+ true_channel=0;
+ break;
+ case pwl_load_type_values:
+ nominal_val=globals.Flash.load_type_pwl_time[channel][range][polarity][entry];
+ nominal_wordout=globals.Flash.load_type_pwl_Vc_norm4095[channel][range][polarity][entry];
+ reset_state=0;
+ disable_errors=1;
+ break;
+ }
+
+ /* just get nominal value, don't activate */
+ if (nom_val) {
+ *nom_val = nominal_val;
+ return OK;
+ }
+
+ /* For timing parameters, turn off output and error-checking, and change prf/pw */
+ /* For ampl/os parameters, use existing timing and output state, and use error-checking */
+
+ if (reset_state) {
+ Main_Rst();
+ Set_Output_State(true_channel,output_off);
+ Main_update_shift_registers();
+ bus_setpin(PW_ENABLE, 1); /* enable PW circuit (but output relay still off) */
+ }
+
+ if (disable_errors) {
+ globals.Flash.fully_programmed=Being_Programmed; /* disable error-checking */
+ Ctrl_PRF_Limiter(0); /* re-enables after *rst */
+ }
+
+ globals.Flags.extended_ampl_min_max=YES;
+ globals.ChannelState[true_channel].test_delay_mode=NO;
+
+ switch (parameter) {
+ case (pwl_ampl_values):
+ status=Set_Amplitude(0,polarity,1,nominal_wordout,range,0,channel,nominal_val,0);
+ break;
+ case (pwl_os_values):
+ status=Set_Offset(0,1,nominal_wordout,range,channel,nominal_val);
+ break;
+ case pwl_pw_values:
+ other_setting=0.08/nominal_val;
+ if (other_setting > 500e3) {
+ other_setting=500e3;
+ }
+
+ Set_Pol(channel,pol_norm);
+
+ status=Set_frequency(0,0,0,globals.Flash.ChanKey_frequency?channel:0,other_setting);
+
+ if (!status) {
+ status=Set_Pw(0,nominal_wordout,range,channel,nominal_val,0);
+ }
+ break;
+ case pwl_delay_values:
+ other_setting=0.08/nominal_val;
+ if (other_setting > 500e3) {
+ other_setting=500e3;
+ }
+
+ /* set delay constants to zero, temporarily */
+ temp1=globals.Flash.propagation_delay[channel];
+ temp2=globals.Flash.delay_shrink[channel];
+ globals.Flash.propagation_delay[channel]=0.0;
+ globals.Flash.delay_shrink[channel]=0.0;
+
+ globals.ChannelState[channel].test_delay_mode=YES;
+
+ status=Set_frequency(0,0,0,globals.Flash.ChanKey_frequency?channel:0,other_setting);
+ if (!status) {
+ status=Set_Delay(0,nominal_wordout,range,channel,nominal_val);
+ }
+
+ globals.Flash.propagation_delay[channel]=temp1;
+ globals.Flash.delay_shrink[channel]=temp2;
+
+ break;
+ case pwl_period_values:
+ other_setting=0.4*nominal_val;
+ if (other_setting>1.0) {
+ other_setting=1.0; /* reduce pulse width if required */
+ }
+
+ status=Set_frequency(0,nominal_wordout,range,channel,1.0/nominal_val);
+
+ if (!status) {
+ status=Set_Pw(0,0,0,globals.Flash.ChanKey_pw?channel:0,other_setting,0);
+ }
+ break;
+
+ case pwl_burst_values:
+ other_setting=20.0*nominal_val;
+
+ if (other_setting>10.0) {
+ other_setting=10.0; /* reduce pulse width if required */
+ }
+ status=Set_frequency(0,0,0,channel,1.0/other_setting);
+ Main_update_shift_registers();
+
+ if (!status) {
+ status=Set_Pw(0,0,0,globals.Flash.ChanKey_pw?channel:0,nominal_val,0);
+ }
+ if (!status) {
+ status=Set_Burst_Count(channel,4,nominal_val);
+ }
+ if (!status) {
+ status=Set_Burst_Time(0,nominal_wordout,range,channel,nominal_val);
+ }
+
+ break;
+
+ case pwl_rise_time_values:
+ other_setting=10; /* reduce test frequency if required */
+ status=Set_frequency(0,0,0,globals.Flash.ChanKey_frequency?channel:0,other_setting);
+ if (!status) {
+ status=Set_rise_time(0,nominal_wordout,range,channel,nominal_val);
+ }
+ break;
+
+ case pwl_slew_values:
+ other_setting=10; /* reduce test frequency if required */
+ status=Set_frequency(0,0,0,globals.Flash.ChanKey_frequency?channel:0,other_setting);
+ if (!status) {
+ status=Set_slew(0,nominal_wordout,range,channel,nominal_val);
+ }
+ break;
+
+ case pwl_load_type_values:
+ Set_avrq_res(0,nominal_wordout,range,channel,nominal_val);
+ break;
+
+ case pwl_vcc1_values:
+ status=Set_Amplitude(0,polarity,1,nominal_wordout,range,0,channel,nominal_val,0);
+ break;
+
+ case pwl_vcc2_values:
+ status=Set_Amplitude(0,polarity,1,nominal_wordout,range,0,channel,nominal_val,0);
+ break;
+
+ }
+
+ /* enables or disables delay diagnostic mode */
+ Set_Mux(true_channel);
+
+ Main_update_shift_registers();
+ Menu_Update_Display();
+
+ /* re-enable error-checking */
+ globals.Flash.fully_programmed=All_Programmed;
+
+ /* rise time requires more values to be set before it can be measured */
+ if (parameter != pwl_rise_time_values) {
+ globals.Flags.extended_ampl_min_max=NO;
+ }
+
+ return status;
+}
+
+
+int Set_VI_Cal_Pnt(int parameter,int channel,int calibration_point_number,float cal_point)
+{
+ int polarity,range,entry,status,num_in_range,num_of_ranges,eprom_loc;
+ float nom_ampl;
+ int index;
+ int max_points,max_polarity,max_ranges;
+ float *pwl_amp;
+ int true_channel;
+
+ true_channel=channel;
+
+ Get_VI_Rng_Info(parameter,channel,calibration_point_number,&range,&polarity,&entry,&num_in_range,&num_of_ranges);
+
+ max_points=points_in_range;
+ switch (parameter) {
+ case (pwl_ampl_values):
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl_amp=&globals.Flash.ampl_pwl_amp[0][0][0][0];
+ break;
+ case (pwl_os_values):
+ max_polarity=os_polarities;
+ max_ranges=os_ranges;
+ pwl_amp=&globals.Flash.os_pwl_amp[0][0][0][0];
+ break;
+ case pwl_pw_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_amp=&globals.Flash.pw_pwl_time[0][0][0][0];
+ break;
+ case pwl_delay_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_amp=&globals.Flash.delay_pwl_time[0][0][0][0];
+ break;
+ case pwl_period_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_amp=&globals.Flash.period_pwl_time[0][0][0][0];
+ break;
+ case pwl_burst_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_amp=&globals.Flash.burst_pwl_time[0][0][0][0];
+ break;
+ case pwl_rise_time_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl_amp=&globals.Flash.rise_time_pwl_time[0][0][0][0];
+ break;
+ case pwl_slew_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_amp=&globals.Flash.slew_pwl_time[0][0][0][0];
+ break;
+ case pwl_vcc1_values:
+ max_polarity=1;
+ max_ranges=1;
+ true_channel=0;
+ pwl_amp=&globals.Flash.vcc1_pwl_amp[0][0][0][0];
+ break;
+ case pwl_vcc2_values:
+ max_polarity=1;
+ max_ranges=1;
+ true_channel=0;
+ pwl_amp=&globals.Flash.vcc2_pwl_amp[0][0][0][0];
+ break;
+ case pwl_load_type_values:
+ max_polarity=load_type_polarities;
+ max_ranges=load_type_ranges;
+ pwl_amp=&globals.Flash.load_type_pwl_time[0][0][0][0];
+ break;
+ }
+ index=true_channel*max_ranges*max_polarity*max_points
+ +range*max_polarity*max_points
+ +polarity*max_points
+ +entry;
+
+ nom_ampl=pwl_amp[index];
+
+ switch (parameter) {
+ case (pwl_ampl_values):
+ if (globals.ChannelState[channel].amplitude<0.0) {
+ nom_ampl=-nom_ampl;
+ }
+ if ( (cal_point>0.0 && nom_ampl<0.0) || (cal_point<0.0 && nom_ampl>0.0)) {
+ return CalibrationPolarityError;
+ }
+ if (fabs(nom_ampl) < smallest_allowed_number) {
+ return CalibrationZeroError;
+ }
+ if (fabs( (cal_point-nom_ampl)/nom_ampl) >0.3) {
+ return CalibrationPercentError;
+ }
+ break;
+
+ case (pwl_os_values):
+ /* check for divide-by-zero error */
+ if (fabs(nom_ampl) > smallest_allowed_number) {
+ /* exclude relative changes of 30% or more */
+ if (fabs( (cal_point-nom_ampl)/nom_ampl) > 0.3) {
+ return CalibrationPercentError;
+ }
+ }
+ /* exclude changes greater than 20% of entire range */
+ if (fabs(cal_point-nom_ampl) > (0.2*fabs(globals.Flash.max_offset[channel]-globals.Flash.min_offset[channel]))) {
+ return CalibrationPercentError;
+ }
+ break;
+
+ case pwl_pw_values:
+ case pwl_period_values:
+ case pwl_burst_values:
+ case pwl_rise_time_values:
+ case pwl_slew_values:
+ case pwl_load_type_values:
+ /* exclude relative changes of 45% or more unless < 15 ns */
+ if ( (fabs(cal_point-nom_ampl)/nom_ampl > 0.45) && (fabs(cal_point-nom_ampl)>15e-9)) {
+ return CalibrationPercentError;
+ }
+ if (cal_point<0.0) {
+ return Negative_Not_Allowed;
+ }
+ break;
+
+ case pwl_delay_values:
+ /* exclude relative changes of 45% or more unless < 15 ns */
+ if ( (fabs(cal_point-nom_ampl)/nom_ampl > 0.45) && (fabs(cal_point-nom_ampl)>15e-9)) {
+ return CalibrationPercentError;
+ }
+ break;
+
+ case pwl_vcc1_values:
+ case pwl_vcc2_values:
+ if (fabs(nom_ampl) > smallest_allowed_number) {
+ /* exclude relative changes of 30% or more */
+ if (fabs( (cal_point-nom_ampl)/nom_ampl) > 0.3) {
+ return CalibrationPercentError;
+ }
+ }
+ break;
+ }
+
+
+
+ status=OK;
+ globals.Flags.extended_ampl_min_max=YES;
+
+ if (parameter==pwl_ampl_values) {
+ cal_point=fabs(cal_point);
+ }
+
+ *(float *)(&pwl_amp[index])=cal_point;
+
+ /* see if new point prevents min/max from being obtained */
+ status=Check_MinMax_Cal(channel,parameter);
+
+ if (status) {
+ /* revert to original value if required */
+ *(float *)(&pwl_amp[index])=nom_ampl;
+ }
+
+ Set_Cal_Nom(channel,calibration_point_number,parameter,NULL);
+
+ Main_update_shift_registers();
+ Menu_Update_Display();
+
+ eprom_loc = (char *) (&pwl_amp[index]) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(nom_ampl));
+
+ globals.Flags.extended_ampl_min_max=NO;
+ return status;
+}
+
+
+int Set_VI_Del_Cal(int parameter,int channel,int calibration_point_number)
+{
+ int polarity,range,entry,status,i,num_in_range,num_of_ranges;
+ float temp1[10];
+ int temp2[10];
+ int index;
+ int max_points,max_polarity,max_ranges;
+ int *pointer_int1;
+ float *pointer_float1;
+ int eprom_loc,size_of_float1,size_of_int1;
+ int true_channel;
+
+ true_channel=channel;
+
+ max_points=points_in_range;
+
+ switch (parameter) {
+ case (pwl_ampl_values):
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pointer_int1=&globals.Flash.ampl_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.ampl_pwl_amp[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.ampl_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.ampl_pwl_amp);
+ break;
+ case (pwl_os_values):
+ max_polarity=os_polarities;
+ max_ranges=os_ranges;
+ pointer_int1=&globals.Flash.os_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.os_pwl_amp[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.os_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.os_pwl_amp);
+ break;
+ case pwl_pw_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_int1=&globals.Flash.pw_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.pw_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.pw_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.pw_pwl_time);
+ break;
+ case pwl_delay_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_int1=&globals.Flash.delay_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.delay_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.delay_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.delay_pwl_time);
+ break;
+ case pwl_period_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_int1=&globals.Flash.period_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.period_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.period_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.period_pwl_time);
+ break;
+ case pwl_burst_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_int1=&globals.Flash.burst_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.burst_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.burst_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.burst_pwl_time);
+ break;
+ case pwl_rise_time_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pointer_int1=&globals.Flash.rise_time_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.rise_time_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.rise_time_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.rise_time_pwl_time);
+ break;
+ case pwl_slew_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_int1=&globals.Flash.slew_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.slew_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.slew_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.slew_pwl_time);
+ break;
+ case pwl_vcc1_values:
+ max_polarity=1;
+ max_ranges=1;
+ pointer_int1=&globals.Flash.vcc1_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.vcc1_pwl_amp[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.vcc1_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.vcc1_pwl_amp);
+ true_channel=0;
+ break;
+ case pwl_vcc2_values:
+ max_polarity=1;
+ max_ranges=1;
+ pointer_int1=&globals.Flash.vcc2_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.vcc2_pwl_amp[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.vcc2_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.vcc2_pwl_amp);
+ true_channel=0;
+ break;
+ case pwl_load_type_values:
+ max_polarity=load_type_polarities;
+ max_ranges=load_type_ranges;
+ pointer_int1=&globals.Flash.load_type_pwl_Vc_norm4095[0][0][0][0];
+ pointer_float1=&globals.Flash.load_type_pwl_time[0][0][0][0];
+ size_of_int1=sizeof(globals.Flash.load_type_pwl_Vc_norm4095);
+ size_of_float1=sizeof(globals.Flash.load_type_pwl_time);
+ break;
+ }
+
+ Get_VI_Rng_Info(parameter,channel,calibration_point_number,&range,&polarity,&entry,&num_in_range,&num_of_ranges);
+
+ index=true_channel*max_ranges*max_polarity*max_points
+ +range*max_polarity*max_points
+ +polarity*max_points;
+
+
+ /* can not delete top or bottom of a range */
+ if ((entry==0) || (entry==(num_in_range-1))) {
+ return CalibrationRangeError;
+ }
+
+ /* backup calibration values */
+ for (i=0; i<max_points; i++) {
+ temp1[i]=pointer_float1[index+i];
+ temp2[i]=pointer_int1[index+i];
+ }
+
+ /* move the data, overwriting the deleted point */
+ for (i=entry; i<max_points-1; i++) {
+ *(float *)(&pointer_float1[index+i])=pointer_float1[index+i+1];
+ *(int *)(&pointer_int1[index+i])=pointer_int1[index+i+1];
+ }
+
+ *(float *)(&pointer_float1[index+points_in_range-1])=0.0;
+ *(int *)(&pointer_int1[index+points_in_range-1])=0;
+
+ /* see if new point prevents min/max from being obtained */
+ status=Check_MinMax_Cal(channel,parameter);
+
+ if (status) {
+ /* revert to original calibration */
+ for (i=0; i<max_points; i++) {
+ *(float *)(&pointer_float1[index+i])=temp1[i];
+ *(int *)(&pointer_int1[index+i])=temp2[i];
+ }
+ }
+
+ Set_Amplitude(0,0,0,0,0,0,channel,0.0,0);
+ Main_update_shift_registers();
+
+ Set_Offset(0,0,0,0,channel,0.0);
+ Main_update_shift_registers();
+
+ Menu_Update_Display();
+
+ eprom_loc = (char *) pointer_int1 - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,size_of_int1);
+
+ eprom_loc = (char *) pointer_float1 - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,size_of_float1);
+
+ return status;
+}
+
+
+int Set_VI_Control(int parameter,int channel,float new_ampl,int *point_found,int *relay_range,
+ int *UseNegData,int *entry,int *word_out,int *actual_pol)
+{
+ float use_ampl,tweaked_use_ampl,fraction;
+ int i;
+ float min_os_in_range,max_os_in_range;
+ float min_ampl_in_range,max_ampl_in_range;
+
+ int max_points,max_polarity,max_ranges;
+ float *pwl_amp;
+ int *pwl_vc;
+ int index,use_range;
+ int range_i,entry_i;
+ float inverse_word_out;
+ int timing_extrapolation_allowed;
+ int pw_polarity;
+
+ float pw_distort_val;
+ float ampl_for_distort_calc;
+
+
+ int top_range_only;
+ int starting_range;
+
+ int decreasing_values_allowed;
+ int reciprocal_relationship;
+
+ int true_channel;
+
+ true_channel=channel;
+
+ top_range_only=0;
+ starting_range=0;
+ max_points=points_in_range;
+ timing_extrapolation_allowed=NO;
+ reciprocal_relationship=NO;
+ decreasing_values_allowed=NO;
+ min_os_in_range=max_os_in_range=0.0;
+ min_ampl_in_range=max_ampl_in_range=0.0;
+
+
+ switch (parameter) {
+ case pwl_ampl_values:
+
+ if (globals.Flash.ampl_coupled_to_os[channel]) {
+ new_ampl+=globals.ChannelState[channel].offset; /* for 1011-style offset circuit */
+ }
+
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl_vc=&globals.Flash.ampl_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.ampl_pwl_amp[0][0][0][0];
+ if (new_ampl<0.0) {
+ *actual_pol=1;
+ *UseNegData=1;
+ } else {
+ *actual_pol=0;
+ *UseNegData=0;
+ }
+ if (globals.Flash.use_pos_ampl_data_only[channel] && new_ampl<0.0) {
+ *UseNegData=0;
+ }
+ use_ampl=fabs(new_ampl);
+
+ /* use top amplitude range in AV-1011 if Zout=2 */
+ top_range_only = globals.Flash.switchable_zout[channel]
+ && (globals.ChannelState[channel].zout==globals.Flash.zout_min[channel]);
+
+ /* if high_impedance_mode the relay range is automatically set to 3 (for 1011, 1015 only),
+ if such a range exists */
+
+ if ( globals.Flash.switchable_load[channel] &&
+ (globals.ChannelState[channel].load_type>globals.Flash.low_load_type[channel]) &&
+ globals.Flash.ampl_pwl_Vc_norm4095[channel][3][*actual_pol][1] > 0) {
+ starting_range=3;
+ top_range_only=0;
+ }
+
+ /* if 1011-OT offset is non-zero, the relay range is automatically set to 3 or 4 (for 1011, 1015 only) */
+
+ if (globals.Flash.ampl_coupled_to_os[channel]
+ && globals.Flash.switchable_zout[channel]
+ && (fabs(globals.ChannelState[channel].offset)>(globals.Flash.max_offset[channel]/max_v_dymanic_range))) {
+ starting_range=3;
+ }
+
+ /* for AVMP-4-B: lower ampl range used for first PW range only */
+ if (globals.Flash.use_high_ampl_ranges_for_high_pw_ranges[channel] &&
+ ((globals.Registers.shift_reg_out[3] & 0x7f) > 0)) {
+ top_range_only=1;
+ }
+
+ break;
+ case pwl_os_values:
+ decreasing_values_allowed=YES; /* allows Vc=0 to corresponds to most + OS, and Vc=10V to give most - OS */
+ max_polarity=os_polarities;
+ max_ranges=os_ranges;
+ pwl_vc=&globals.Flash.os_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.os_pwl_amp[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ break;
+ case pwl_pw_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_vc=&globals.Flash.pw_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.pw_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+
+ /* increase PW if required to compensate for series output diode turn-on time */
+ if ( (globals.Flash.fully_programmed != Being_Programmed)
+ && (globals.Flash.distort_Y[channel] != 0.0)
+ && (fabs(globals.ChannelState[channel].offset)<fabs(globals.Flash.distort_max_os[channel])) ) {
+
+ ampl_for_distort_calc = fabs(globals.ChannelState[channel].amplitude);
+
+ /* clamping distortion above a certain amplitude */
+ if (ampl_for_distort_calc > globals.Flash.distort_max_ampl[channel]) {
+ ampl_for_distort_calc = globals.Flash.distort_max_ampl[channel];
+ }
+
+ /* clamping distortion below "zero equiv" amplitude */
+ if (ampl_for_distort_calc < globals.Flash.ampl_zero_equiv[channel]) {
+ ampl_for_distort_calc = globals.Flash.ampl_zero_equiv[channel];
+ }
+
+ /* prohit values of Y that would cause divide-by-zero error */
+ if ( (-globals.Flash.distort_Y[channel]) > globals.Flash.ampl_zero_equiv[channel]) {
+ return PW_Distort_Error;
+ }
+
+ pw_distort_val=globals.Flash.distort_Z[channel] +
+ globals.Flash.distort_X[channel] / (ampl_for_distort_calc+globals.Flash.distort_Y[channel]);
+
+ /* calculate new actual PW */
+ use_ampl=use_ampl+pw_distort_val;
+ }
+
+ /* tweak depending on polarity */
+ if (globals.ChannelState[channel].amplitude<0.0) {
+ pw_polarity = 1;
+ use_ampl=use_ampl+globals.Flash.pulse_width_pol_tweak[channel][pw_polarity];
+ } else {
+ pw_polarity = 0;
+ use_ampl=use_ampl+globals.Flash.pulse_width_pol_tweak[channel][pw_polarity];
+ }
+
+ /* tweak depending on amplitude range (steps, not gradual like distort params */
+
+ if (fabs(globals.ChannelState[channel].amplitude) <= globals.Flash.pw_shift_below_this_ampl[channel]) {
+ use_ampl=use_ampl+globals.Flash.pw_shift_below_ampl_by[channel];
+ }
+
+ reciprocal_relationship=YES;
+ timing_extrapolation_allowed=YES;
+ break;
+ case pwl_delay_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_vc=&globals.Flash.delay_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.delay_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ reciprocal_relationship=YES;
+ timing_extrapolation_allowed=YES;
+ break;
+ case pwl_period_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_vc=&globals.Flash.period_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.period_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ timing_extrapolation_allowed=YES;
+ reciprocal_relationship=YES;
+ break;
+ case pwl_burst_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_vc=&globals.Flash.burst_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.burst_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ reciprocal_relationship=YES;
+ timing_extrapolation_allowed=YES;
+ break;
+ case pwl_rise_time_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl_vc=&globals.Flash.rise_time_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.rise_time_pwl_time[0][0][0][0];
+ if (globals.ChannelState[channel].amplitude<0.0) {
+ *actual_pol=*UseNegData=1;
+ } else {
+ *actual_pol=*UseNegData=0;
+ }
+ use_ampl=new_ampl;
+ reciprocal_relationship=NO;
+ timing_extrapolation_allowed=NO;
+ break;
+ case pwl_slew_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl_vc=&globals.Flash.slew_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.slew_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ reciprocal_relationship=NO;
+ timing_extrapolation_allowed=NO;
+ top_range_only=YES; /* higher drive voltage = lower ripple in slew */
+ break;
+ case pwl_vcc1_values:
+ max_polarity=1;
+ max_ranges=1;
+ pwl_vc=&globals.Flash.vcc1_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.vcc1_pwl_amp[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ true_channel=0;
+ break;
+ case pwl_vcc2_values:
+ max_polarity=1;
+ max_ranges=1;
+ pwl_vc=&globals.Flash.vcc2_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.vcc2_pwl_amp[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ true_channel=0;
+ break;
+ case pwl_load_type_values:
+ max_polarity=load_type_polarities;
+ max_ranges=load_type_ranges;
+ pwl_vc=&globals.Flash.load_type_pwl_Vc_norm4095[0][0][0][0];
+ pwl_amp=&globals.Flash.load_type_pwl_time[0][0][0][0];
+ *UseNegData=0;
+ use_ampl=new_ampl;
+ reciprocal_relationship=YES;
+ timing_extrapolation_allowed=YES;
+ break;
+ }
+
+
+ /* if top_range_only=false, the first match (i.e. in the lowest range) is used. */
+ /* if top_range_only=true, the last match (i.e. in the highest range) is used. */
+
+ *point_found=*relay_range=*entry=0;
+ *word_out=-1;
+
+ tweaked_use_ampl = use_ampl;
+
+ for (range_i=starting_range; (range_i<max_ranges) && (!*point_found || top_range_only); ++range_i) { /* use non-all-zero ranges */
+//printf ("range_i %d\r\n",range_i);
+ /* apply pw ampl/pol tweaks */
+ if (parameter == pwl_pw_values) {
+ tweaked_use_ampl = use_ampl + globals.Flash.pw_range_pol_tweaks[channel][range_i][pw_polarity];
+ }
+
+ for (entry_i=0; (entry_i<max_points-1) && (!*point_found || top_range_only); ++entry_i) {
+//printf ("entry_i %d\r\n",entry_i);
+
+ index=true_channel*max_ranges*max_polarity*max_points
+ +(range_i)*max_polarity*max_points
+ +(*UseNegData)*max_points
+ +(entry_i);
+
+ if ( (fabs(pwl_amp[index]-pwl_amp[index+1])>smallest_allowed_number)
+ &&
+ ( ((tweaked_use_ampl>=pwl_amp[index]) && (tweaked_use_ampl<=pwl_amp[index+1]))
+ ||
+ (decreasing_values_allowed && (tweaked_use_ampl<=pwl_amp[index]) && (tweaked_use_ampl>=pwl_amp[index+1])) /* for OS only */
+ )
+ ) {
+ *point_found=1;
+
+ if ((parameter==pwl_ampl_values) && globals.Flash.ampl_os_ranges_related[channel]) {
+ for (i=0; i<points_in_range; i++) {
+ if (max_os_in_range<globals.Flash.os_pwl_amp[channel][range_i][0][i]) {
+ max_os_in_range=globals.Flash.os_pwl_amp[channel][range_i][0][i];
+ }
+ if (min_os_in_range>globals.Flash.os_pwl_amp[channel][range_i][0][i]) {
+ min_os_in_range=globals.Flash.os_pwl_amp[channel][range_i][0][i];
+ }
+ }
+ if ((globals.ChannelState[channel].offset<min_os_in_range) || (globals.ChannelState[channel].offset>max_os_in_range)) {
+ *point_found=0; /* try higher range if can't satisfy os and ampl both in this range */
+ }
}
- Set_Load(i,globals.ChannelState[i].load_type);
- Set_Logic_Level(i,globals.ChannelState[i].logic_level);
- Set_rise_time(0,0,0,i,globals.ChannelState[i].rise_time);
- Set_slew(0,0,0,i,globals.ChannelState[i].slew);
- Set_current_limit(0,i,globals.ChannelState[i].soft_current_limit);
+ if ((parameter==pwl_os_values) && globals.Flash.ampl_os_ranges_related[channel]) {
+ for (i=0; i<points_in_range; i++) {
+ if (max_ampl_in_range<globals.Flash.ampl_pwl_amp[channel][range_i][*UseNegData][i]) {
+ max_ampl_in_range=globals.Flash.ampl_pwl_amp[channel][range_i][*UseNegData][i];
+ }
+ if (min_ampl_in_range>globals.Flash.ampl_pwl_amp[channel][range_i][*UseNegData][i]) {
+ min_ampl_in_range=globals.Flash.ampl_pwl_amp[channel][range_i][*UseNegData][i];
+ }
+ }
+ if ((fabs(globals.ChannelState[channel].amplitude)<min_ampl_in_range) || (fabs(globals.ChannelState[channel].amplitude)>max_ampl_in_range)) {
+ *point_found=0; /* try higher range if can't satisfy os and ampl both in this range */
+ }
+ }
+
+ fraction = (tweaked_use_ampl-pwl_amp[index]) / (pwl_amp[index] - pwl_amp[index+1]);
+ *relay_range=range_i;
+ *entry=entry_i;
+
+ /* check for linear voltage-controlled PW */
+ if ( (parameter==pwl_pw_values)
+ && globals.Flash.volt_ctrl_pw[channel]
+ && (pwl_vc[index] < pwl_vc[index+1])) {
+ reciprocal_relationship=NO;
+ }
- if (globals.Flash.max_burst_count[i]>1) {
- Set_Burst_Count(i,globals.ChannelState[i].burst_count,globals.ChannelState[i].burst_time);
+ if (reciprocal_relationship) {
+ inverse_word_out = fraction * (1.0/((float) pwl_vc[index]) - 1.0/((float) pwl_vc[index+1]));
+ inverse_word_out+=1/((float) pwl_vc[index]);
+ *word_out=(int) (1.0/inverse_word_out);
+ } else {
+ *word_out = (int) ( fraction * (float) (pwl_vc[index] - pwl_vc[index+1]) );
+ *word_out+=pwl_vc[index];
}
+ }
+ }
+ }
+
+ /* The amplitude/os settings must lie within the calibration points. */
+ /* However, the timing data is allowed to lie outside the upper end, */
+ /* because the reciprocal relationship allows an asymptotic extension to infinity, */
+ /* at the expense of lower resolution */
+
+ if (*word_out<0 && timing_extrapolation_allowed) {
+ *point_found=0;
+ use_range=-1;
+
+ tweaked_use_ampl = use_ampl;
- Set_Trig_Source(i,globals.ChannelState[i].trigger_source);
+ /* identify highest range that starts with a cal point less than the setting */
+ for (range_i=0; range_i<max_ranges; ++range_i) { /* use non-all-zero ranges */
+ if (parameter == pwl_pw_values) {
+ tweaked_use_ampl = use_ampl + globals.Flash.pw_range_pol_tweaks[channel][range_i][pw_polarity];
+ }
- Set_Amplitude(0,0,0,0,0,0,i,globals.ChannelState[i].amplitude,0);
- Set_Offset(0,0,0,0,i,globals.ChannelState[i].offset);
- Set_Output_State(i,globals.ChannelState[i].output_state);
+ index=true_channel*max_ranges*max_polarity*max_points
+ +(range_i)*max_polarity*max_points
+ +(*UseNegData)*max_points;
+ if (pwl_amp[index]>smallest_allowed_number && pwl_amp[index]<tweaked_use_ampl) {
+ use_range=range_i;
+ }
+ }
+
+ if (use_range<0) {
+ return HardwareError;
+ }
- Set_current_limit(0,i,globals.ChannelState[i].soft_current_limit);
+ for (entry_i=max_points-2; (entry_i>=0) && (!*point_found); --entry_i) {
+ index=true_channel*max_ranges*max_polarity*max_points
+ +(use_range)*max_polarity*max_points
+ +(*UseNegData)*max_points
+ +(entry_i);
- Set_avrq_ampl(0,0,0,2,globals.ChannelState[i].vcc1);
- Set_avrq_ampl(0,0,0,3,globals.ChannelState[i].vcc2);
- Set_avrq_ampl(0,0,0,4,globals.ChannelState[i].vlogic);
- */
- globals.do_check_settings=YES; /* check for conflicting settings */
+ /* find the last two non-zero entries, and extrapolate from them */
+ if ( (fabs(pwl_amp[index])>smallest_allowed_number)
+ && (fabs(pwl_amp[index+1])>smallest_allowed_number)
+ && (fabs(pwl_amp[index]-pwl_amp[index+1])>smallest_allowed_number) ) {
+ *point_found=1;
+
+ fraction = (tweaked_use_ampl-pwl_amp[index]) / (pwl_amp[index] - pwl_amp[index+1]);
+ *relay_range=use_range;
+ *entry=entry_i;
+
+ inverse_word_out = fraction * (1.0/((float) pwl_vc[index]) - 1.0/((float) pwl_vc[index+1]));
+ inverse_word_out+=1/((float) pwl_vc[index]);
+ *word_out=(int) (1.0/inverse_word_out);
+ }
+ }
}
+ if (*word_out<0) {
+ *word_out=0;
+ return HardwareError;
+ }
+
+ /* check for 12 or 13 bit overflow */
+ if (*word_out>dac_max) {
+ *word_out=dac_max; /* just to prevent wandering bits */
+ return HardwareError;
+ }
-// Error_check(globals.ChannelState); /* establishes min/max values for queries, but reports no errors */
-// update_whole_main_menu=YES;
-// Ctrl_PRF_Limiter(1);
-// Menu_Clear_Buttons();
+ return OK;
}
+
+
+int Set_VI_Add_Cal(int parameter,int channel,float cal_point)
+{
+ int point_found,range,polarity,entry,word_out,total;
+ int i;
+ float max_in_range;
+ float least_integrated_error,integrated_error;
+ float interp_ampl,fraction;
+ int delete_point;
+ float old_val;
+ float abs_cal_point;
+ int max_points,max_polarity,max_ranges;
+
+ float temp_y_float[points_in_range+1];
+ float temp_x_float[points_in_range+1];
+ int temp_x_int[points_in_range+1];
+
+ int index,actual_pol;
+ float *pointer_y_float;
+ int *pointer_x_int;
+
+ int eprom_loc,size_of_y_float,size_of_x_int;
+
+ int true_channel;
+
+ true_channel = channel;
+
+ range=polarity=0;
+
+ max_points=points_in_range;
+
+ abs_cal_point=cal_point;
+
+ switch (parameter) {
+ case (pwl_ampl_values):
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+
+ pointer_x_int=&globals.Flash.ampl_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.ampl_pwl_amp[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.ampl_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.ampl_pwl_amp);
+
+ Set_VI_Control(pwl_ampl_values,channel,globals.ChannelState[channel].amplitude,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ old_val=globals.ChannelState[channel].amplitude;
+ abs_cal_point=fabs(cal_point); /* ampl data is positive always */
+
+ /* special amplitude polarity check */
+
+ if ( (cal_point>0.0 && old_val<0.0) || (cal_point<0.0 && old_val>0.0)) {
+ return CalibrationPolarityError;
+ }
+
+ break;
+ case (pwl_os_values):
+ max_polarity=os_polarities;
+ max_ranges=os_ranges;
+ pointer_x_int=&globals.Flash.os_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.os_pwl_amp[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.os_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.os_pwl_amp);
+
+ old_val=globals.ChannelState[channel].offset;
+ Set_VI_Control(pwl_os_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_pw_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_x_int=&globals.Flash.pw_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.pw_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.pw_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.pw_pwl_time);
+ old_val=globals.ChannelState[channel].pw;
+ Set_VI_Control(pwl_pw_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_delay_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_x_int=&globals.Flash.delay_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.delay_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.delay_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.delay_pwl_time);
+ old_val=globals.ChannelState[channel].delay;
+ Set_VI_Control(pwl_delay_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_period_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_x_int=&globals.Flash.period_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.period_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.period_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.period_pwl_time);
+ old_val=1.0/globals.ChannelState[channel].frequency;
+ Set_VI_Control(pwl_period_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_burst_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_x_int=&globals.Flash.burst_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.burst_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.burst_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.burst_pwl_time);
+ old_val=globals.ChannelState[channel].burst_time;
+ Set_VI_Control(pwl_burst_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_rise_time_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pointer_x_int=&globals.Flash.rise_time_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.rise_time_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.rise_time_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.rise_time_pwl_time);
+ old_val=globals.ChannelState[channel].rise_time;
+ Set_VI_Control(pwl_rise_time_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_slew_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pointer_x_int=&globals.Flash.slew_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.slew_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.slew_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.slew_pwl_time);
+ old_val=globals.ChannelState[channel].slew;
+ Set_VI_Control(pwl_slew_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_vcc1_values:
+ max_polarity=1;
+ max_ranges=1;
+ true_channel=0;
+ pointer_x_int=&globals.Flash.vcc1_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.vcc1_pwl_amp[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.vcc1_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.vcc1_pwl_amp);
+ old_val=globals.ChannelState[true_channel].vcc1;
+ Set_VI_Control(pwl_vcc1_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_vcc2_values:
+ max_polarity=1;
+ max_ranges=1;
+ true_channel=0;
+ pointer_x_int=&globals.Flash.vcc2_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.vcc2_pwl_amp[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.vcc2_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.vcc2_pwl_amp);
+ old_val=globals.ChannelState[true_channel].vcc2;
+ Set_VI_Control(pwl_vcc2_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+ case pwl_load_type_values:
+ max_polarity=load_type_polarities;
+ max_ranges=load_type_ranges;
+ pointer_x_int=&globals.Flash.load_type_pwl_Vc_norm4095[0][0][0][0];
+ pointer_y_float=&globals.Flash.load_type_pwl_time[0][0][0][0];
+ size_of_x_int=sizeof(globals.Flash.load_type_pwl_Vc_norm4095);
+ size_of_y_float=sizeof(globals.Flash.load_type_pwl_time);
+ old_val=globals.ChannelState[channel].load_type;
+ Set_VI_Control(pwl_load_type_values,channel,old_val,&point_found,
+ &range,&polarity,&entry,&word_out,&actual_pol);
+ break;
+
+ }
+
+ temp_y_float[max_points]=0.0; /* Adding a cal point may temporarily result in 11 data points. */
+ temp_x_float[max_points]=0.0; /* One is eventually discarded. */
+ temp_x_int[max_points]=0;
+
+
+ index=true_channel*max_ranges*max_polarity*max_points
+ +range*max_polarity*max_points
+ +polarity*max_points;
+
+
+ /* make a copy of the calibration data in this range */
+ for (i=0; i<max_points; i++) {
+ temp_y_float[i]=pointer_y_float[index+i]; /* work on this data */
+ temp_x_int[i]=pointer_x_int[index+i];
+ }
+
+
+ /* check range for maximum value, and number of points */
+ max_in_range=0.0;
+ total=max_points;
+ for (i=max_points-1; i>=0; --i) {
+ if ( fabs(temp_y_float[i])<smallest_allowed_number && (total==i+1)) {
+ --total;
+ }
+ if (fabs(temp_y_float[i])>max_in_range) {
+ max_in_range=fabs(temp_y_float[i]);
+ }
+ }
+
+
+ /* check for excessive deviation between old and new amplitudes at this range/word combination */
+ if (fabs(cal_point-old_val) > max_in_range/3.0) {
+ return CalibrationPercentError;
+ }
+ /* check for overly-close data points */
+ if ( word_out==temp_x_int[entry] ) {
+ return CalibrationClosenessError;
+ }
+ if ( word_out==temp_x_int[entry+1]) {
+ return CalibrationClosenessError;
+ }
+
+
+
+ /* move old data over */
+ for (i=max_points-1; i>entry; i--) {
+ temp_y_float[i+1]=temp_y_float[i];
+ temp_x_int[i+1]=temp_x_int[i];
+ }
+
+
+ /* add the new data */
+ temp_y_float[entry+1]=abs_cal_point;
+ temp_x_int[entry+1]=word_out;
+ for (i=0; i<=max_points; ++i) {
+ temp_x_float[i]=(float) temp_x_int[i];
+ }
+
+
+ /* delete a point, if required */
+ if (total==max_points) {
+ least_integrated_error=1e18;
+
+ for (i=1; i<max_points; i++) { /* end points are not considered for deletion */
+ /* calculate interpolated amplitude, if this cal point was deleted */
+ fraction = (temp_x_float[i]-temp_x_float[i-1]) / (temp_x_float[i+1]-temp_x_float[i-1]);
+ interp_ampl = temp_y_float[i-1] + (fraction * (temp_y_float[i+1]-temp_y_float[i-1]));
+
+ /* calculate percent error at interpolated point */
+ integrated_error = fabs( (interp_ampl-temp_y_float[i])/temp_y_float[i]);
+
+ /* calculate intergrated error */
+ integrated_error *= fabs( temp_y_float[i+1] - temp_y_float[i-1] );
+
+ if (integrated_error<least_integrated_error) {
+ delete_point=i;
+ least_integrated_error=integrated_error;
+ }
+ }
+
+ /* delete the point that is most linear with the two around it */
+ for (i=delete_point; i<max_points; i++) {
+ temp_y_float[i]=temp_y_float[i+1];
+ temp_x_float[i]=temp_x_float[i+1];
+ temp_x_int[i]=temp_x_int[i+1];
+ }
+ }
+
+
+ /* store new calibration data for this range */
+ for (i=0; i<max_points; i++) {
+ *(float *)(&pointer_y_float[index+i])=temp_y_float[i];
+ *(int *)(&pointer_x_int[index+i])=temp_x_int[i];
+ }
+
+ eprom_loc = (char *) pointer_x_int - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,size_of_x_int);
+
+ eprom_loc = (char *) pointer_y_float - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,size_of_y_float);
+
+ globals.Flags.extended_ampl_min_max=NO;
+
+ /* update output */
+ switch (parameter) {
+ case (pwl_ampl_values):
+ case (pwl_vcc1_values):
+ case (pwl_vcc2_values):
+ Set_Amplitude(0,0,0,0,0,0,channel,cal_point,0);
+ break;
+
+ case (pwl_os_values):
+ Set_Offset(0,0,0,0,channel,cal_point);
+ break;
+
+ case pwl_pw_values:
+ Set_Pw(0,0,0,channel,cal_point,0);
+ break;
+
+ case pwl_delay_values:
+ Set_Delay(0,0,0,channel,cal_point);
+ break;
+
+ case pwl_period_values:
+ Set_frequency(0,0,0,channel,cal_point);
+ break;
+
+ case pwl_burst_values:
+ Set_Burst_Time(0,0,0,channel,cal_point);
+ break;
+
+ case pwl_rise_time_values:
+ Set_rise_time(0,0,0,channel,cal_point);
+ break;
+
+ case pwl_slew_values:
+ Set_slew(0,0,0,channel,cal_point);
+ break;
+
+ case pwl_load_type_values:
+ Set_avrq_res(0,0,0,channel,cal_point);
+ break;
+ }
+
+ return OK;
+}
+
+
+int Get_VI_Num_Pnts(int parameter,int channel)
+{
+ int dummy1,dummy2,dummy3,num_in_range,num_of_ranges;
+
+ return Get_VI_Rng_Info(parameter,channel,0,&dummy1,&dummy2,&dummy3,&num_in_range,&num_of_ranges);
+}
+
+
+
+int Get_VI_Rng_Info(int parameter, int channel, int calibration_point_number, int *range,
+ int *polarity, int *entry, int *num_in_range, int *num_of_ranges)
+{
+ int x_polarity,x_range,x_entry,total;
+ int num_in_current_range;
+ int max_polarity,max_points,max_ranges;
+ float *pwl;
+ int index;
+ int true_channel;
+
+ true_channel=channel;
+
+ *polarity=0;
+ *range=0;
+ *entry=0;
+ *num_in_range=0;
+
+ /* determine array structure */
+ max_points=points_in_range;
+
+ switch (parameter) {
+ case pwl_ampl_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl=&globals.Flash.ampl_pwl_amp[0][0][0][0];
+ break;
+ case pwl_os_values:
+ max_polarity=os_polarities;
+ max_ranges=os_ranges;
+ pwl=&globals.Flash.os_pwl_amp[0][0][0][0];
+ break;
+ case pwl_pw_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl=&globals.Flash.pw_pwl_time[0][0][0][0];
+ break;
+ case pwl_delay_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl=&globals.Flash.delay_pwl_time[0][0][0][0];
+ break;
+ case pwl_period_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl=&globals.Flash.period_pwl_time[0][0][0][0];
+ break;
+ case pwl_burst_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl=&globals.Flash.burst_pwl_time[0][0][0][0];
+ break;
+ case pwl_rise_time_values:
+ max_polarity=ampl_polarities;
+ max_ranges=ampl_ranges;
+ pwl=&globals.Flash.rise_time_pwl_time[0][0][0][0];
+ break;
+ case pwl_slew_values:
+ max_polarity=timing_polarities;
+ max_ranges=timing_ranges;
+ pwl=&globals.Flash.slew_pwl_time[0][0][0][0];
+ break;
+ case pwl_vcc1_values:
+ max_polarity=1;
+ max_ranges=1;
+ pwl=&globals.Flash.vcc1_pwl_amp[0][0][0][0];
+ true_channel=0;
+ break;
+ case pwl_vcc2_values:
+ max_polarity=1;
+ max_ranges=1;
+ pwl=&globals.Flash.vcc2_pwl_amp[0][0][0][0];
+ true_channel=0;
+ break;
+ case pwl_load_type_values:
+ max_polarity=load_type_polarities;
+ max_ranges=load_type_ranges;
+ pwl=&globals.Flash.load_type_pwl_time[0][0][0][0];
+ break;
+ }
+
+
+
+ total=0;
+ *num_of_ranges=0;
+
+ for (x_polarity=0; x_polarity<max_polarity; x_polarity++)
+ for (x_range=0; x_range<max_ranges; x_range++) {
+
+ /* determine number of data points in range */
+ /* do this by counting number of zeroes at top end of array */
+ num_in_current_range=max_points;
+ for (x_entry=max_points-1; x_entry>=0; --x_entry) {
+ /* pwl is a pointer to either the amplitude or offset control array. */
+ /* Multidimensional pointer arrays are not possible, since the array size */
+ /* is unknown at compilation time. Thus, the index offset has to be calculated manually. */
+ index=true_channel*max_ranges*max_polarity*max_points
+ +x_range*max_polarity*max_points
+ +x_polarity*max_points
+ +x_entry;
+ if ( fabs(pwl[index])<smallest_allowed_number && (num_in_current_range==x_entry+1)) {
+ --num_in_current_range;
+ }
+ }
+
+ if (num_in_current_range) {
+ *num_of_ranges=x_range;
+
+ for (x_entry=0; x_entry<num_in_current_range; x_entry++) {
+ ++total;
+ if (total==calibration_point_number) {
+ calibration_point_number=0; /* to prevent further matches */
+ *range=x_range;
+ *polarity=x_polarity;
+ *entry=x_entry;
+ *num_in_range=num_in_current_range;
+ }
+ }
+ }
+ }
+
+ return total;
+}
+
+
+int Check_MinMax_Cal(int channel,int parameter)
+{
+ int status;
+
+ status=OK;
+
+ /* see if new point prevents zero, min, max, or current value from being obtained */
+ switch (parameter) {
+ case (pwl_ampl_values):
+ status=Set_Amplitude(1,0,0,0,0,0,channel,globals.Flash.min_ampl[channel],0)
+ || Set_Amplitude(1,0,0,0,0,0,channel,globals.Flash.max_ampl[channel],0)
+ || Set_Amplitude(1,0,0,0,0,0,channel,0.0,0);
+ break;
+
+ case (pwl_os_values):
+ status=Set_Offset(1,0,0,0,channel,globals.Flash.min_offset[channel])
+ || Set_Offset(1,0,0,0,channel,globals.Flash.max_offset[channel])
+ || Set_Offset(1,0,0,0,channel,0.0);
+ break;
+
+ case pwl_pw_values:
+ status=Set_Pw(1,0,0,channel,globals.Flash.min_pw[channel],0)
+ || Set_Pw(1,0,0,channel,globals.Flash.max_pw[channel],0);
+ break;
+
+ case pwl_delay_values:
+ status=Set_Delay(1,0,0,channel,globals.Flash.min_delay[channel])
+ || Set_Delay(1,0,0,channel,globals.Flash.max_delay[channel]);
+ break;
+
+ case pwl_period_values:
+ status=Set_frequency(1,0,0,channel,globals.Flash.min_freq[channel])
+ || Set_frequency(1,0,0,channel,globals.Flash.max_freq[channel]);
+ break;
+
+ case pwl_burst_values:
+ status=Set_Burst_Time(1,0,0,channel,globals.Flash.min_burst_gap[channel])
+ || Set_Burst_Time(1,0,0,channel,globals.Flash.max_burst_gap[channel]);
+ break;
+
+ case pwl_rise_time_values:
+ status=Set_rise_time(1,0,0,channel,globals.Flash.min_rise_time[channel])
+ || Set_rise_time(1,0,0,channel,globals.Flash.max_rise_time[channel]);
+ break;
+
+ case pwl_slew_values:
+ status=Set_slew(1,0,0,channel,globals.Flash.min_slew[channel])
+ || Set_slew(1,0,0,channel,globals.Flash.max_slew[channel]);
+ break;
+
+ case (pwl_vcc1_values):
+ status=Set_Amplitude(1,0,0,0,0,0,channel,0.0,0)
+ || Set_Amplitude(1,0,0,0,0,0,channel,globals.Flash.vcc1_max[0],0);
+ break;
+
+ case (pwl_vcc2_values):
+ status=Set_Amplitude(1,0,0,0,0,0,channel,0.0,0)
+ || Set_Amplitude(1,0,0,0,0,0,channel,globals.Flash.vcc2_max[0],0);
+ break;
+
+ case pwl_load_type_values:
+ status=Set_avrq_res(1,0,0,channel,globals.Flash.low_load_type[channel])
+ || Set_avrq_res(1,0,0,channel,globals.Flash.high_load_type[channel]);
+ break;
+ }
+
+ if (status) {
+ /* change the error code to a calibration-related one */
+ status=CalibrationMinMaxError;
+ }
+
+ return status;
+}
+
+
+int control_pcb107(int address, int dac, int word, int range)
+{
+ /* reset all lines */
+ I2C_Write(PCF8574+address,0);
+
+ set_dac(dac,word);
+
+ /* send and load range data */
+ I2C_Write(PCF8574+address,(range << 3));
+ I2C_Write(PCF8574+address,(range << 3) | 0x80);
+
+ /* clear the lines */
+ I2C_Write(PCF8574+address,0);
+
+ return OK;
+}
+
+
+int Set_Burst_Count(int channel,int count,float new_burst_time)
+{
+ int check_valid;
+ int hextext_out;
+
+ if (globals.Flash.max_burst_count[channel]<=1) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_Burst_Count) {
+ return InvalidChannel;
+ }
+
+ /* check duty cycle */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].burst_count=count;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+
+ /* update variables if OK */
+ if (count!=globals.ChannelState[channel].burst_count) {
+ globals.Changes.update_burst_count=YES;
+ }
+
+ globals.ChannelState[channel].burst_count = count;
+ Set_Update_Chans();
+
+ if (!globals.Flash.burst_func[channel]) {
+ /* Call update routine for pulse generator burst mode. */
+ /* Update pulse separation at the same time. This routine does the actual changes. */
+ Set_Burst_Time(0,0,0,channel,new_burst_time);
+ } else {
+ /* reset all lines */
+ I2C_Write(PCF8574+Second_PW_Port,0);
+
+ /* send first hextet */
+ hextext_out=globals.ChannelState[channel].burst_count & 0x003f;
+
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out);
+ /* load hextet */
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out | 0x40 );
+
+ /* send second hextet */
+ if (globals.ChannelState[channel].burst_count > 0) {
+ /* set "not_reset" bit high to enable burst mode for N > 0 */
+ hextext_out = ((globals.ChannelState[channel].burst_count >> 6) & 0x07) | 0x08;
+ } else {
+ hextext_out = 0;
+ }
+
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out);
+ /* load hextet */
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out | 0x80 );
+
+ /* clear the lines */
+ I2C_Write(PCF8574+Second_PW_Port,0);
+
+ }
+
+ return OK;
+}
+
+
+int Set_Burst_Time(int check_possible_only,int word_override,int range_override,int channel,float new_burst_time)
+{
+ int check_valid;
+ int count_word_out;
+ int hextext_out;
+ int status,point_found,relay_range,UseNegData,entry,actual_pol,word_out;
+
+ if (globals.Flash.max_burst_count[channel]<=1) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_Burst_Time) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ /* check duty cycle */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].burst_time=new_burst_time;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ /* tweak count based on actual circuit */
+ count_word_out = globals.ChannelState[channel].burst_count - 1;
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ if ((status=Set_VI_Control(pwl_burst_values,channel,new_burst_time,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ start_gate_override ();
+
+ /* update DAC */
+ set_dac(6,word_out);
+
+
+ /* update range and burst count */
+
+ /* reset all lines */
+ I2C_Write(PCF8574+Second_PW_Port,0);
+
+ /* send first hextet */
+ hextext_out=count_word_out & 0x003f;
+
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out);
+ /* load hextet */
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out | 0x40 );
+
+ /* send second hextet */
+ hextext_out= ((count_word_out >> 6) & 0x07) | ((relay_range << 3) & 0x0038);
+
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out);
+ /* load hextet */
+ I2C_Write(PCF8574+Second_PW_Port, hextext_out | 0x80 );
+
+ /* clear the lines */
+ I2C_Write(PCF8574+Second_PW_Port,0);
+
+ if (globals.Registers.last_relay_driver_settings[2] != relay_range) {
+ g_usleep (1e3 * globals.Timers.normal_relay_bounce_time_in_milliseconds);
+ }
+ stop_gate_override ();
+
+ globals.Registers.last_relay_driver_settings[2] = relay_range;
+
+ /* update variables if OK */
+ if (new_burst_time!=globals.ChannelState[channel].burst_time) {
+ globals.Changes.update_burst_time=YES;
+ }
+
+ globals.ChannelState[channel].burst_time = new_burst_time;
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_rise_time(int check_possible_only,int word_override,int range_override,int channel,float new_rise_time)
+{
+ int check_valid;
+ int status,point_found,relay_range,UseNegData,entry,actual_pol,word_out;
+ char range_control;
+
+ if (globals.Flash.fixed_rise_time[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_rise_time) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ /* check duty cycle */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].rise_time=new_rise_time;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ if ((status=Set_VI_Control(pwl_rise_time_values,channel,new_rise_time,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ set_dac(globals.Flash.rise_time_dac[channel],word_out);
+
+ if (!globals.Flash.pcb_203a_rise_time[channel]) {
+ /* original AVRQ PCB */
+ switch (relay_range) {
+ case 0:
+ range_control = (char) 0x01;
+ break;
+ case 1:
+ range_control = (char) 0x08;
+ break;
+ case 2:
+ range_control = (char) 0x10;
+ break;
+ case 3:
+ range_control = (char) 0x20;
+ break;
+ case 4:
+ range_control = (char) 0x40;
+ break;
+ case 5:
+ range_control = (char) 0x80;
+ break;
+ case 6:
+ case 7:
+ return HardwareError;
+ break;
+ }
+ } else {
+ /* PCB 203A */
+ switch (relay_range) {
+ case 0:
+ range_control = (char) 0x0f;
+ break;
+ case 1:
+ range_control = (char) 0x02;
+ break;
+ case 2:
+ range_control = (char) 0x04;
+ break;
+ case 3:
+ range_control = (char) 0x08;
+ break;
+ case 4:
+ range_control = (char) 0x10;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ return HardwareError;
+ break;
+ }
+ }
+
+
+
+ if (globals.Registers.last_rise_time_relay_setting != range_control) {
+ /* update range hardware */
+ if (globals.ChannelState[channel].trigger_source!=source_hold) {
+ bus_setpin(O_GATE, 1);
+ }
+
+ if (!globals.Flash.pcb_203a_rise_time[channel]) {
+ I2C_Write(PCF8574A+rise_time_port,range_control);
+ } else {
+ globals.Registers.avrq_reg = (range_control & 0x1f) |
+ (globals.Registers.avrq_reg & 0xe0);
+ I2C_Write(PCF8574A+rise_time_port,globals.Registers.avrq_reg);
+ }
+ g_usleep (5e5);
+
+ if (globals.ChannelState[channel].trigger_source!=source_hold) {
+ bus_setpin(O_GATE, 0);
+ }
+ }
+
+ /* update variables if OK */
+ if (new_rise_time!=globals.ChannelState[channel].rise_time) {
+ globals.Changes.update_rise_time=YES;
+ }
+
+ globals.ChannelState[channel].rise_time = new_rise_time;
+ globals.Registers.last_rise_time_relay_setting = range_control;
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_current_limit(int check_possible_only,int channel,float new_adj_current_limit)
+{
+ int check_valid;
+ float limit;
+ int word_out;
+
+ if (!globals.Flash.hard_current_limit_enabled[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_current_limit) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].soft_current_limit=new_adj_current_limit;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ if (globals.ChannelState[channel].func_mode==dc_mode_on) {
+ limit=globals.Flash.current_limit_dc_mode[channel];
+ } else {
+ limit=globals.Flash.current_limit_pulse_mode[channel];
+ }
+
+ if (globals.Flash.soft_current_limit_enabled[channel] && (new_adj_current_limit<limit)) {
+ limit=new_adj_current_limit;
+ }
+
+ word_out = (int) ( ((float) dac_max) * (limit/globals.Flash.current_limit_full_scale[channel]) );
+ set_dac(globals.Flash.current_limit_dac[channel],word_out);
+
+ /* update variables if OK */
+ if (limit!=globals.ChannelState[channel].soft_current_limit) {
+ globals.Changes.update_soft_current_limit=YES;
+ }
+
+ globals.ChannelState[channel].soft_current_limit=limit;
+
+ return OK;
+}
+
+
+int Set_avrq_res(int check_possible_only,int word_override,int range_override,int channel,float new_res)
+{
+ int check_valid;
+ int status,point_found,relay_range,UseNegData,entry,actual_pol,word_out;
+
+ float compensated_new_res;
+
+ if (!globals.Flash.switchable_load[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_load_type) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].load_type=new_res;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ /* ugly hack - fix me?
+ CH2 = opto VCC
+ Calibrate res at 3.0V
+ Compensate for >3.0V */
+ if (globals.ChannelState[0].vcc2 > 0.0) {
+ compensated_new_res = new_res * 3.0/globals.ChannelState[0].vcc2;
+ } else {
+ return amplitude_lower_limit;
+ }
+
+ if ((status=Set_VI_Control(pwl_load_type_values,channel,compensated_new_res,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ set_dac(globals.Flash.load_type_dac[channel],word_out);
+
+ /* no ranges are used */
+
+ /* update variables if OK */
+ if (new_res!=globals.ChannelState[channel].load_type) {
+ globals.Changes.update_load=YES;
+ }
+
+ globals.ChannelState[channel].load_type = new_res;
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_slew(int check_possible_only,int word_override,int range_override,int channel,float new_slew)
+{
+ int check_valid;
+ int status,point_found,relay_range,UseNegData,entry,actual_pol,word_out;
+ char range_control;
+
+ if (!globals.Flash.curr_slew[channel]) {
+ return Unrecognized;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_slew) {
+ return InvalidChannel;
+ }
+
+ if (!check_possible_only) {
+ /* check duty cycle */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ TestState[channel].slew=new_slew;
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ if ((status=Set_VI_Control(pwl_slew_values,channel,new_slew,&point_found,
+ &relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+ set_dac(globals.Flash.slew_dac[channel],word_out);
+
+ switch (relay_range) {
+ case 0:
+ range_control = 0x0f;
+ break;
+ case 1:
+ range_control = 0x07;
+ break;
+ case 2:
+ range_control = 0x03;
+ break;
+ case 3:
+ range_control = 0x01;
+ break;
+ case 4:
+ default:
+ range_control = 0x00;
+ break;
+ }
+
+ I2C_Write(PCF8574,range_control);
+
+ /* update variables if OK */
+ if (new_slew!=globals.ChannelState[channel].slew) {
+ globals.Changes.update_slew=YES;
+ }
+
+ globals.ChannelState[channel].slew = new_slew;
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int Set_avrq_ampl(int check_possible_only,int word_override,int range_override,int channel,float new_avrq_ampl)
+{
+ int check_valid;
+ int status,point_found,relay_range,UseNegData,entry,actual_pol,word_out;
+ int true_channel;
+ int use_pwl;
+
+ if (!globals.Flash.enable_avrq_extra_ampls) {
+ return Unrecognized;
+ }
+
+ /* check channels */
+ if ((channel < 1) || (channel>4)) {
+ return InvalidChannel;
+ }
+
+ if (channel == 1) {
+ true_channel = 1;
+ } else {
+ true_channel = 0;
+ }
+
+ if (!check_possible_only) {
+ /* check duty cycle */
+ int i;
+ for (i=0; i<max_channels; ++i) {
+ TestState[i]=globals.ChannelState[i];
+ }
+ switch (channel) {
+ case 1:
+ TestState[true_channel].amplitude=new_avrq_ampl;
+ break;
+ case 2:
+ TestState[true_channel].vcc1=new_avrq_ampl;
+ if (TestState[true_channel].vlogic >= smallest_allowed_number) {
+ TestState[true_channel].vlogic = new_avrq_ampl;
+ }
+ break;
+ case 3:
+ TestState[true_channel].vcc2=new_avrq_ampl;
+ break;
+ case 4:
+ TestState[true_channel].vlogic=new_avrq_ampl;
+ break;
+ }
+ if ((check_valid=Error_check(TestState))) {
+ return check_valid;
+ }
+ }
+
+ /* find appropriate range/fine settings from piece-wise linear data in flash memory */
+ if (word_override) {
+ word_out=word_override;
+ relay_range=range_override;
+ } else {
+ switch (channel) {
+ case 1:
+ use_pwl = pwl_ampl_values;
+ break;
+ case 2:
+ use_pwl = pwl_vcc1_values;
+ break;
+ case 3:
+ use_pwl = pwl_vcc2_values;
+ break;
+ case 4:
+ use_pwl = pwl_vlogic_values;
+ if (new_avrq_ampl > 0.0) {
+ new_avrq_ampl = globals.ChannelState[true_channel].vcc1;
+ }
+ break;
+ }
+
+ if (use_pwl != pwl_vlogic_values)
+ if ((status=Set_VI_Control(use_pwl,channel,new_avrq_ampl,&point_found,&relay_range,&UseNegData,&entry,&word_out,&actual_pol))) {
+ return status;
+ }
+
+ }
+
+ if (check_possible_only) {
+ if (point_found) {
+ return OK;
+ } else {
+ return CalibrationMinMaxError;
+ }
+ }
+
+
+ /* update variables if OK */
+ switch (channel) {
+ case 1:
+ Set_avrq_ampl(0,0,0,4,0.0);
+
+ set_dac(1,word_out);
+
+ globals.Registers.avrq_reg = globals.Registers.avrq_reg & 0x3f;
+ I2C_Write(PCF8574A+rise_time_port,globals.Registers.avrq_reg);
+
+ if (new_avrq_ampl!=globals.ChannelState[true_channel].amplitude) {
+ globals.Changes.update_amp=YES;
+ }
+ globals.ChannelState[true_channel].amplitude=new_avrq_ampl;
+ break;
+ case 2:
+ set_dac(1,word_out);
+
+ globals.Registers.avrq_reg = 0x40 | (globals.Registers.avrq_reg & 0xbf);
+ I2C_Write(PCF8574A+rise_time_port,globals.Registers.avrq_reg);
+
+ if (new_avrq_ampl!=globals.ChannelState[true_channel].vcc1) {
+ globals.Changes.update_amp=YES;
+ }
+ globals.ChannelState[true_channel].vcc1=new_avrq_ampl;
+ break;
+ case 3:
+ set_dac(0,word_out);
+ if (new_avrq_ampl!=globals.ChannelState[true_channel].vcc2) {
+ globals.Changes.update_amp=YES;
+ }
+ globals.ChannelState[true_channel].vcc2=new_avrq_ampl;
+
+ /* update ampl-dependent load resistance */
+ Set_avrq_res(0,0,0,0,globals.ChannelState[0].load_type);
+
+ break;
+ case 4:
+ if (new_avrq_ampl >= smallest_allowed_number) {
+ relay_range = 0x80;
+ } else {
+ relay_range = 0x0;
+ }
+ globals.Registers.avrq_reg = relay_range | (globals.Registers.avrq_reg & 0x7f);
+ I2C_Write(PCF8574A+rise_time_port,globals.Registers.avrq_reg);
+
+ if (new_avrq_ampl!=globals.ChannelState[true_channel].vlogic) {
+ globals.Changes.update_amp=YES;
+ }
+ globals.ChannelState[true_channel].vlogic=new_avrq_ampl;
+ break;
+ }
+
+
+ /* reduce vlogic based on vcc1, if required */
+ if (channel == 2) {
+ if (globals.ChannelState[true_channel].vlogic > smallest_allowed_number) {
+ Set_avrq_ampl(0,0,0,4,globals.ChannelState[true_channel].vcc1);
+ } else {
+ Set_avrq_ampl(0,0,0,4,0.0);
+ }
+ }
+
+ /* reduce vcc1 if ibias is active, because they share a DAC */
+ if ((channel == 1) && (globals.ChannelState[true_channel].amplitude > smallest_allowed_number)) {
+ globals.ChannelState[0].vcc1=0.0;
+ }
+
+ /* reduce vcc1 if ibias is active, because they share a DAC */
+ if ((channel == 2) && (globals.ChannelState[true_channel].vcc1 > smallest_allowed_number)) {
+ globals.ChannelState[1].amplitude=0.0;
+ }
+
+ Set_Update_Chans();
+
+ return OK;
+}
+
+
+int go_cal(CalStruct *caldata)
+{
+ int i, status, points;
+ float meas, nom_val, change;
+ float min_val, max_val, chk_val;
+ char lcd_msg[LCD_cols+1];
+ char prefix[LCD_cols+1];
+
+ points = Get_VI_Num_Pnts(caldata->cal_type,caldata->channel);
+
+ caldata->count = 0;
+ caldata->error = 0;
+ caldata->max_change = 0.0;
+ caldata->avg_change = 0.0;
+
+ min_val = 100e-6;
+ if (caldata->cal_type == pwl_period_values) {
+ max_val = 4.0 / globals.Flash.min_freq[caldata->channel];
+ chk_val = 0.25 / globals.Flash.max_freq[caldata->channel];
+ if (chk_val > min_val) {
+ min_val = chk_val;
+ }
+ } else if (caldata->cal_type == pwl_pw_values) {
+ max_val = 4.0 * globals.Flash.max_pw[caldata->channel];
+ chk_val = 0.25 * globals.Flash.min_pw[caldata->channel];
+ if (chk_val > min_val) {
+ min_val = chk_val;
+ }
+ } else if (caldata->cal_type == pwl_delay_values) {
+ max_val = 4.0 * globals.Flash.max_delay[caldata->channel];
+ }
+
+ for (i=1; i<=points; i++) {
+ Set_Cal_Nom(caldata->channel,i,caldata->cal_type,&nom_val);
+ if ( (nom_val >= min_val) && (nom_val <= max_val) ) {
+ Set_Cal_Nom(caldata->channel,i,caldata->cal_type,NULL);
+
+ LCD_clear();
+ LCD_write(0,0,"Self-calibration in progress.");
+
+ if (caldata->cal_type == pwl_period_values) {
+ sprintf (prefix, "CH%d PER %d:",caldata->channel+1,i);
+ } else if (caldata->cal_type == pwl_pw_values) {
+ sprintf (prefix, "CH%d PW %d:",caldata->channel+1,i);
+ } else if (caldata->cal_type == pwl_delay_values) {
+ sprintf (prefix, "CH%d DLY %d:",caldata->channel+1,i);
+ }
+ sprintf (lcd_msg, "%s %.3e",prefix,nom_val);
+ LCD_write(2,0,lcd_msg);
+
+ if (caldata->cal_type == pwl_period_values) {
+ I2C_Self_Cal (caldata->channel, MEAS_PRF, &meas, 1.0 / globals.ChannelState[caldata->channel].frequency);
+ } else if (caldata->cal_type == pwl_pw_values) {
+ I2C_Self_Cal (caldata->channel, MEAS_PW, &meas, globals.ChannelState[caldata->channel].pw);
+ } else {
+ I2C_Self_Cal (caldata->channel, MEAS_PW, &meas, globals.ChannelState[caldata->channel].delay);
+ }
+
+ change = 100.0 * (meas-nom_val)/nom_val;
+ status = Set_VI_Cal_Pnt(caldata->cal_type,caldata->channel,i,meas);
+ if (status) {
+ ++caldata->error;
+ } else {
+ ++caldata->count;
+ if (fabs(change)>caldata->max_change) {
+ caldata->max_change = change;
+ }
+ caldata->avg_change = ((caldata->avg_change * (((float) caldata->count) - 1.0)) + change) / caldata->count;
+ }
+
+ LCD_clear();
+ LCD_write(0,0,"Self-calibration in progress.");
+ sprintf (lcd_msg, "%s %.3e -> %.3e",prefix,nom_val,meas);
+ LCD_write(2,0,lcd_msg);
+ sprintf (lcd_msg, "changed %6.2f%%, err: %d",change,status);
+ LCD_write(3,0,lcd_msg);
+ g_usleep (2e6);
+ }
+ }
+
+ return OK;
+}
+
+
+int cal_string(char *parameter, CalStruct *caldata)
+{
+ char string[max_output_length];
+
+ sprintf(string,"CH%d %s cal: %d errors. Adj: %6.2f%% max, %6.2f%% avg.\n\r", caldata->channel+1,parameter, caldata->error, caldata->max_change, caldata->avg_change);
+ strcat (caldata->response, string);
+}
+
+
+int self_cal()
+{
+ CalStruct caldata;
+ return do_full_self_cal(&caldata);
+}
+
+
+int do_full_self_cal(CalStruct *caldata)
+{
+ char string[LCD_cols+1];
+ long start_timer, diff_timer;
+ int eprom_loc;
+
+ Menu_Clear_Buttons();
+ LCD_clear(); /*0123456789012345678901234567890123456789*/
+ LCD_write(0,0,"Self-calibration in progress.");
+ /*0123456789012345678901234567890123456789*/
+ sprintf(string,"Typical run time: %d min, %d sec.", globals.Flash.self_cal_typical_time_min, globals.Flash.self_cal_typical_time_sec);
+ LCD_write(1,0,string);
+
+ while ((sec_timer() - globals.Timers.startup_timer_value) < (long)globals.Flash.self_cal_pause) {
+ /*0123456789012345678901234567890123456789*/
+ sprintf (string, "Min warm-up is %ds, on for %lds.", globals.Flash.self_cal_pause, sec_timer() - globals.Timers.startup_timer_value);
+ LCD_write(3,0,string);
+ g_usleep (2e5);
+ }
+
+ start_timer = sec_timer();
+ caldata->response[0] = 0;
+ caldata->total_errors = 0;
+ caldata->total_max_change = 0.0;
+
+ caldata->cal_type = pwl_pw_values;
+ for (caldata->channel=0; caldata->channel<(globals.Flash.ChanKey_pw?globals.Flash.channels:1); ++caldata->channel) {
+ go_cal(caldata);
+ cal_string("PW", caldata);
+ caldata->total_errors += caldata->error;
+ if (fabs(caldata->total_max_change) < fabs(caldata->max_change)) {
+ caldata->total_max_change = caldata->max_change;
+ }
+ }
+
+ caldata->cal_type = pwl_delay_values;
+ for (caldata->channel=0; caldata->channel<(globals.Flash.ChanKey_delay?globals.Flash.channels:1); ++caldata->channel) {
+ go_cal(caldata);
+ cal_string("Delay", caldata);
+ caldata->total_errors += caldata->error;
+ if (fabs(caldata->total_max_change) < fabs(caldata->max_change)) {
+ caldata->total_max_change = caldata->max_change;
+ }
+ }
+
+ caldata->cal_type = pwl_period_values;
+ for (caldata->channel=0; caldata->channel<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++caldata->channel) {
+ go_cal(caldata);
+ cal_string("Period", caldata);
+ caldata->total_errors += caldata->error;
+ if (fabs(caldata->total_max_change) < fabs(caldata->max_change)) {
+ caldata->total_max_change = caldata->max_change;
+ }
+ }
+
+ Main_Rst();
+
+ LCD_clear(); /*0123456789012345678901234567890123456789*/
+ LCD_write(0,0,"Self-calibration complete.");
+ sprintf (string, "%d errors. Max change: %6.2f%%", caldata->total_errors, caldata->total_max_change);
+ LCD_write(1,0,string);
+ LCD_write(2,0,"More details are provided by \"cal?\"");
+ g_usleep (3e6);
+
+ Menu_Update_Display();
+
+ diff_timer = sec_timer() - start_timer;
+
+ globals.Flash.self_cal_typical_time_min = (int) (diff_timer / 60);
+ globals.Flash.self_cal_typical_time_sec = (int) (diff_timer % 60);
+
+ sprintf(string,"Completed in %d minutes and %d seconds\n\r", globals.Flash.self_cal_typical_time_min, globals.Flash.self_cal_typical_time_sec);
+ strcat (caldata->response, string);
+
+ eprom_loc = (char *) &(globals.Flash.self_cal_typical_time_min) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.self_cal_typical_time_min));
+ eprom_loc = (char *) &(globals.Flash.self_cal_typical_time_sec) - (char *) &(globals.Flash.flash_start);
+ writeUserBlock(eprom_loc,&globals.Flash.flash_start + eprom_loc,sizeof(globals.Flash.self_cal_typical_time_sec));
+
+ if (caldata->total_errors) {
+ return SelfCalError;
+ }
+}
+
+int I2C_Self_Cal(int channel, int meas_mode, float *meas, float target_time)
+{
+#define MAX_TRIES 35
+#define AVG_TRIES 4
+
+ int word, buffer, ch_mode;
+ long count;
+ float measuring_time;
+ float min_time;
+ float avg, max_error, this, this_error;
+ int iter, stable,i;
+ float prev[AVG_TRIES];
+
+ for (i=0; i<AVG_TRIES; i++) {
+ prev[i]=0.0;
+ }
+
+ *meas = 0.0;
+ stable = 0;
+
+ if (channel) {
+ ch_mode = MEAS_CH2;
+ } else {
+ ch_mode = MEAS_CH1;
+ }
+
+ measuring_time = 1.0;
+
+ min_time = globals.ChannelState[channel].pw * 3.0;
+ if (min_time > measuring_time) {
+ measuring_time = min_time;
+ }
+
+ min_time = (1.0/globals.ChannelState[channel].frequency);
+ if (min_time > measuring_time) {
+ measuring_time = min_time;
+ }
+
+ if (meas_mode == MEAS_PRF) {
+ min_time = (1.0/globals.ChannelState[channel].frequency) * 3.0;
+ if (min_time > measuring_time) {
+ measuring_time = min_time;
+ }
+ }
+
+ min_time = fabs(globals.ChannelState[channel].delay) * 3.0;
+ if (min_time > measuring_time) {
+ measuring_time = min_time;
+ }
+
+ for (iter = 1; (iter <= MAX_TRIES) && !stable; iter++) {
+
+ if (iter <= LCD_cols) {
+ LCD_write(3,(iter-1) % 35,". ");
+ }
+
+ if (meas_mode == MEAS_PW) {
+ start_gate_override ();
+ // delay to let oscillator reset, within 20% of a period?
+ g_usleep((gulong) (2.0e5 / globals.ChannelState[channel].frequency));
+ }
+
+ // reset counters
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+
+ // arm flip-flops
+ word = ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+
+ if (meas_mode == MEAS_PW) {
+ stop_gate_override ();
+ }
+
+ // time to measure
+ g_usleep((gulong) (measuring_time * 1.0e6));
+
+ // latch into buffers
+ word = NOT_ENABLE_COUNT | LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_0;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+
+ // read buffers
+ buffer = I2C_Read (PCF8574+From_Self_Cal_Port);
+ count = (long) buffer;
+
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_1;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ buffer = I2C_Read (PCF8574+From_Self_Cal_Port);
+ count = count | ((long) buffer << 8);
+
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_2;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ buffer = I2C_Read (PCF8574+From_Self_Cal_Port);
+ count = count | ((long) buffer << 16);
+
+ word = NOT_ENABLE_COUNT | NOT_LOAD_BUFFERS_CLK | NOT_CLR_COUNTERS | meas_mode | ch_mode | COUNTER_BYTE_3;
+ I2C_Write(PCF8574+To_Self_Cal_Port,word);
+ buffer = I2C_Read (PCF8574+From_Self_Cal_Port);
+ count = count | ((long) buffer << 24);
+
+ if (count < 100) {
+ //return SelfCalError;
+ if (iter <= LCD_cols) {
+ LCD_write(3,iter-1,"x");
+ }
+ continue;
+ }
+
+ this = count * 100e-9;
+ max_error = 0.001;
+ avg = 0.0;
+
+ for (i=0; i<(AVG_TRIES-1); i++) {
+ prev[i]=prev[i+1];
+ }
+ prev[AVG_TRIES-1] = this;
+ for (i = 0; i<AVG_TRIES; i++) {
+ avg += (prev[i]/AVG_TRIES);
+ }
+
+ this_error = fabs ((this - avg) / avg);
+ if (this_error < max_error) {
+ stable = 1;
+ }
+ }
+
+ if (!stable) {
+ return SelfCalError;
+ }
+
+ *meas = this;
+ return OK;
+}
+