/* START LIBRARY DESCRIPTION *********************************************
ERRCHK.LIB
	Copyright (c) 2006, Avtech Electrosystems Ltd.

DESCRIPTION:
	Error-checking and reporting functions.

SUPPORT LIB'S:
END DESCRIPTION **********************************************************/


/*** BeginHeader Error_check */

#include <string.h>
#include <glib/gprintf.h>
#include <glib.h>
#include <math.h>
#include "globals.h"
#include "lcd.h"
#include "error_utils.h"
#include "menus.h"
#include "gpib.h"
#include "device-functions.h"

/*** EndHeader */

void set_gpib_error_flags (int error_num);

void set_gpib_error_flags (int error_num)
{

	if (error_num == OK) {
		return;
	}

	/* set the error flags in the GPIB ESR register right away */
	switch (error_num) {
	case AsyncModeDisabled:
	case Unrecognized:
	case SyntaxError:
	case UnknownUnits:
	case InvalidChannel:
	case ThisShouldntHappen:
	case obsolete_feature:
	case config_too_large:
	case config_cant_be_negative:
		GPIB_Set_Command_Error();
		break;
	case query_error_interrupted:
	case query_error_unterminated:
		GPIB_Set_Query_Error();
		break;
	case Overload_Detected:
	case Overtemp_Detected:
	case Overvolt_Detected:
	case Device_Specific_Aux_Error_Detected:
	case queue_overflow:
	case CalibrationPercentError:
	case CalibrationZeroError:
	case CalibrationMinMaxError_ampl:
        case CalibrationMinMaxError_pw:
        case CalibrationMinMaxError_os:
        case CalibrationMinMaxError_freq:
        case CalibrationMinMaxError_delay:
        case CalibrationMinMaxError_burst:
        case CalibrationMinMaxError_rise:
        case CalibrationMinMaxError_slew:
	case CalibrationClosenessError:
	case CalibrationRangeError:
	case CalibrationPolarityError:
	case Soft_Limit_Exceeded:
	case SelfCalError:
	case NetworkNotFound:
	case Startup_Not_Finished:
	case GPIB_missing:
	case Between_0_and_10_Volts:
		GPIB_Set_Device_Dependent_Error();
		break;
	default:
		GPIB_Set_Execution_Error();
		break;
	}

	return;
}

void queue_error(int error_num);

void queue_error(int error_num)
{
	if (error_num == OK) {
		return;
	}

	set_gpib_error_flags (error_num);
	if (globals.Errors.number_of_errors<error_queue_length) {
		++globals.Errors.number_of_errors;
		globals.Errors.error_queue[globals.Errors.number_of_errors]=error_num;
	} else {
		globals.Errors.error_queue[globals.Errors.number_of_errors]=queue_overflow;
	}

	return;
}



/*----------------------------------------------------------------------------------------------------------*/
void queue_error_and_get_text(gchar** response, int error_num)
{
	g_assert (*response == NULL);

	if (error_num == OK) {
		return;
	}

	queue_error (error_num);
	get_error_text (response, error_num);
	return;
}

/*----------------------------------------------------------------------------------------------------------*/
void queue_error_from_parser(gchar** response, int error_num)
{
	g_assert (*response == NULL);

	if (error_num == OK) {
		return;
	}

	queue_error_and_get_text(response, error_num);
	Show_Main_Menu();
	return;
}


void queue_error_for_gpib_only(int error_num)
{
	if (error_num == OK) {
		return;
	}

	queue_error(error_num);
	return;
}


void queue_error_and_display_on_LCD(int error_num)
{
	if (error_num == OK) {
		return;
	}

	gchar* response = NULL;
	queue_error_and_get_text(&response, error_num);
	LCD_display_extended_message (response, TRUE, TRUE);
	g_free (response);
}

extern void send_message(gchar* message);

void queue_and_broadcast_sensor_alarm(int error_num)
{
	if (error_num == OK) {
		return;
	}

	gchar* response = NULL;
	queue_error_and_get_text(&response, error_num);
	LCD_display_extended_message (response, TRUE, TRUE);

	gchar *broadcast_str = g_strdup_printf ("%s\r\n> ", response);
	send_message(broadcast_str);
	g_free (broadcast_str);

	g_free (response);
}


/*----------------------------------------------------------------------------------------------------------*/
void Error_Remove_From_Queue(void)
{
	int i;
	for (i=1; i<globals.Errors.number_of_errors; ++i) {
		globals.Errors.error_queue[i]=globals.Errors.error_queue[i+1];
	}
	--globals.Errors.number_of_errors; 	/* error reported, so remove it from the error queue */
}


void format_error_text (gchar **response, int error_type, char *in);

void format_error_text (gchar **response, int error_type, char *in)
{
	char* prefix = NULL;

	switch (error_type) {
	case 0:
		prefix = g_strdup("No error");
		break;
	case -100:
		prefix=g_strdup("Command error");
		break;
	case -102:
		prefix=g_strdup("Syntax error");
		break;
	case -114:
		prefix=g_strdup("Command error");
		break;
	case -131:
		prefix=g_strdup("Invalid suffix");
		break;
	case -200:
		prefix=g_strdup("Execution error");
		break;
	case -221:
		prefix=g_strdup("Settings conflict");
		break;
	case -222:
		prefix=g_strdup("Data out of range");
		break;
	case -224:
		prefix=g_strdup("Illegal parameter value");
		break;
	case -240:
		prefix=g_strdup("Hardware error");
		break;
	case -300:
		prefix=g_strdup("Device-specific error");
		break;
	case -340:
		prefix=g_strdup("Calibration failed");
		break;
	case -350:
		prefix=g_strdup("Queue overflow");
		break;
	case -400:
		prefix=g_strdup("Query error");
		break;
	default:
		prefix=g_strdup("System error");
		break;
	}


	*response = g_strdup_printf("%d, \"%s; %s\"", error_type, prefix, in);
	g_free(prefix);
}


