#include "device-functions.h" #include "globals.h" #include "version.h" #include "error_utils.h" #include "i2c.h" #include "bus.h" #include "lcd.h" #include "flash.h" #include "menus.h" #include #include #include #include #include #include static void start_gate_override (); static void stop_gate_override (); void idn_string(gchar** response) { *response = g_strdup_printf ("AVTECH ELECTROSYSTEMS,%s,SN:%s,v%s", globals.Flash.model_num, globals.Flash.serial_num, FW_VERSION); } void Main_Rst (void) { int i; globals.Flags.extended_ampl_min_max=NO; // go backwards, so channel 0 overrides everything for (i=globals.Flash.channels-1; i>=0; --i) { globals.ChannelState[i].route_primary=1; globals.ChannelState[i].route_secondary=1; globals.ChannelState[i].frequency=globals.Flash.min_freq[i]; globals.ChannelState[i].delay=globals.Flash.min_delay[i]; if (globals.Flash.min_pw[i] > 0.0) { globals.ChannelState[i].pw=globals.Flash.min_pw[i]; } else { globals.ChannelState[i].pw=0.0; } if (globals.Flash.ampl_min_max_only[i] || (globals.Flash.min_ampl[i] > 0.0)) { globals.ChannelState[i].amplitude = globals.Flash.min_ampl[i]; } else { globals.ChannelState[i].amplitude=0.0; } globals.ChannelState[i].offset=0.0; globals.ChannelState[i].zout=globals.Flash.zout_min[i]; globals.ChannelState[i].hold_setting = hold_width; globals.ChannelState[i].double_pulse = double_off; globals.ChannelState[i].ab_mode = pw_normal; globals.ChannelState[i].func_mode = pulse_mode_on; globals.ChannelState[i].polarity = globals.Flash.invert_by_default[i]; globals.ChannelState[i].output_state = output_off; globals.ChannelState[i].gate_type = gate_sync; globals.ChannelState[i].trigger_source = source_internal; globals.ChannelState[i].amp_mode = amp_mode_normal; globals.ChannelState[i].os_mode = os_mode_normal; globals.ChannelState[i].gate_level = gate_low; globals.ChannelState[i].load_type= globals.Flash.low_load_type[i]; globals.ChannelState[i].test_delay_mode = NO; globals.ChannelState[i].logic_level = logic_ttl; globals.ChannelState[i].burst_count = 1 && !globals.Flash.burst_func[i]; globals.ChannelState[i].burst_time = globals.Constraints.composite_min_burst_time[i]; globals.ChannelState[i].rise_time = globals.Flash.min_rise_time[i]; globals.ChannelState[i].soft_current_limit = globals.Flash.max_soft_current_limit[i]; globals.ChannelState[i].vcc1 = 0.0; globals.ChannelState[i].vcc2 = globals.Flash.vcc2_min[i]; globals.ChannelState[i].vlogic = 0.0; globals.ChannelState[i].slew = globals.Flash.min_slew[i]; 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); 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; // reset all transient flags globals.Flags = globals.DefaultFlags; Menu_Clear_Buttons(); } void 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 UseNegData; /* if polarity is negative and separate piece-wise linear data is available for neg */ int point_found; int entry; 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 (!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) { int i, error_num; for (i=0; iold_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))); } long 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 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) { int i, check_valid; for (i=0; i 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]) { // reset PG B line (see below) globals.Registers.shift_reg_out[2] &= (long)0x7ffff; /* 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; // set XTRA RLY 5 high in this range for AVR-E3-B-R5-N-M5, and other // units with PG A, B, and C. This corresponds to PG B. globals.Registers.shift_reg_out[2] |= (long)0x80000; } else { cap_range_control = 1 << (relay_range-2); globals.Registers.shift_reg_out[2] &= (long)0x7ffff; } } } /* 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); } 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 point_found; int entry,dummy1,dummy2,dummy3; int 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) { int i, error_num; for (i=0; i= 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 (setting1) { int i; if (!globals.Flash.ChanKey_frequency) for (i=1; i1.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(&globals.Flash, 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(&globals.Flash, 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 */ } } 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)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(&globals.Flash, 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(&globals.Flash, 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 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.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.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(); Show_Main_Menu(); 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(&globals.Flash, eprom_loc, sizeof(globals.Flash.propagation_delay)); eprom_loc = (char *) &(globals.Flash.delay_shrink) - (char *) &(globals.Flash.flash_start); writeUserBlock(&globals.Flash, 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(); Show_Main_Menu(); /* 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(); Show_Main_Menu(); eprom_loc = (char *) (&pwl_amp[index]) - (char *) &(globals.Flash.flash_start); writeUserBlock(&globals.Flash, 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]; short temp2[10]; int index; int max_points,max_polarity,max_ranges; short *pointer_short1; float *pointer_float1; int eprom_loc,size_of_float1,size_of_short1; 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_short1=&globals.Flash.ampl_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.ampl_pwl_amp[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.os_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.os_pwl_amp[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.pw_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.pw_pwl_time[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.delay_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.delay_pwl_time[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.period_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.period_pwl_time[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.burst_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.burst_pwl_time[0][0][0][0]; size_of_short1=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_short1=&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_short1=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_short1=&globals.Flash.slew_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.slew_pwl_time[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.vcc1_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.vcc1_pwl_amp[0][0][0][0]; size_of_short1=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_short1=&globals.Flash.vcc2_pwl_Vc_norm4095[0][0][0][0]; pointer_float1=&globals.Flash.vcc2_pwl_amp[0][0][0][0]; size_of_short1=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_short1=&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_short1=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; iglobals.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) 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_ismallest_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; iglobals.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].offsetmax_os_in_range)) { *point_found=0; /* try higher range if can't satisfy os and ampl both in this range */ } } if ((parameter==pwl_os_values) && globals.Flash.ampl_os_ranges_related[channel]) { for (i=0; iglobals.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)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 (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; /* identify highest range that starts with a cal point less than the setting */ for (range_i=0; range_ismallest_allowed_number && pwl_amp[index]=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); /* 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; } 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_short[points_in_range+1]; int index,actual_pol; float *pointer_y_float; short *pointer_x_short; int eprom_loc,size_of_y_float,size_of_x_short; 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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short=&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_short=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_short[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=0; --i) { 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_short[entry] ) { return CalibrationClosenessError; } if ( word_out==temp_x_short[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_short[i+1]=temp_x_short[i]; } /* add the new data */ temp_y_float[entry+1]=abs_cal_point; temp_x_short[entry+1]=word_out; for (i=0; i<=max_points; ++i) { temp_x_float[i]=(float) temp_x_short[i]; } /* delete a point, if required */ if (total==max_points) { least_integrated_error=1e18; for (i=1; i=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]) 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 count_word_out; int 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, check_valid; for (i=0; i> 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; 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 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, check_valid; for (i=0; i3.0V */ float compensated_new_res; if (globals.ChannelState[0].vcc2 > 0.0) { compensated_new_res = new_res * 3.0/globals.ChannelState[0].vcc2; } else { return amplitude_lower_limit; } int status; 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; i4)) { 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= 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; gchar *lcd_msg = NULL; gchar *prefix = NULL; 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) { prefix = g_strdup_printf ("CH%d PER %d:",caldata->channel+1,i); } else if (caldata->cal_type == pwl_pw_values) { prefix = g_strdup_printf ("CH%d PW %d:",caldata->channel+1,i); } else if (caldata->cal_type == pwl_delay_values) { prefix = g_strdup_printf ("CH%d DLY %d:",caldata->channel+1,i); } lcd_msg = g_strdup_printf ("%s %.3e",prefix,nom_val); LCD_write(2,0,lcd_msg); g_free (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."); lcd_msg = g_strdup_printf ("%s %.3e -> %.3e",prefix,nom_val,meas); LCD_write(2,0,lcd_msg); g_free (lcd_msg); lcd_msg = g_strdup_printf ("changed %6.2f%%, err: %d",change,status); LCD_write(3,0,lcd_msg); g_free (lcd_msg); g_free (prefix); g_usleep (2e6); } } return OK; } void cal_string(char *parameter, CalStruct *caldata) { gchar *string = g_strdup_printf ("CH%d %s cal: %d errors. Adj: %6.2f%% max, %6.2f%% avg.\r\n", caldata->channel+1,parameter, caldata->error, caldata->max_change, caldata->avg_change); g_string_append (caldata->response, string); g_free (string); } int self_cal() { CalStruct caldata; int status = do_full_self_cal(&caldata); g_string_free (caldata.response, TRUE); return status; } int do_full_self_cal(CalStruct *caldata) { gchar *string; long start_timer, diff_timer; int eprom_loc; caldata->response = g_string_new (""); Menu_Clear_Buttons(); LCD_clear(); /*0123456789012345678901234567890123456789*/ LCD_write(0,0,"Self-calibration in progress."); /*0123456789012345678901234567890123456789*/ string = g_strdup_printf ("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); g_free (string); while ((sec_timer() - globals.Timers.startup_timer_value) < (long)globals.Flash.self_cal_pause) { /*0123456789012345678901234567890123456789*/ string = g_strdup_printf ("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_free (string); g_usleep (2e5); } start_timer = sec_timer(); 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."); string = g_strdup_printf ("%d errors. Max change: %6.2f%%", caldata->total_errors, caldata->total_max_change); LCD_write(1,0,string); g_free (string); LCD_write(2,0,"More details are provided by \"cal?\""); g_usleep (3e6); Show_Main_Menu(); 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); string = g_strdup_printf ("Completed in %d minutes and %d seconds\r\n", globals.Flash.self_cal_typical_time_min, globals.Flash.self_cal_typical_time_sec); g_string_append (caldata->response, string); g_free (string); eprom_loc = (char *) &(globals.Flash.self_cal_typical_time_min) - (char *) &(globals.Flash.flash_start); writeUserBlock(&globals.Flash, 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(&globals.Flash, eprom_loc, sizeof(globals.Flash.self_cal_typical_time_sec)); if (caldata->total_errors) { return SelfCalError; } else { return OK; } } 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 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=0; --i) { globals.ChannelState[i].route_primary=globals.Flash.rcl_route_primary[i][setting_num]; globals.ChannelState[i].route_secondary=globals.Flash.rcl_route_secondary[i][setting_num]; globals.ChannelState[i].frequency=globals.Flash.rcl_frequency[i][setting_num]; globals.ChannelState[i].delay=globals.Flash.rcl_delay[i][setting_num]; globals.ChannelState[i].pw=globals.Flash.rcl_pw[i][setting_num]; globals.ChannelState[i].amplitude=globals.Flash.rcl_amplitude[i][setting_num]; globals.ChannelState[i].offset=globals.Flash.rcl_offset[i][setting_num]; globals.ChannelState[i].burst_count=globals.Flash.rcl_burst_count[i][setting_num]; globals.ChannelState[i].burst_time=globals.Flash.rcl_burst_time[i][setting_num]; globals.ChannelState[i].rise_time=globals.Flash.rcl_rise_time[i][setting_num]; globals.ChannelState[i].slew=globals.Flash.rcl_slew[i][setting_num]; globals.ChannelState[i].vcc1=globals.Flash.rcl_vcc1[i][setting_num]; globals.ChannelState[i].vcc2=globals.Flash.rcl_vcc2[i][setting_num]; globals.ChannelState[i].vlogic=globals.Flash.rcl_vlogic[i][setting_num]; globals.ChannelState[i].soft_current_limit=globals.Flash.rcl_soft_current_limit[i][setting_num]; globals.ChannelState[i].load_type=globals.Flash.rcl_load[i][setting_num]; temp=globals.Flash.rcl_misc[i][setting_num]; if (temp&1) { globals.ChannelState[i].zout=globals.Flash.zout_max[i]; } else { globals.ChannelState[i].zout=globals.Flash.zout_min[i]; } globals.ChannelState[i].hold_setting = (temp >> 1) & 1; globals.ChannelState[i].double_pulse = (temp >> 2) & 1; globals.ChannelState[i].ab_mode = (temp >> 3) & 1; /* one bit removed */ globals.ChannelState[i].polarity = (temp >> 5) & 1; globals.ChannelState[i].output_state = (temp >> 6) & 1; globals.ChannelState[i].gate_type = (temp >> 7) & 1; globals.ChannelState[i].trigger_source = (temp >> 8) & 7; globals.ChannelState[i].amp_mode = (temp >> 11) & 1; globals.ChannelState[i].gate_level = (temp >> 12) & 1; globals.ChannelState[i].logic_level = (temp >> 14) & 1; globals.ChannelState[i].os_mode = (temp >> 15) & 1; temp=globals.Flash.rcl_misc2[i][setting_num]; /* the high bit of amp_mode was added later; hence the odd reconstruction */ globals.ChannelState[i].amp_mode |= (temp << 1) & 2; globals.ChannelState[i].func_mode = (temp >> 2) & 0x1f; /* 5 bits! */ 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_Pw(0,0,0,i,globals.ChannelState[i].pw,0); 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); if (globals.Flash.voltage_offset_enabled[i] || globals.Flash.current_offset_enabled[i]) { Set_Offset(0,0,0,0,i,globals.ChannelState[i].offset); } 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); Set_Output_State(i,globals.ChannelState[i].output_state); } Menu_Clear_Buttons(); globals.Flags.do_check_settings=YES; /* check for conflicting settings */ Error_check(globals.ChannelState); /* establishes min/max values for queries, but reports no errors */ return; } void Set_Sav(int setting_num) { int temp; int i; for (i=0; i1) & 1) << 0; temp |= globals.ChannelState[i].func_mode << 2; /* 5 bits! */ globals.Flash.rcl_misc2[i][setting_num]=temp; } /* save everything */ writeUserBlock(&globals.Flash, 0, sizeof(globals.Flash)); return; } void Main_update_shift_registers() { static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock (&mutex); /* send MSB first, LSB last */ /* send highest # SR first */ int i,j,n; /* counters */ char data_out; int temp_output_state[max_channels]; /* suppress triggering during relay switching */ if ( globals.Registers.last_relay_driver_settings[0]!=globals.Registers.shift_reg_out[2] || globals.Registers.last_relay_driver_settings[1]!=globals.Registers.shift_reg_out[3]) { start_gate_override (); } /* physically turn off output for amplitude range changes */ /* i.e., short output in 155's */ if (globals.Flags.force_output_fully_off==YES) for (i=0; i<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++i) { temp_output_state[i]=globals.ChannelState[i].output_state; Set_Output_State(i,output_off); g_usleep (1e3 * globals.Timers.normal_relay_bounce_time_in_milliseconds); } bus_setpin(out_CLOCK_LINE, 1); bus_setpin(out_STROBE_LINE, 0); for (i=(num_out_SRs-1); i>=0; --i) { switch (i) { case 0: case 1: n=8; break; case 2: case 3: n=20; /* 20 bit shift registers - UCN5812s */ break; } for (j=n-1; j>=0; --j) { /* send MSB first, LSB last */ bus_setpin(out_CLOCK_LINE, 0); data_out = (char) (1 & (globals.Registers.shift_reg_out[i]>>j)); bus_setpin(out_DATA_LINE, data_out); bus_setpin(out_CLOCK_LINE, 1); } } bus_setpin(out_STROBE_LINE, 1); // latch the data bus_setpin(out_STROBE_LINE, 0); // release latch for (i=0; i<8; ++i) { /* load the upper-nibble latch */ bus_writebyte ((uint8_t) (Octal_DACportCS_high), (uint8_t) (globals.Registers.parallel_DAC_reg[i] >> 8)); /* write lower byte (with address data), and force transfer of latched nibble */ bus_writebyte ((uint8_t) (Octal_DACportCS_low + i), (uint8_t) (globals.Registers.parallel_DAC_reg[i] & 255)); } /* keep trigger suppressed for a time (normally 5ms) after a relay update */ if ( globals.Registers.last_relay_driver_settings[0]!=globals.Registers.shift_reg_out[2] || globals.Registers.last_relay_driver_settings[1]!=globals.Registers.shift_reg_out[3] || globals.Flags.force_output_fully_off==YES) { g_usleep (1e3 * globals.Timers.Relay_Switching_Delay_in_Milliseconds); } /* restore output if required */ if (globals.Flags.force_output_fully_off==YES) for (i=0; i<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++i) { Set_Output_State(i,temp_output_state[i]); g_usleep (1e3 * globals.Timers.normal_relay_bounce_time_in_milliseconds); globals.Flags.force_output_fully_off=NO; } stop_gate_override (); globals.Timers.Relay_Switching_Delay_in_Milliseconds=globals.Timers.normal_relay_bounce_time_in_milliseconds; /* restore default delay */ /* save relay data for comparision next time */ globals.Registers.last_relay_driver_settings[0]=globals.Registers.shift_reg_out[2]; globals.Registers.last_relay_driver_settings[1]=globals.Registers.shift_reg_out[3]; // reset update sensors globals.Changes.update_os = 0; globals.Changes.update_amp = 0; globals.Changes.update_zout = 0; globals.Changes.update_load = 0; g_static_mutex_unlock (&mutex); } int IO_Setup_RS232(int baud, char hardhand, gboolean update_flash) { FILE* configfile = fopen("/tmp/instgettyopts", "w"); if(configfile) { fprintf(configfile, "OPTS=-L %s\n", hardhand ? "-h" : ""); fprintf(configfile, "BAUD=%d\n", baud); fclose(configfile); system("systemctl --no-block restart inst-getty@ttyO5.service"); } globals.Flash.baud = baud; globals.Flash.hardhand = hardhand; if (update_flash) { int size = sizeof(globals.Flash.baud) + sizeof(globals.Flash.parity) + sizeof(globals.Flash.stopbits) + sizeof(globals.Flash.databits) + sizeof(globals.Flash.hardhand) + sizeof(globals.Flash.echo); int eprom_loc = (char *) &(globals.Flash.baud) - (char *) &(globals.Flash.flash_start); writeUserBlock(&globals.Flash, eprom_loc, size); } return OK; } // this is a conversation handler for pam, it basically sends the password when pam asks for it static int conversation(int num_msg, const struct pam_message **msgs, struct pam_response **resp, void *appdata_ptr) { struct pam_response* responses = calloc(num_msg, sizeof(struct pam_response)); if (!responses) { return PAM_CONV_ERR; } int i; // not compiling in gnu99 mode? for (i = 0; i < num_msg; i++) { const struct pam_message *msg = msgs[i]; struct pam_response* response = &(responses[i]); switch (msg->msg_style) { case PAM_PROMPT_ECHO_OFF: response->resp = strdup((char*) appdata_ptr); if (!response->resp) { return PAM_CONV_ERR; } break; default: return PAM_CONV_ERR; } response->resp_retcode = 0; } *resp = responses; return PAM_SUCCESS; } static gboolean checkpassword(const char* username, char* password) { struct pam_conv pam_conversation = { conversation, password }; pam_handle_t* pamh; if (pam_start("passwd", username, &pam_conversation, &pamh) != PAM_SUCCESS) { return FALSE; } if (pam_authenticate(pamh, 0) != PAM_SUCCESS) { return FALSE; } // we only want to check the password and not actually start a session, so get out of here pam_end(pamh, 0); return TRUE; } int change_password(gchar *old_password, gchar *new_password) { gboolean old_valid = TRUE; char* user = "admin"; // Skip password check if the supplied old_password is NULL. This // only happens when resetting the password to the default. if (old_password != NULL ) { old_valid = checkpassword(user,old_password); } if (old_valid == TRUE) { struct lu_context *ctx; struct lu_error *error = NULL; struct lu_ent *ent; ctx = lu_start(user, lu_user, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (ctx == NULL ) { return password_change_error; } ent = lu_ent_new(); if (lu_user_lookup_name(ctx, user, ent, &error) == FALSE) { return password_change_error; // user doesn't exist } if (lu_user_setpass(ctx, ent, new_password, FALSE, &error) == FALSE) { return password_change_error; } lu_end(ctx); return OK; } else { return password_change_error; } }