/* 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 "globals.h"
#include "dummy_functions.h"
#include "lcd.h"

/*** EndHeader */

/* FIXME */
int Error_Screen=NO;

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:
		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:
	case CalibrationClosenessError:
	case CalibrationRangeError:
	case CalibrationPolarityError:
	case Soft_Limit_Exceeded:
	case SelfCalError:
		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.number_of_errors<error_queue_length) {
		++globals.number_of_errors;
		globals.error_queue[globals.number_of_errors]=error_num;
	} else {
		globals.error_queue[globals.number_of_errors]=queue_overflow;
	}

	return;
}



/*----------------------------------------------------------------------------------------------------------*/
void queue_error_and_get_text(gchar** response, int error_num)
{
	*response[0]=0;
	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)
{
	*response[0]=0;
	if (error_num == OK) {
		return;
	}
	queue_error_and_get_text(response, error_num);
	Menu_Refresh();
	return;
}


void queue_error_for_gpib_only(int error_num);

void queue_error_for_gpib_only(int error_num)
{
// not part of this project, but left in for coder's reference. Can be deleted for now
	if (error_num == OK) {
		return;
	}
	queue_error(error_num);
	return;
}


void queue_error_and_display_on_LCD(int error_num);

void queue_error_and_display_on_LCD(int error_num)
{
	gchar* response = NULL;
	queue_error_and_get_text(&response, error_num);
	LCD_display_error_message (response);
}


void queue_and_broadcast_sensor_alarm(int error_num);

void queue_and_broadcast_sensor_alarm(int error_num)
{
// not part of this project, but left in for coder's reference. Can be deleted for now
}

/*----------------------------------------------------------------------------------------------------------*/
void Error_Remove_From_Queue(void)
{
	int i;
	for (i=1; i<globals.number_of_errors; ++i) {
		globals.error_queue[i]=globals.error_queue[i+1];
	}
	--globals.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\"\n", 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 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 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 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 PW_Exceeds_Double_Separation:
		format_error_text(response,-221,"PW can not exceed double pulse separation.");
		break;

	case Double_Separation_Too_Large:
		format_error_text(response,-221,"Double pulse separation is too high. It must be < 95% of the period.");
		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. The output has been turned off.");
		break;

	case Overtemp_Detected:
		format_error_text(response,-300,"Overheating problem. The output has been turned off.");
		break;

	case Overvolt_Detected:
		format_error_text(response,-300,"Over-voltage or over-current! The output has been turned off.");
		break;

	case Soft_Limit_Exceeded:
		format_error_text(response,-300,"Monitor current limit exceeded! The output has been turned off.");
		break;

	case Device_Specific_Aux_Error_Detected:
		// replace with "FIXME" if Flash not implemented yet
		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 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:
		format_error_text(response,-340,"Would prevent operation at the minimum or maximum settings.");
		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 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 PW_Distort_Error:
		format_error_text(response,-240,"Not possible with the current PW distortion settings.");
		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 password_change_error:
		format_error_text(response,-222,"Incorrect old password, or new password is too long or short. ");
		break;

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

}