void get_error_text(gchar **response, int error_num)
{
	switch (error_num) {

	case OK:
		format_error_text(response,0,"");
		break;

	case Unrecognized:
		format_error_text(response,-102,"Unrecognized command.");
		break;

	case AsyncModeDisabled:
		format_error_text(response,-102,"Async gating not available.");
		break;

	case SyntaxError:
		format_error_text(response,-100,"Recognized command, but improper syntax.");
		break;

	case InvalidChannel:
		format_error_text(response,-114,"Invalid channel suffix.");
		break;

	case OutOfRange:
		format_error_text(response,-222,"Too high or too low.");
		break;

	case Negative_Not_Allowed:
		format_error_text(response,-222,"Negative value not allowed.");
		break;

	case IllegalParameter:
	case rise_time_confined_values:
	case amplitude_confined_values:
		format_error_text(response,-224,"Not in list of allowed values.");
		break;

	case UnknownUnits:
		format_error_text(response,-131,"Unrecognized units.");
		break;

	case Route_Range_Error:
		format_error_text(response,-224,"Ranges are not supported.");
		break;

	case AB_Mode_Error:
		format_error_text(response,-221,"This PW mode is not valid for the current trigger mode.");
		break;

	case Valid_For_RS232_TELNET_Only:
		format_error_text(response,-221,"Command valid in RS232 or TELNET modes only.");
		break;

	case PW_Exceeds_Period:
		format_error_text(response,-221,"PW can not exceed period.");
		break;

	case Delay_Exceeds_95Period:
		format_error_text(response,-221,"Delay can not exceed 95% of period.");
		break;

	case NeedNonZeroAmpl:
		format_error_text(response,-222,"Amplitude must be non-zero.");
		break;

	case freq_lower_limit:
		format_error_text(response,-222,"PRF too low.");
		break;

	case freq_upper_limit:
		format_error_text(response,-222,"PRF too high.");
		break;

	case pw_lower_limit:
		format_error_text(response,-222,"PW too low.");
		break;

	case pw_upper_limit:
		format_error_text(response,-222,"PW too high.");
		break;

	case pw_rc_limit:
		format_error_text(response,-222,"PW exceeds RC limit.");
		break;

	case HVPS_Current_Too_High:
		format_error_text(response,-222,"HVPS current too high.");
		break;

	case max_rise_time_error:
		format_error_text(response,-222,"Rise time too high.");
		break;

	case min_rise_time_error:
		format_error_text(response,-222,"Rise time too low.");
		break;

	case max_slew_error:
		format_error_text(response,-222,"Slew rate too high.");
		break;

	case min_slew_error:
		format_error_text(response,-222,"Slew rate too low.");
		break;

	case max_load_type_error:
		format_error_text(response,-222,"Resistance too high.");
		break;

	case min_load_type_error:
		format_error_text(response,-222,"Duty cycle too high or load resistance too low.");
		break;

	case max_soft_current_limit_error:
		format_error_text(response,-222,"Current limit too high.");
		break;

	case min_soft_current_limit_error:
		format_error_text(response,-222,"Current limit too low.");
		break;

	case duty_cycle_upper_limit:
		format_error_text(response,-222,"Duty cycle too high.");
		break;

	case Average_Amplitude_Too_High:
		format_error_text(response,-222,"Average amplitude too high.");
		break;

	case delay_lower_limit:
		format_error_text(response,-222,"Delay too low.");
		break;

	case delay_upper_limit:
		format_error_text(response,-222,"Delay too high.");
		break;

	case amplitude_lower_limit:
		format_error_text(response,-222,"Amplitude too low.");
		break;

	case amplitude_upper_limit:
		format_error_text(response,-222,"Amplitude too high.");
		break;

	case amplitude_gap:
		format_error_text(response,-222,"Amplitude magnitude too low.");
		break;

	case peak_power_limit:
		format_error_text(response,-222,"Peak power too high.");
		break;

	case average_power_limit:
		format_error_text(response,-222,"Average power too high.");
		break;

	case offset_lower_limit:
		format_error_text(response,-222,"Offset too low.");
		break;

	case offset_upper_limit:
		format_error_text(response,-222,"Offset too high.");
		break;

	case ampl_plus_os_lower_limit:
		format_error_text(response,-222,"AMPL+OS too low.");
		break;

	case ampl_plus_os_upper_limit:
		format_error_text(response,-222,"AMPL+OS too high.");
		break;

	case DutyTriggerError:
		format_error_text(response,-221,"Duty cycle can not be set. Set PW instead.");
		break;

	case Double_Separation_Too_Small:
		format_error_text(response,-221,"Double pulse separation too small.");
		break;

	case Double_Separation_Too_Large:
		format_error_text(response,-221,"Double pulse separation too high.");
		break;

	case Cant_Do_Burst_and_Double:
		format_error_text(response,-221,"Can't use burst mode and double pulse mode at the same time.");
                break;

	case queue_overflow:
		format_error_text(response,-350,"Clear with *cls or syst:err.");
		break;

	case query_error_interrupted:
		format_error_text(response,-400,"Data lost in output buffer.");
		break;

	case query_error_unterminated:
		format_error_text(response,-400,"No data to send.");
		break;

	case Overload_Detected:
		format_error_text(response,-300,"Power supply overload detected. Output disabled.");
		break;

	case Overtemp_Detected:
		format_error_text(response,-300,globals.Flash.ot_error_message);
		break;

	case Overvolt_Detected:
		format_error_text(response,-300,globals.Flash.ov_error_message);
		break;

	case Soft_Limit_Exceeded:
		format_error_text(response,-300,"Monitor current limit exceeded. Output disabled.");
		break;

	case Device_Specific_Aux_Error_Detected:
		format_error_text(response,-300,globals.Flash.aux_error_message);
		break;

	case CalibrationPercentError:
		format_error_text(response,-340,"Percent change is too large.");
		break;

	case Between_0_and_10_Volts:
		format_error_text(response,-340,"Must be between 0.0 and 10.0.");
		break;

	case CalibrationPolarityError:
		format_error_text(response,-340,"Old and new polarities disagree.");
		break;

	case CalibrationZeroError:
		format_error_text(response,-340,"Zero point can not be changed.");
		break;

	case CalibrationMinMaxError_ampl:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum amplitude.");
		break;

	case CalibrationMinMaxError_pw:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum pulse width.");
		break;

	case CalibrationMinMaxError_os:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum offset.");
		break;

	case CalibrationMinMaxError_freq:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum frequency.");
		break;

	case CalibrationMinMaxError_delay:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum delay.");
		break;

	case CalibrationMinMaxError_burst:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum burst separation.");
		break;

	case CalibrationMinMaxError_rise:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum rise time.");
		break;

	case CalibrationMinMaxError_slew:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum slew rate.");
		break;



	case CalibrationClosenessError:
		format_error_text(response,-340,"Too few calibration points, or they are too closely spaced.");
		break;

	case CalibrationRangeError:
		format_error_text(response,-340,"Top or bottom of range. Can not be deleted.");
		break;

	case SelfCalError:
		format_error_text(response,-340,"Calibration problem.");
		break;

	case HardwareError:
		format_error_text(response,-240,"Not possible with the current calibration settings.");
		break;

        case GPIB_missing:
                format_error_text(response,-240,"GPIB chip not detected. Defective hardware?");
                break;

	case CalibrationTimingProblem:
		format_error_text(response,-221,"Set timing to allow operation at minimum and maximum amplitudes.");
		break;

	case Coupled_OS_Ampl_Error:
		format_error_text(response,-221,"If ampl > 0, ampl+offset must be > 0, if ampl < 0, ampl+offset must be < 0.");
		break;

	case PRF_limited_by_offset:
		format_error_text(response,-221,"Offset too high for this PRF.");
		break;

	case PW_Distort_Error:
		format_error_text(response,-240,"Not possible with the current PW distortion settings.");
		break;

        case DelayRangeError:
                format_error_text(response,-240,"Gap in possible delay values. Set delay_shrink to zero to override.");
                break;

        case ExternalModeDelayError:
                format_error_text(response,-240,"TRIG-OUT delay not monotonic, boost fixed delay or sync delay.");
                break;

	case burst_duty_error:
		format_error_text(response,-222,"Duty cycle inside burst is too high.");
		break;

	case min_burst_period_error:
		format_error_text(response,-222,"Time between consecutive rising edges inside burst is too low.");
		break;

	case max_burst_count_error:
		format_error_text(response,-222,"Too many pulses per burst.");
		break;

	case min_burst_gap_error:
		format_error_text(response,-222,"Pulse separation too low.");
		break;

	case max_burst_gap_error:
		format_error_text(response,-222,"Pulse separation too high.");
		break;

	case Burst_Exceeds_Period:
		format_error_text(response,-222,"Burst width can not exceed period.");
		break;

        case Dead_Time_Error:
                format_error_text(response,-222,"Insufficient time between end of one pulse and start of next.");
                break;

	case password_change_error:
		format_error_text(response,-222,"Incorrect old password, or new password is too long or short. ");
		break;

	case NetworkNotFound:
		format_error_text(response,-240,"Network not found.");
		break;

	case ThisShouldntHappen:
		format_error_text(response,-200,"Invalid execution path. Programming error.");
		break;

	case Startup_Not_Finished:
		format_error_text(response,-300,"Not ready for commands yet. Still booting up.");
		break;

	case obsolete_feature:
                format_error_text(response,-200,"Obsolete feature enabled. Re-program.");
                break;

	case config_too_large:
                format_error_text(response,-200,"This constant is too large. Reprogram it.");
                break;

	case config_cant_be_negative:
		format_error_text(response,-200,"This constant can't be negative. Reprogram it.");
                break;

	default:
		format_error_text(response,-200,"Specific problem unknown.");
	}

}


void check_initial_min_value (float test_limit, float *running_limit, float proposed_value, int possible_error, int *actual_error) {
	*running_limit = test_limit;

	if ( ((test_limit >= 0.0) && (proposed_value < (*running_limit * 0.999))) ||
		((test_limit < 0.0) && (proposed_value < (*running_limit * 1.001)))) {
		*actual_error = possible_error;
	}
}

void check_another_min_value (float test_limit, float *running_limit, float proposed_value, int possible_error, int *actual_error) {
	if (test_limit > *running_limit) {
		check_initial_min_value (test_limit, running_limit, proposed_value, possible_error, actual_error);
	}
}


void check_initial_max_value (float test_limit, float *running_limit, float proposed_value, int possible_error, int *actual_error) {
	*running_limit = test_limit;

	if ( ((test_limit >= 0.0) && (proposed_value > (*running_limit * 1.001))) ||
		((test_limit < 0.0) && (proposed_value > (*running_limit * 0.999)))) {
		*actual_error = possible_error;
	}
}

void check_another_max_value (float test_limit, float *running_limit, float proposed_value, int possible_error, int *actual_error) {
	if (test_limit < *running_limit) {
		check_initial_max_value (test_limit, running_limit, proposed_value, possible_error, actual_error);
	}
}



int Error_check(ChannelStruct ChannelStateToTest[max_channels])
{
	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);

	float max_duty_high_ampl,max_duty_low_ampl,max_duty_this_ampl;
	float ampl_fixed_max_duty;
	float temp;
	float duty_scale;
	float duty_cycle;
	int report_error = OK;
	gboolean early_quit = FALSE;

	int i;
	int num_of_chan;

	/* todo: check avrq settings */

	num_of_chan=globals.Flash.channels;
	if (num_of_chan==0) {
		num_of_chan=1;
	}


	if (num_of_chan>1) {
		if (!globals.Flash.ChanKey_frequency) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].frequency=ChannelStateToTest[0].frequency;
			}
		if (!globals.Flash.ChanKey_delay) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].delay=ChannelStateToTest[0].delay;
			}
		if (!globals.Flash.ChanKey_pw) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].pw=ChannelStateToTest[0].pw;
			}
		if (!globals.Flash.ChanKey_amplitude) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].amplitude=ChannelStateToTest[0].amplitude;
			}
		if (!globals.Flash.ChanKey_offset) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].offset=ChannelStateToTest[0].offset;
			}

		if (!globals.Flash.ChanKey_Curr_Mon_value) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].Curr_Mon_value=ChannelStateToTest[0].Curr_Mon_value;
			}
		if (!globals.Flash.ChanKey_Curr_Mon_offset) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].Curr_Mon_offset=ChannelStateToTest[0].Curr_Mon_offset;
			}

		if (!globals.Flash.ChanKey_zout) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].zout=ChannelStateToTest[0].zout;
			}
		if (!globals.Flash.ChanKey_hold_setting) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].hold_setting=ChannelStateToTest[0].hold_setting;
			}
		if (!globals.Flash.ChanKey_double_pulse) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].double_pulse=ChannelStateToTest[0].double_pulse;
			}
		if (!globals.Flash.ChanKey_pw) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].pw_ctrl_mode=ChannelStateToTest[0].pw_ctrl_mode;
			}
		if (!globals.Flash.ChanKey_func_mode) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].func_mode=ChannelStateToTest[0].func_mode;
			}
		if (!globals.Flash.ChanKey_inverted) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].inverted=ChannelStateToTest[0].inverted;
			}
		if (!globals.Flash.ChanKey_output_state) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].output_state=ChannelStateToTest[0].output_state;
			}
		if (!globals.Flash.ChanKey_gate_type) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].gate_type=ChannelStateToTest[0].gate_type;
			}
		if (!globals.Flash.ChanKey_trigger_source) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].trigger_source=ChannelStateToTest[0].trigger_source;
			}
		if (!globals.Flash.ChanKey_amp_mode) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].amp_mode=ChannelStateToTest[0].amp_mode;
			}
		if (!globals.Flash.ChanKey_gate_level) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].gate_level=ChannelStateToTest[0].gate_level;
			}
		if (!globals.Flash.ChanKey_load_type) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].load_type=ChannelStateToTest[0].load_type;
			}
		if (!globals.Flash.ChanKey_test_delay_mode) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].test_delay_mode=ChannelStateToTest[0].test_delay_mode;
			}
		if (!globals.Flash.ChanKey_os_mode) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].os_mode=ChannelStateToTest[0].os_mode;
			}
		if (!globals.Flash.ChanKey_Burst_Count) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].burst_count=ChannelStateToTest[0].burst_count;
			}
		if (!globals.Flash.ChanKey_Burst_Time) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].burst_time=ChannelStateToTest[0].burst_time;
			}
		if (!globals.Flash.ChanKey_rise_time) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].rise_time=ChannelStateToTest[0].rise_time;
			}
		if (!globals.Flash.ChanKey_slew) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].slew=ChannelStateToTest[0].slew;
			}
		if (!globals.Flash.ChanKey_current_limit) for (i=1; i<num_of_chan; ++i) {
				ChannelStateToTest[i].soft_current_limit=ChannelStateToTest[0].soft_current_limit;
			}
	}


	// check for non-channel-specific obsolete features
	if ( globals.Flash.enable_avrq_extra_ampls ) {
		report_error = obsolete_feature;
	}


	for (i=0; (i<num_of_chan) && !early_quit; ++i) {
		/* Must be changing a setting */
		globals.Timers.last_activity_at[i] = sec_timer ();

		/* ignore errors if it is in programming mode */
		if (globals.Flash.fully_programmed != All_Programmed) {
			early_quit = TRUE;
			break;
		}

		if (globals.Flags.do_check_settings==NO) {
			early_quit = TRUE;
			break;
		}

		// check for channel-specific obsolete features
		if ( globals.Flash.use_high_ampl_ranges_for_high_pw_ranges[i] ) {
			report_error = obsolete_feature;
		}

		/* check for settings that would cause divide-by-zero errors in the error-checking routine */
		if (ChannelStateToTest[i].frequency<smallest_allowed_number) {
			early_quit = TRUE;
			report_error = freq_lower_limit;
			break;
		}

		if (ChannelStateToTest[i].pw<smallest_allowed_number
		                && globals.Flash.min_pw[i]>0.0) {
			early_quit = TRUE;
			report_error = pw_lower_limit;
			break;
		}

		if (fabs(globals.Flash.ampl_zero_equiv[i] > 2000.0)) {
			report_error = config_too_large;
		}

                if (fabs(globals.Flash.os_zero_equiv[i] > 2000.0)) {
                        report_error = config_too_large;
                }

		if (	(globals.Flash.ampl_zero_equiv[i] < 0.0) ||
			(globals.Flash.os_zero_equiv[i] < 0.0) ||
			(globals.Flash.hvps_avg_curr_limit[i] < 0.0) ||
			(globals.Flash.max_avg_power[i] < 0.0) ) {
			report_error = config_cant_be_negative;
		}

		/* calculate maximum duty cycle based on amplitude and load, for later use */

		max_duty_high_ampl=globals.Flash.max_duty_high[i];
		max_duty_low_ampl=globals.Flash.max_duty_low[i];

		/* Choose highest of 4 duty cycles that meet max ampl limits */
		if (globals.Flash.duty_ampl[i]>0.0 && (fabs(ChannelStateToTest[i].amplitude)<= globals.Flash.duty_ampl[i])) {
			max_duty_this_ampl=max_duty_low_ampl;
		} else {
			max_duty_this_ampl=max_duty_high_ampl;
		}

		if (globals.Flash.duty_ampl_mid1[i]>0.0 &&
		                (fabs(ChannelStateToTest[i].amplitude)<= globals.Flash.duty_ampl_mid1[i]) &&
		                (globals.Flash.max_duty_mid1[i] > max_duty_this_ampl)) {
			max_duty_this_ampl = globals.Flash.max_duty_mid1[i];
		}

		if (globals.Flash.duty_ampl_mid2[i]>0.0 &&
		                (fabs(ChannelStateToTest[i].amplitude)<= globals.Flash.duty_ampl_mid2[i]) &&
		                (globals.Flash.max_duty_mid2[i] > max_duty_this_ampl)) {
			max_duty_this_ampl = globals.Flash.max_duty_mid2[i];
		}

		ampl_fixed_max_duty = max_duty_this_ampl;
		if (globals.Flash.switchable_load[i]) {
			ampl_fixed_max_duty = max_duty_this_ampl * (ChannelStateToTest[i].load_type / globals.Flash.low_load_type[i]);
			temp = globals.Flash.max_high_rl_duty[i];
			if (ampl_fixed_max_duty > temp) {
				ampl_fixed_max_duty = temp;
			}
		}


		/* take burst mode and double-pulse mode into account when setting the maximum duty cycle */
		duty_scale = 100.0; 		/* convert from percent */

		if (ChannelStateToTest[i].double_pulse==double_on) {
			duty_scale = 200.0;
		}
		if (	(ChannelStateToTest[i].burst_count>1)
		                && (globals.Flash.max_burst_count[i]>1)
		                && !globals.Flash.burst_func[i]) {
			duty_scale *= (float) ChannelStateToTest[i].burst_count;
		}


		/* --- check minimum frequency --- */
		check_initial_min_value (globals.Flash.min_freq[i], &globals.Constraints.err_min_freq[i], ChannelStateToTest[i].frequency, freq_lower_limit, &report_error);
		/* ------------------------------- */

		/* --- check maximum frequency --- */
		check_initial_max_value (globals.Flash.max_freq[i], &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, freq_upper_limit, &report_error);

		if ((globals.Flash.max_freq_for_high_ot[i] > 0.0) && (fabs(ChannelStateToTest[i].offset) > globals.Flash.high_ot[i])) {
			check_another_max_value (globals.Flash.max_freq_for_high_ot[i], &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, PRF_limited_by_offset, &report_error);
		}

		check_another_max_value (0.95/fabs(ChannelStateToTest[i].delay), &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, Delay_Exceeds_95Period, &report_error);

		if (globals.Flash.min_pw[i] > 0.0) {

			check_another_max_value (1/ChannelStateToTest[i].pw, &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, PW_Exceeds_Period, &report_error);

			if (		(ChannelStateToTest[i].burst_count>1)
			                && (globals.Flash.max_burst_count[i]>1)
			                && !globals.Flash.burst_func[i]) {
				check_another_max_value (1/(ChannelStateToTest[i].burst_count * (ChannelStateToTest[i].pw+ChannelStateToTest[i].burst_time)),
								&globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, Burst_Exceeds_Period, &report_error);
			}

			check_another_max_value ((1/ChannelStateToTest[i].pw)*(ampl_fixed_max_duty/duty_scale),
							&globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, duty_cycle_upper_limit, &report_error);

			if (ChannelStateToTest[i].double_pulse==double_on) {
				// pulse sep must be less than one half-period
				check_another_max_value (0.5 / ChannelStateToTest[i].delay, &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, Double_Separation_Too_Large, &report_error);
			}

			if ((globals.Flash.max_avg_ampl[i]) > 0.0 && (fabs(ChannelStateToTest[i].amplitude)) > 0.0) {
				temp=100.0 * globals.Flash.max_avg_ampl[i] / (fabs(ChannelStateToTest[i].amplitude) * ChannelStateToTest[i].pw * duty_scale);
				check_another_max_value (temp, &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, Average_Amplitude_Too_High, &report_error);
			}

			if ((globals.Flash.hvps_avg_curr_limit[i] > 0.0) && (fabs(ChannelStateToTest[i].amplitude) > 0.0) && (ChannelStateToTest[i].pw > 0.0)) {
				temp=(100.0 / duty_scale) * globals.Flash.hvps_avg_curr_limit[i] * ChannelStateToTest[i].load_type /
				     (fabs(ChannelStateToTest[i].amplitude) * ChannelStateToTest[i].pw);
				check_another_max_value (temp, &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, HVPS_Current_Too_High, &report_error);
			}

			if (globals.Flash.max_avg_power[i] > 0.0) {
				temp = (globals.Flash.max_avg_power[i] * ChannelStateToTest[i].load_type) / (ChannelStateToTest[i].amplitude * ChannelStateToTest[i].amplitude * ChannelStateToTest[i].pw);
				check_another_max_value (temp, &globals.Constraints.err_max_freq[i], ChannelStateToTest[i].frequency, average_power_limit, &report_error);
			}
		}
		/* ------------------------------- */


		/* --- check minimum pulse width --- */
		check_initial_min_value (globals.Flash.min_pw[i], &globals.Constraints.err_min_pw[i], ChannelStateToTest[i].pw, pw_lower_limit, &report_error);
		/* ------------------------------- */


		/* --- check maximum pw ---------- */
		check_initial_max_value (globals.Flash.max_pw[i], &globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, pw_upper_limit, &report_error);

		/* polarity overrides */
		if ((ChannelStateToTest[i].amplitude >= 0.0) && (globals.Flash.max_pw_pol[i][0] > 0.0)) {
			check_another_max_value (globals.Flash.max_pw_pol[i][0], &globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, pw_upper_limit, &report_error);
		} else if ((ChannelStateToTest[i].amplitude <0.0) && (globals.Flash.max_pw_pol[i][1] > 0.0)) {
			check_another_max_value (globals.Flash.max_pw_pol[i][1], &globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, pw_upper_limit, &report_error);
		}

		// RC limit, as per AVR-8F-B
		if (globals.Flash.cap_for_pw_rc_limit[i] > 0.0) {
			check_another_max_value (globals.Flash.cap_for_pw_rc_limit[i] * ChannelStateToTest[i].load_type, 
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, pw_rc_limit, &report_error);
		}

		if (ChannelStateToTest[i].double_pulse==double_on) {
			check_another_max_value ((ChannelStateToTest[i].delay - globals.Flash.double_pulse_extra_deadtime[i]) / (1.0 + globals.Flash.double_pulse_extra_pw_margin[i]),
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, Double_Separation_Too_Small, &report_error);
			if (ChannelStateToTest[i].burst_count>1) {
				report_error=Cant_Do_Burst_and_Double;
			}
		}

		check_another_max_value ((1/ChannelStateToTest[i].frequency) - globals.Flash.dead_time[i],
						&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, Dead_Time_Error, &report_error);

		check_another_max_value (1/ChannelStateToTest[i].frequency, &globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, PW_Exceeds_Period, &report_error);

		if (		(ChannelStateToTest[i].burst_count>1)
		                && (globals.Flash.max_burst_count[i]>1)
		                && !globals.Flash.burst_func[i]) {

			check_another_max_value ((1/ChannelStateToTest[i].frequency)/ChannelStateToTest[i].burst_count - ChannelStateToTest[i].burst_time,
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, Burst_Exceeds_Period, &report_error);
		}

		check_another_max_value ((1/ChannelStateToTest[i].frequency)*(ampl_fixed_max_duty/duty_scale),
						&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, duty_cycle_upper_limit, &report_error);

		if ((globals.Flash.max_avg_ampl[i]) > 0.0 && (fabs(ChannelStateToTest[i].amplitude)) > 0.0) {
			check_another_max_value (100.0 * globals.Flash.max_avg_ampl[i] / (fabs(ChannelStateToTest[i].amplitude) * ChannelStateToTest[i].frequency * duty_scale),
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, Average_Amplitude_Too_High, &report_error);
		}

		if ((globals.Flash.hvps_avg_curr_limit[i] > 0.0) && (fabs(ChannelStateToTest[i].amplitude) > 0.0) && (ChannelStateToTest[i].frequency > 0.0)) {
			check_another_max_value ((100.0 / duty_scale) * globals.Flash.hvps_avg_curr_limit[i] * ChannelStateToTest[i].load_type /
							(fabs(ChannelStateToTest[i].amplitude) * ChannelStateToTest[i].frequency),
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, HVPS_Current_Too_High, &report_error);
		}

		if (globals.Flash.max_avg_power[i] > 0.0) {
			check_another_max_value (globals.Flash.max_avg_power[i] * ChannelStateToTest[i].load_type /
							(ChannelStateToTest[i].amplitude * ChannelStateToTest[i].amplitude * ChannelStateToTest[i].frequency),
							&globals.Constraints.err_max_pw[i], ChannelStateToTest[i].pw, average_power_limit, &report_error);
		}

		/* ------------------------------- */

		/* --- check minimum delay ------- */
		if (globals.Flash.min_delay[i] != 0.0) {
			/* use programmed limit, if non-zero */
			temp=globals.Flash.min_delay[i];
		} else {
			/* otherwise, assume delay has equal +/- range */
			temp=-globals.Flash.max_delay[i];

			/* for dual-delay units, positive delay only for second channel */
			if ((globals.Flash.ChanKey_delay?globals.Flash.channels:1)>1) {
				if (i>0) {
					temp=0.0;
				}
			}
		}
		check_initial_min_value (temp, &globals.Constraints.err_min_delay[i], ChannelStateToTest[i].delay, delay_lower_limit, &report_error);

		check_another_min_value (-0.95/ChannelStateToTest[i].frequency, &globals.Constraints.err_min_delay[i], ChannelStateToTest[i].delay, Delay_Exceeds_95Period, &report_error);

		if (ChannelStateToTest[i].double_pulse==double_on) {

			check_another_min_value (globals.Flash.double_pulse_min_sep[i], 
							&globals.Constraints.err_min_delay[i], ChannelStateToTest[i].delay, Double_Separation_Too_Small, &report_error);

			check_another_min_value (ChannelStateToTest[i].pw * (1.0 + globals.Flash.double_pulse_extra_pw_margin[i]) + globals.Flash.double_pulse_extra_deadtime[i],
							&globals.Constraints.err_min_delay[i], ChannelStateToTest[i].delay, Double_Separation_Too_Small, &report_error);
		}
		/*	------------------------------- */

		/* --- check maximum delay ------- */
		check_initial_max_value (globals.Flash.max_delay[i], &globals.Constraints.err_max_delay[i], ChannelStateToTest[i].delay, delay_upper_limit, &report_error);

		check_another_max_value (0.95/ChannelStateToTest[i].frequency, &globals.Constraints.err_max_delay[i], ChannelStateToTest[i].delay, Delay_Exceeds_95Period, &report_error);

		if (ChannelStateToTest[i].double_pulse==double_on) {
			// one half-period
			check_another_max_value (0.5 / ChannelStateToTest[i].frequency, &globals.Constraints.err_max_delay[i], ChannelStateToTest[i].delay, Double_Separation_Too_Large, &report_error);
		}
		/* ------------------------------- */

		// calculate duty cycle for later use
		duty_cycle=ChannelStateToTest[i].pw*ChannelStateToTest[i].frequency*100.0;	/* calculate duty cycle */

		/* disable amplitude checks if amplitude calibration is in progress */
		if (!globals.Flags.extended_ampl_min_max) {

			/* --- check fixed amplitudes ---- */

			float min_fixed_ampl, max_fixed_ampl;
			min_fixed_ampl = max_fixed_ampl = 0.0;

			gboolean uses_fixed_ampl;
			uses_fixed_ampl = (number_of_fixed_ampl_points(i)>0);

			if (uses_fixed_ampl) {
				get_min_max_fixed_ampls (i, &min_fixed_ampl, &max_fixed_ampl);

				if (!fixed_ampl_ok (i, ChannelStateToTest[i].amplitude)) {
					report_error=amplitude_confined_values;
				}
			}
			/* ------------------------------- */


			/* --- check gaps in ampl range, AVRQ -AHV/-XHV ---- */
			if (non_zero_first_ampl_point(i)) {
				if (fabs(ChannelStateToTest[i].amplitude) < globals.Flash.ampl_zero_equiv[i]) {
					report_error=amplitude_gap;
				}
			}

			/* ------------------------------------------------- */



			/* --- check minimum amplitude --- */

			if (uses_fixed_ampl && (min_fixed_ampl > globals.Flash.min_ampl[i])) {
				temp = min_fixed_ampl;
			} else {
				temp = globals.Flash.min_ampl[i];
			}
			check_initial_min_value (temp, &globals.Constraints.err_min_ampl[i], ChannelStateToTest[i].amplitude, amplitude_lower_limit, &report_error);

			check_another_min_value (globals.Flash.min_vout[i]-ChannelStateToTest[i].offset,
							&globals.Constraints.err_min_ampl[i], ChannelStateToTest[i].amplitude, ampl_plus_os_lower_limit, &report_error);

			/* ------------------------------- */



			/* --- check maximum amplitude --- */
                        if (uses_fixed_ampl && (max_fixed_ampl < globals.Flash.max_ampl[i])) {
                                temp = max_fixed_ampl;
			} else {
                                temp = globals.Flash.max_ampl[i];
			}
			check_initial_max_value (temp, &globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, amplitude_upper_limit, &report_error);

			check_another_max_value (globals.Flash.max_vout[i]-ChannelStateToTest[i].offset,
							&globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, ampl_plus_os_upper_limit, &report_error);

			if (globals.Flash.max_peak_power[i] > 0.0) {
				temp = sqrt(globals.Flash.max_peak_power[i] * ChannelStateToTest[i].load_type);
				// temp is positive at this point
				check_another_max_value (temp, &globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, peak_power_limit, &report_error);

				temp = temp * -1.0;	// check negative possibility
				check_another_min_value (temp, &globals.Constraints.err_min_ampl[i], ChannelStateToTest[i].amplitude, peak_power_limit, &report_error);
			}

			if (globals.Flash.max_avg_power[i] > 0.0) {
				temp = sqrt(globals.Flash.max_avg_power[i] * ChannelStateToTest[i].load_type / (ChannelStateToTest[i].pw  * ChannelStateToTest[i].frequency));
				// temp is positive at this point
				check_another_max_value (temp, &globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, average_power_limit, &report_error);

				temp = temp * -1.0;	// check negative possibility
				check_another_min_value (temp, &globals.Constraints.err_min_ampl[i], ChannelStateToTest[i].amplitude, average_power_limit, &report_error);
			}

			if (globals.Flash.min_pw[i] > 0.0) {
				/* Check average amplitude */
				if (globals.Flash.max_avg_ampl[i] > 0.0) {
					temp = 100.0 * globals.Flash.max_avg_ampl[i] / (ChannelStateToTest[i].frequency * ChannelStateToTest[i].pw * duty_scale);
					// temp is positive at this point
					check_another_max_value (temp, &globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, Average_Amplitude_Too_High, &report_error);

					temp = temp * -1.0;	// check negative possibility
					check_another_min_value (temp, &globals.Constraints.err_min_ampl[i], ChannelStateToTest[i].amplitude, Average_Amplitude_Too_High, &report_error);
				}

				if ((globals.Flash.hvps_avg_curr_limit[i] > 0.0) && (fabs(ChannelStateToTest[i].frequency) > 0.0) && (ChannelStateToTest[i].pw > 0.0)) {
					temp=(100.0 / duty_scale) * globals.Flash.hvps_avg_curr_limit[i] * ChannelStateToTest[i].load_type /
					     (ChannelStateToTest[i].frequency * ChannelStateToTest[i].pw);
					// temp is positive at this point
					check_another_max_value (temp, &globals.Constraints.err_max_ampl[i], ChannelStateToTest[i].amplitude, HVPS_Current_Too_High, &report_error);

					temp = temp * -1.0;	// check negative possibility
					if (temp > globals.Constraints.err_min_ampl[i]) {
						globals.Constraints.err_min_ampl[i]=temp;
						if (ChannelStateToTest[i].amplitude<(1.001*globals.Constraints.err_min_ampl[i])) {
							report_error=HVPS_Current_Too_High;
						}
					}
				}

				if (duty_cycle>(100.0*ampl_fixed_max_duty/duty_scale))
					/* set at crossover voltage */
				{
					// FIXME to use check_ functions
					temp=globals.Flash.duty_ampl[i];

					if (temp<globals.Constraints.err_max_ampl[i]) {
						globals.Constraints.err_max_ampl[i]=temp;
						if (	(		(globals.Constraints.err_max_ampl[i]>=0.0 && ChannelStateToTest[i].amplitude>(1.001*globals.Constraints.err_max_ampl[i]))
						                        || (globals.Constraints.err_max_ampl[i]<0.0 && ChannelStateToTest[i].amplitude>(0.999*globals.Constraints.err_max_ampl[i]))
						     )
						                && (duty_cycle > 1.001*(100.0*max_duty_high_ampl/duty_scale))
						   ) {
							report_error=duty_cycle_upper_limit;
						}
					}
				}

			}

			/* ------------------------------- */


			if ((globals.Flash.voltage_offset_enabled[i]) || (globals.Flash.current_offset_enabled[i])) {
				/* --- check minimum offset ------ */
				check_initial_min_value (globals.Flash.min_offset[i],
									&globals.Constraints.err_min_offset[i], ChannelStateToTest[i].offset, offset_lower_limit, &report_error);

				check_another_min_value (globals.Flash.min_vout[i]-ChannelStateToTest[i].amplitude,
									&globals.Constraints.err_min_offset[i], ChannelStateToTest[i].offset, ampl_plus_os_lower_limit, &report_error);

				/* 1011 models: high level of PG-P output must remain positive */
				// FIXME use new check_ functions?
				if (globals.Flash.ampl_coupled_to_os[i]) {
					if (ChannelStateToTest[i].amplitude>globals.Flash.ampl_zero_equiv[i]) {
						temp=-ChannelStateToTest[i].amplitude;
						if (temp>globals.Constraints.err_min_offset[i]) {
							globals.Constraints.err_min_offset[i]=temp;
							if (ChannelStateToTest[i].offset<=globals.Constraints.err_min_offset[i]) {
								report_error=Coupled_OS_Ampl_Error;
							}
						}
					}
				}

				if (    (globals.Flash.max_freq_for_high_ot[i] > 0.0) &&
					(ChannelStateToTest[i].frequency > globals.Flash.max_freq_for_high_ot[i])) {

					temp = -globals.Flash.high_ot[i];
						if (temp>globals.Constraints.err_min_offset[i]) {
						globals.Constraints.err_min_offset[i]=temp;
						if (ChannelStateToTest[i].offset<=globals.Constraints.err_min_offset[i]) {
							report_error=PRF_limited_by_offset;
						}
					}
				}

				/* ------------------------------- */


				/* --- check maximum offset ------ */
				check_initial_max_value (globals.Flash.max_offset[i],
								&globals.Constraints.err_max_offset[i], ChannelStateToTest[i].offset, offset_upper_limit, &report_error);

				check_another_max_value (globals.Flash.max_vout[i]-ChannelStateToTest[i].amplitude,
								&globals.Constraints.err_max_offset[i], ChannelStateToTest[i].offset, ampl_plus_os_upper_limit, &report_error);

				/* 1011 models: low level of PG-N output must remain negative */
				if (globals.Flash.ampl_coupled_to_os[i]) {
					if (ChannelStateToTest[i].amplitude<-globals.Flash.ampl_zero_equiv[i]) {
						temp=-ChannelStateToTest[i].amplitude;
						if (temp<globals.Constraints.err_max_offset[i]) {
							globals.Constraints.err_max_offset[i]=temp;
							if (ChannelStateToTest[i].offset>=globals.Constraints.err_max_offset[i]) {
								report_error=Coupled_OS_Ampl_Error;
							}
						}
					}
				}

                                if (    (globals.Flash.max_freq_for_high_ot[i] > 0.0) &&
                                        (ChannelStateToTest[i].frequency > globals.Flash.max_freq_for_high_ot[i])) {

                                        temp = globals.Flash.high_ot[i];
                                        if (temp<globals.Constraints.err_max_offset[i]) {
                                                globals.Constraints.err_max_offset[i]=temp;
                                                if (ChannelStateToTest[i].offset>=globals.Constraints.err_max_offset[i]) {
                                                        report_error=PRF_limited_by_offset;
                                                }
                                        }
                                }

				/* ------------------------------- */
			}
		}


		/* --- check for nonsensical negatives ------ */
		if (	ChannelStateToTest[i].frequency<0.0
		                || ((ChannelStateToTest[i].pw<0.0) && (globals.Flash.min_pw[i] > 0.0))
		                || ChannelStateToTest[i].zout<0) {
			report_error=Negative_Not_Allowed;
		}
		/* ------------------------------- */



		/* --- check burst count settings --- */

		if (globals.Flash.max_burst_count[i]>1) {

			/* --- check minimum setting --- */
			if ( (!globals.Flash.burst_func[i] && ChannelStateToTest[i].burst_count<1)
			                ||
			                (globals.Flash.burst_func[i] &&  ChannelStateToTest[i].burst_count<0)) {
				report_error=IllegalParameter;
			}

			/* --- check maximum setting --- */

			globals.Constraints.err_max_burst_count[i]=globals.Flash.max_burst_count[i];

			if (ChannelStateToTest[i].burst_count>globals.Constraints.err_max_burst_count[i]) {
				report_error=max_burst_count_error;
			}


			if (!globals.Flash.burst_func[i]) {
				if (globals.Flash.min_pw[i] > 0.0) {
					temp = (ChannelStateToTest[i].frequency * ampl_fixed_max_duty) /
					       (ChannelStateToTest[i].pw * 100.0);

					if (temp < (float) globals.Constraints.err_max_burst_count[i]) {
						globals.Constraints.err_max_burst_count[i] = (int) temp;
						if (		(ChannelStateToTest[i].burst_count>globals.Constraints.err_max_burst_count[i])
						                && (ChannelStateToTest[i].burst_count>1)) {
							report_error=max_burst_count_error;
						}
					}


					temp = (1.0/ChannelStateToTest[i].frequency) /
					       (ChannelStateToTest[i].pw+ChannelStateToTest[i].burst_time);

					if (temp < (float) globals.Constraints.err_max_burst_count[i]) {
						globals.Constraints.err_max_burst_count[i] = (int) temp;
						if (		(ChannelStateToTest[i].burst_count>globals.Constraints.err_max_burst_count[i])
						                &&	(ChannelStateToTest[i].burst_count>1)) {
							report_error=Burst_Exceeds_Period;
						}
					}
				}


				/* --- check minimum burst gap settings --- */

				// FIXME - update with new check_ routines, but only report error if count>1
				globals.Constraints.err_min_burst_time[i]=globals.Flash.min_burst_gap[i];
				if (		(ChannelStateToTest[i].burst_count>1)
				                && (ChannelStateToTest[i].burst_time<(0.999*globals.Constraints.err_min_burst_time[i]))) {
					report_error=min_burst_gap_error;
				}


				/* --- check minimum burst period settings --- */

				// FIXME - update with new check_ routines, but only report error if count>1
				if (globals.Flash.min_pw[i] > 0.0) {
					temp = globals.Flash.min_burst_per[i] - ChannelStateToTest[i].pw;
					if (temp > globals.Constraints.err_min_burst_time[i]) {
						globals.Constraints.err_min_burst_time[i] = temp;
						if (		(ChannelStateToTest[i].burst_count>1)
						                && (ChannelStateToTest[i].burst_time<(0.999*globals.Constraints.err_min_burst_time[i]))) {
							report_error=min_burst_period_error;
						}
					}

					/* only report error when burst count is > 1, otherwise it gets annoying */
					temp = ChannelStateToTest[i].pw * (100.0/globals.Flash.max_burst_duty[i] - 1.0);
					if (temp > globals.Constraints.err_min_burst_time[i]) {
						globals.Constraints.err_min_burst_time[i] = temp;
						if (		(ChannelStateToTest[i].burst_time<(0.999*globals.Constraints.err_min_burst_time[i]))
						                && (ChannelStateToTest[i].burst_count>1)) {
							report_error=burst_duty_error;
						}
					}
				}

				/* --- check maximum burst gap settings --- */

				// FIXME - update with new check_ routines, but only report error if count>1
				globals.Constraints.err_max_burst_time[i]=globals.Flash.max_burst_gap[i];
				if (	(ChannelStateToTest[i].burst_count>1)
				     && (ChannelStateToTest[i].burst_time>(1.001*globals.Constraints.err_max_burst_time[i]))) {
					report_error=max_burst_gap_error;
				}
			}
		}

		/* --- check rise time settings --- */
		/* disable amplitude checks if calibration is in progress */
		if (!globals.Flash.fixed_rise_time[i])
			if (!globals.Flags.extended_ampl_min_max) {

				if (globals.Flash.rise_time_min_max_only[i]) {
					if ( 	!(fabs(ChannelStateToTest[i].rise_time - globals.Flash.min_rise_time[i]) < smallest_allowed_number )
				                &&
				                !(fabs(ChannelStateToTest[i].rise_time - globals.Flash.max_rise_time[i]) < smallest_allowed_number )
					   ) {
						report_error=rise_time_confined_values;
					}
				}

				check_initial_min_value (globals.Flash.min_rise_time[i], &globals.Constraints.err_min_rise_time[i], ChannelStateToTest[i].rise_time, min_rise_time_error, &report_error);
				check_initial_max_value (globals.Flash.max_rise_time[i], &globals.Constraints.err_max_rise_time[i], ChannelStateToTest[i].rise_time, max_rise_time_error, &report_error);
			}

		/* --- check slew settings --- */
		/* disable amplitude checks if calibration is in progress */
		if (globals.Flash.curr_slew[i])
			if (!globals.Flags.extended_ampl_min_max) {
				check_initial_min_value (globals.Flash.min_slew[i], &globals.Constraints.err_min_slew[i], ChannelStateToTest[i].slew, min_slew_error, &report_error);
				check_initial_max_value (globals.Flash.max_slew[i], &globals.Constraints.err_max_slew[i], ChannelStateToTest[i].slew, max_slew_error, &report_error);
			}

		/* --- check resistance settings --- */

		if (globals.Flash.switchable_load[i]) {
			check_initial_min_value (globals.Flash.low_load_type[i], &globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, min_load_type_error, &report_error);

			if (duty_cycle > max_duty_this_ampl) {
				check_another_min_value (globals.Flash.low_load_type[i] * duty_cycle / max_duty_this_ampl,
								&globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, min_load_type_error, &report_error);
			}
		}

		if (globals.Flash.cap_for_pw_rc_limit[i] > 0.0) {
			check_another_min_value (ChannelStateToTest[i].pw / globals.Flash.cap_for_pw_rc_limit[i], 
							&globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, pw_rc_limit, &report_error);
		}

		if (globals.Flash.hvps_avg_curr_limit[i] > 0.0) {
			check_another_min_value ((duty_scale / 100.0) * fabs(ChannelStateToTest[i].amplitude) * ChannelStateToTest[i].pw * ChannelStateToTest[i].frequency /
							globals.Flash.hvps_avg_curr_limit[i],
							&globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, HVPS_Current_Too_High, &report_error);
		}

		if (globals.Flash.max_peak_power[i] > 0.0) {
			check_another_min_value (ChannelStateToTest[i].amplitude * ChannelStateToTest[i].amplitude / globals.Flash.max_peak_power[i],
							&globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, peak_power_limit, &report_error);
		}

		if (globals.Flash.max_avg_power[i] > 0.0) {
			check_another_min_value ((ChannelStateToTest[i].amplitude * ChannelStateToTest[i].amplitude * ChannelStateToTest[i].pw * ChannelStateToTest[i].frequency) /
							globals.Flash.max_avg_power[i],
							&globals.Constraints.err_min_load_type[i], ChannelStateToTest[i].load_type, average_power_limit, &report_error);
		}

		check_initial_max_value (globals.Flash.high_load_type[i], &globals.Constraints.err_max_load_type[i], ChannelStateToTest[i].load_type, max_load_type_error, &report_error);

		/* --- check soft_current_limit settings --- */
		if (globals.Flash.soft_current_limit_enabled[i]) {
			// FIXME to use new check_ functions

			globals.Constraints.err_min_soft_current_limit[i]=globals.Flash.min_soft_current_limit[i];
			if (ChannelStateToTest[i].soft_current_limit<(0.999*globals.Constraints.err_min_soft_current_limit[i])) {
				report_error=min_soft_current_limit_error;
			}

			globals.Constraints.err_max_soft_current_limit[i]=globals.Flash.max_soft_current_limit[i];

			temp=globals.Flash.current_limit_pulse_mode[i];;
			if (temp < globals.Constraints.err_max_soft_current_limit[i]) {
				globals.Constraints.err_max_soft_current_limit[i] = temp;
			}

			if (ChannelStateToTest[i].func_mode==dc_mode_on) {
				temp=globals.Flash.current_limit_dc_mode[i];
				if (temp < globals.Constraints.err_max_soft_current_limit[i]) {
					globals.Constraints.err_max_soft_current_limit[i] = temp;
				}
			}

			if (ChannelStateToTest[i].soft_current_limit>(1.001*globals.Constraints.err_max_soft_current_limit[i])) {
				report_error=max_soft_current_limit_error;
			}
		}


		/* --- done all per-channel checking ---- */
	}

	// merge min/max values for shared channel variables on multi-channel instruments
	// for example, ampl on CH2 may force lower max freq on all channels

	if (num_of_chan>1) {
		if (!globals.Flash.ChanKey_frequency) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_freq[0] < globals.Constraints.err_min_freq[i]) {
					globals.Constraints.err_min_freq[0] = globals.Constraints.err_min_freq[i];
				}
				if (globals.Constraints.err_max_freq[0] > globals.Constraints.err_max_freq[i]) {
					globals.Constraints.err_max_freq[0] = globals.Constraints.err_max_freq[i];
				}
			}

		if (!globals.Flash.ChanKey_delay) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_delay[0] < globals.Constraints.err_min_delay[i]) {
					globals.Constraints.err_min_delay[0] = globals.Constraints.err_min_delay[i];
				}
				if (globals.Constraints.err_max_delay[0] > globals.Constraints.err_max_delay[i]) {
					globals.Constraints.err_max_delay[0] = globals.Constraints.err_max_delay[i];
				}
			}

		if (!globals.Flash.ChanKey_pw) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_pw[0] < globals.Constraints.err_min_pw[i]) {
					globals.Constraints.err_min_pw[0] = globals.Constraints.err_min_pw[i];
				}
				if (globals.Constraints.err_max_pw[0] > globals.Constraints.err_max_pw[i]) {
					globals.Constraints.err_max_pw[0] = globals.Constraints.err_max_pw[i];
				}
			}

		if (!globals.Flash.ChanKey_amplitude) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_ampl[0] < globals.Constraints.err_min_ampl[i]) {
					globals.Constraints.err_min_ampl[0] = globals.Constraints.err_min_ampl[i];
				}
				if (globals.Constraints.err_max_ampl[0] > globals.Constraints.err_max_ampl[i]) {
					globals.Constraints.err_max_ampl[0] = globals.Constraints.err_max_ampl[i];
				}
			}

		if (!globals.Flash.ChanKey_offset) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_offset[0] < globals.Constraints.err_min_offset[i]) {
					globals.Constraints.err_min_offset[0] = globals.Constraints.err_min_offset[i];
				}
				if (globals.Constraints.err_max_offset[0] > globals.Constraints.err_max_offset[i]) {
					globals.Constraints.err_max_offset[0] = globals.Constraints.err_max_offset[i];
				}
			}

		if (!globals.Flash.ChanKey_load_type) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_load_type[0] < globals.Constraints.err_min_load_type[i]) {
					globals.Constraints.err_min_load_type[0] = globals.Constraints.err_min_load_type[i];
				}
				if (globals.Constraints.err_max_load_type[0] > globals.Constraints.err_max_load_type[i]) {
					globals.Constraints.err_max_load_type[0] = globals.Constraints.err_max_load_type[i];
				}
			}

		if (!globals.Flash.ChanKey_Burst_Count) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_max_burst_count[0] > globals.Constraints.err_max_burst_count[i]) {
					globals.Constraints.err_max_burst_count[0] = globals.Constraints.err_max_burst_count[i];
				}
			}

		if (!globals.Flash.ChanKey_Burst_Time) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_burst_time[0] < globals.Constraints.err_min_burst_time[i]) {
					globals.Constraints.err_min_burst_time[0] = globals.Constraints.err_min_burst_time[i];
				}
				if (globals.Constraints.err_max_burst_time[0] > globals.Constraints.err_max_burst_time[i]) {
					globals.Constraints.err_max_burst_time[0] = globals.Constraints.err_max_burst_time[i];
				}
			}

		if (!globals.Flash.ChanKey_rise_time) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_rise_time[0] < globals.Constraints.err_min_rise_time[i]) {
					globals.Constraints.err_min_rise_time[0] = globals.Constraints.err_min_rise_time[i];
				}
				if (globals.Constraints.err_max_rise_time[0] > globals.Constraints.err_max_rise_time[i]) {
					globals.Constraints.err_max_rise_time[0] = globals.Constraints.err_max_rise_time[i];
				}
			}

		if (!globals.Flash.ChanKey_slew) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_slew[0] < globals.Constraints.err_min_slew[i]) {
					globals.Constraints.err_min_slew[0] = globals.Constraints.err_min_slew[i];
				}
				if (globals.Constraints.err_max_slew[0] > globals.Constraints.err_max_slew[i]) {
					globals.Constraints.err_max_slew[0] = globals.Constraints.err_max_slew[i];
				}
			}

		if (!globals.Flash.ChanKey_current_limit) for (i=1; i<num_of_chan; ++i) {
				if (globals.Constraints.err_min_soft_current_limit[0] < globals.Constraints.err_min_soft_current_limit[i]) {
					globals.Constraints.err_min_soft_current_limit[0] = globals.Constraints.err_min_soft_current_limit[i];
				}
				if (globals.Constraints.err_max_soft_current_limit[0] > globals.Constraints.err_max_soft_current_limit[i]) {
					globals.Constraints.err_max_soft_current_limit[0] = globals.Constraints.err_max_soft_current_limit[i];
				}
			}
	}


	g_static_mutex_unlock (&mutex);

	return report_error;

}