diff options
author | root <root@fedora-arm.domain.avtechpulse.com> | 1999-12-31 19:50:00 -0500 |
---|---|---|
committer | root <root@fedora-arm.domain.avtechpulse.com> | 1999-12-31 19:50:00 -0500 |
commit | 80b991816acb29e645fa7e047325942f8f050861 (patch) | |
tree | d44958d923a3578eaa13bb4432648889b08909a4 | |
parent | 3702b14f594c86af91e063e8b1403e7bfd982bfe (diff) |
add new files
-rw-r--r-- | device-functions.c | 39 | ||||
-rw-r--r-- | device-functions.h | 5 | ||||
-rw-r--r-- | dummy_functions.c | 16 | ||||
-rw-r--r-- | dummy_functions.h | 16 | ||||
-rw-r--r-- | error_utils.c | 521 | ||||
-rw-r--r-- | error_utils.h | 88 | ||||
-rw-r--r-- | globals.c | 8 | ||||
-rw-r--r-- | globals.h | 38 | ||||
-rw-r--r-- | parser.c | 1036 | ||||
-rw-r--r-- | parser.h | 34 | ||||
-rw-r--r-- | string_utils.c | 237 | ||||
-rw-r--r-- | string_utils.h | 12 |
12 files changed, 2050 insertions, 0 deletions
diff --git a/device-functions.c b/device-functions.c new file mode 100644 index 0000000..9422b40 --- /dev/null +++ b/device-functions.c @@ -0,0 +1,39 @@ +#include "device-functions.h"
+
+/* START FUNCTION DESCRIPTION ********************************************
+Set_frequency <DEVFUNC.LIB>
+
+SYNTAX: Set_frequency(int check_possible_only,int word_override,int range_override,int channel,float set_freq)
+
+KEYWORDS:
+
+DESCRIPTION: sets the offset DAC.
+
+RETURN VALUE: error code (zero = OK).
+END DESCRIPTION **********************************************************/
+
+/*----------------------------------------------------------------------------------------------------------*/
+int Set_frequency(int check_possible_only,int word_override,int range_override,int channel,float set_freq)
+{
+ // keep, but ignore, the first 3 parameters for now
+
+ // all this does right now is check the frequency range,
+ // and store the set value.
+
+ /* abandon if high channel selected by user but not enabled by firmware */
+ if (channel && !globals.Flash.ChanKey_frequency) {
+ return InvalidChannel;
+ }
+
+ if (set_freq < 1.0) {
+ return freq_lower_limit;
+ }
+ if (set_freq > 1.0e6) {
+ return freq_upper_limit;
+ }
+
+ globals.ChannelState[channel].frequency=set_freq;
+
+ return OK;
+}
+
diff --git a/device-functions.h b/device-functions.h new file mode 100644 index 0000000..2702753 --- /dev/null +++ b/device-functions.h @@ -0,0 +1,5 @@ +#ifndef DEVICE_FUNCTIONS_H_ +#define DEVICE_FUNCTIONS_H_ +#include "globals.h" +int Set_frequency(int check_possible_only,int word_override,int range_override,int channel,float set_freq); +#endif
\ No newline at end of file diff --git a/dummy_functions.c b/dummy_functions.c new file mode 100644 index 0000000..69bfa15 --- /dev/null +++ b/dummy_functions.c @@ -0,0 +1,16 @@ +#include "dummy_functions.h" + +void Menu_Refresh() {} +void Menu_Update_Display() {} +void GPIB_Set_Command_Error() {} +void GPIB_Set_Query_Error() {} +void GPIB_Set_Device_Dependent_Error() {} +void GPIB_Set_Execution_Error() {} +void break_up_string(char* response, int n, char* r1, char* r2, char* r3) { } +void Main_update_shift_registers() { } +void IO_output_to_comm_bus(char* w, int n) { } //replace with real function +void Error_check(void* p) { } +int query_int(char* resp, int n) +{ + return 0; +} diff --git a/dummy_functions.h b/dummy_functions.h new file mode 100644 index 0000000..27c5872 --- /dev/null +++ b/dummy_functions.h @@ -0,0 +1,16 @@ +#ifndef DUMMY_FUNCTIONS_H_ +#define DUMMY_FUNCTIONS_H_ + +void Menu_Refresh(); +void Menu_Update_Display(); +void GPIB_Set_Command_Error(); +void GPIB_Set_Query_Error(); +void GPIB_Set_Device_Dependent_Error(); +void GPIB_Set_Execution_Error(); +void break_up_string(char* response, int n, char* r1, char* r2, char* r3); +void Main_update_shift_registers(); +void IO_output_to_comm_bus(char* w, int n); +void Error_check(void*); +int query_int(char* resp, int n); + +#endif diff --git a/error_utils.c b/error_utils.c new file mode 100644 index 0000000..56d515a --- /dev/null +++ b/error_utils.c @@ -0,0 +1,521 @@ +/* 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"
+/*** EndHeader */
+
+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;
+ char row0[LCD_cols+1];
+ char row1[LCD_cols+1];
+ char row2[LCD_cols+1];
+
+ char Press_Change_Message[max_output_length]; //!!!
+
+ if (error_num == OK) {
+ return;
+ }
+ queue_error_and_get_text(&response, error_num);
+
+ memset(row0,0,LCD_cols+1);
+ memset(row1,0,LCD_cols+1);
+ memset(row2,0,LCD_cols+1);
+
+ Error_Screen=YES;
+
+ break_up_string (response, LCD_cols, row0, row1, row2);
+
+ LCD_clear();
+ LCD_write(0,0,row0);
+ LCD_write(1,0,row1);
+ LCD_write(2,0,row2);
+ LCD_write(3,0,Press_Change_Message);
+
+ g_free(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.");
+ }
+
+}
+
diff --git a/error_utils.h b/error_utils.h new file mode 100644 index 0000000..a72dc90 --- /dev/null +++ b/error_utils.h @@ -0,0 +1,88 @@ +#ifndef ERROR_UTILS_H_ +#define ERROR_UTILS_H_ + +#include <glib.h> + +/* error codes */ +#define OK 0 +#define Unrecognized 1 +#define SyntaxError 2 +#define OutOfRange 3 +#define UnknownUnits 4 +#define Overload_Detected 5 +#define duty_cycle_upper_limit 6 +#define AB_Mode_Error 7 +#define Valid_For_RS232_TELNET_Only 8 +#define PW_Exceeds_Period 9 +#define Delay_Exceeds_95Period 10 +#define Double_Separation_Too_Large 11 +#define freq_lower_limit 12 +#define freq_upper_limit 13 +#define pw_lower_limit 14 +#define pw_upper_limit 15 +#define delay_upper_limit 16 +#define delay_lower_limit 17 +#define amplitude_lower_limit 18 +#define amplitude_upper_limit 19 +#define offset_lower_limit 20 +#define offset_upper_limit 21 +#define ampl_plus_os_lower_limit 22 +#define ampl_plus_os_upper_limit 23 +#define DutyTriggerError 24 +#define PW_Exceeds_Double_Separation 25 +#define queue_overflow 26 +#define query_error_interrupted 27 +#define IllegalParameter 28 +#define Negative_Not_Allowed 29 +#define query_error_unterminated 30 +#define Overtemp_Detected 31 +#define Overvolt_Detected 32 +#define Device_Specific_Aux_Error_Detected 33 +#define InvalidChannel 34 +#define AsyncModeDisabled 36 +#define CalibrationPercentError 37 +#define NeedNonZeroAmpl 38 +#define amplitude_confined_values 40 +#define HardwareError 41 +#define CalibrationZeroError 42 +#define CalibrationMinMaxError 43 +#define CalibrationClosenessError 44 +#define CalibrationTimingProblem 45 +#define CalibrationRangeError 46 +#define CalibrationPolarityError 47 +#define Coupled_OS_Ampl_Error 48 +#define PW_Distort_Error 49 +#define burst_duty_error 50 +#define min_burst_period_error 51 +#define min_burst_gap_error 52 +#define max_burst_gap_error 53 +#define max_burst_count_error 54 +#define Burst_Exceeds_Period 55 +#define password_change_error 56 +#define min_rise_time_error 57 +#define max_rise_time_error 58 +#define min_soft_current_limit_error 59 +#define max_soft_current_limit_error 60 +#define Average_Amplitude_Too_High 61 +#define Route_Range_Error 64 +#define Soft_Limit_Exceeded 65 +#define min_slew_error 67 +#define max_slew_error 68 +#define min_load_type_error 69 +#define max_load_type_error 70 +#define peak_power_limit 71 +#define average_power_limit 72 +#define SelfCalError 73 + +// BEGIN CUSTOM DEFINES +#define LCD_cols 32 +#define YES 1 +#define NO 0 +// END CUSTOM DEFINES + +void get_error_text(gchar** response, int error_num); +void queue_error_from_parser(gchar** response, int error_num); +void queue_error_and_get_text(gchar** response, int error_num); +void Error_Remove_From_Queue(void); + +#endif
\ No newline at end of file diff --git a/globals.c b/globals.c new file mode 100644 index 0000000..4017cbd --- /dev/null +++ b/globals.c @@ -0,0 +1,8 @@ +#include "globals.h" + +GlobalStruct globals = { + .ChannelState = {0.0}, + .Flash = { "FIXME", (int)1, (char)0, (char)0 }, + .error_queue = {0}, + .number_of_errors = 0 +}; diff --git a/globals.h b/globals.h new file mode 100644 index 0000000..af0e114 --- /dev/null +++ b/globals.h @@ -0,0 +1,38 @@ +#ifndef GLOBALS_H_ +#define GLOBALS_H_ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "error_utils.h" + + +#define error_queue_length 512 +#define max_input_word_length 512 +#define max_commands_in_input 12 +#define max_output_length 512 +#define max_channels 2 + +typedef struct { + float frequency; + // this will be enlarged later +} ChannelStruct; + +typedef struct { + char* aux_error_message; + int channels; + char enable_avrq_extra_ampls; + char ChanKey_frequency; +} FlashStruct; + + +typedef struct { + ChannelStruct ChannelState[max_channels]; + FlashStruct Flash; + int error_queue[error_queue_length+1]; + int number_of_errors; /* how many errors are in the error queue */ +} GlobalStruct; + +extern GlobalStruct globals; + +#endif
\ No newline at end of file diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..cda2bf9 --- /dev/null +++ b/parser.c @@ -0,0 +1,1036 @@ +/* START LIBRARY DESCRIPTION *********************************************
+PARSER.LIB
+ Copyright (c) 1997, Avtech Electrosystems Ltd.
+
+DESCRIPTION:
+ Parser functions.
+
+SUPPORT LIB'S:
+END DESCRIPTION **********************************************************/
+
+
+#include "parser.h"
+#include <glib/gprintf.h>
+
+//STATICS
+static int query_min_max_float (gchar** response, char *parameter, float min_val, float max_val);
+static int query_float (gchar** response, float value);
+static int process_float_param (char *parameter, float *value, float min_val, float max_val, int zero_mode);
+static int check_channel_ok (int channel, int enabled_channels, char chankey);
+static int Parser_id_word(char *id_me, int *channel, int *with_id_code);
+static int Parser_find_commands(int commands[], int command_depth);
+static int Parser_get_unit(char *parameter,char *units);
+static int Parser_channel (int *channel,int with_id_code,int routine_num);
+static int Go_freq_32_33(gchar** response, int channel, char *parameter,char *units,int command_type);
+static int Handle_Units(float *mult,char *units, char *base);
+static int Is_Min_Command(char *text);
+static int Is_Max_Command(char *text);
+static int Go_syst_err_11(gchar** response, int channel, char *parameter,char *units,int command_type);
+static int Go_syst_errcnt66(gchar* response, int channel, char *parameter,char *units,int command_type);
+
+static int Parser_id_word(char *id_me, int *channel, int *with_id_code)
+{
+ int id_code;
+ int set_new_channel;
+
+ set_new_channel=0;
+
+ /* detect channel suffixes in the range of 0-99 */
+ if (isdigit((int) id_me[strlen(id_me)-1])) {
+ set_new_channel=1;
+ *channel=atoi(id_me+strlen(id_me)-1);
+ if (isdigit((int) id_me[strlen(id_me)-2])) {
+ *channel=atoi(id_me+strlen(id_me)-2);
+ id_me[strlen(id_me)-2]=0;
+ } else {
+ id_me[strlen(id_me)-1]=0;
+ }
+ }
+
+
+ if (!strcmp(id_me,"*cls") ) {
+ id_code = 1;
+ } else if (!strcmp(id_me,"*ese") ) {
+ id_code = 2;
+ } else if (!strcmp(id_me,"*esr") ) {
+ id_code = 4;
+ } else if (!strcmp(id_me,"*idn") ) {
+ id_code = 5;
+ } else if (!strcmp(id_me,"*opc") ) {
+ id_code = 6;
+ } else if (!strcmp(id_me,"*rst") ) {
+ id_code = 8;
+ } else if (!strcmp(id_me,"*sre") ) {
+ id_code = 9;
+ } else if (!strcmp(id_me,"*stb") ) {
+ id_code = 10;
+ } else if (!strcmp(id_me,"*tst") ) {
+ id_code = 11;
+ } else if (!strcmp(id_me,"*wai") ) {
+ id_code = 12;
+ } else if (!strcmp(id_me,"system") || !strcmp(id_me,"syst")) {
+ id_code = 13;
+ } else if (!strcmp(id_me,"error") || !strcmp(id_me,"err")) {
+ id_code = 14;
+ } else if (!strcmp(id_me,"version") || !strcmp(id_me,"vers")) {
+ id_code = 15;
+ } else if (!strcmp(id_me,"status") || !strcmp(id_me,"stat") || !strcmp(id_me,"state")) {
+ id_code = 16;
+ } else if (!strcmp(id_me,"operation") || !strcmp(id_me,"oper")) {
+ id_code = 17;
+ } else if (!strcmp(id_me,"event") || !strcmp(id_me,"even")) {
+ id_code = 18;
+ } else if (!strcmp(id_me,"condition") || !strcmp(id_me,"cond")) {
+ id_code = 19;
+ } else if (!strcmp(id_me,"enable") || !strcmp(id_me,"enab")) {
+ id_code = 20;
+ } else if (!strcmp(id_me,"questionable") || !strcmp(id_me,"ques")) {
+ id_code = 21;
+ } else if (!strcmp(id_me,"preset") || !strcmp(id_me,"pres")) {
+ id_code = 22;
+ } else if (!strcmp(id_me,"diagnostic") || !strcmp(id_me,"diag")) {
+ id_code = 23;
+ } else if (!strcmp(id_me,"output") || !strcmp(id_me,"outp")) {
+ id_code = 24;
+ } else if (!strcmp(id_me,"impedance") || !strcmp(id_me,"imp")) {
+ id_code = 25;
+ } else if (!strcmp(id_me,"protection") || !strcmp(id_me,"prot")) {
+ id_code = 26;
+ } else if (!strcmp(id_me,"tripped") || !strcmp(id_me,"trip")) {
+ id_code = 27;
+ } else if (!strcmp(id_me,"source") || !strcmp(id_me,"sour")) {
+ id_code = 28;
+ } else if (!strcmp(id_me,"current") || !strcmp(id_me,"curr")) {
+ id_code = 29;
+ } else if (!strcmp(id_me,"level") || !strcmp(id_me,"lev")) {
+ id_code = 30;
+ } else if (!strcmp(id_me,"immediate") || !strcmp(id_me,"imm")) {
+ id_code = 31;
+ } else if (!strcmp(id_me,"amplitude") || !strcmp(id_me,"ampl")) {
+ id_code = 32;
+ } else if (!strcmp(id_me,"offset") || !strcmp(id_me,"offs")) {
+ id_code = 33;
+ } else if (!strcmp(id_me,"high") ) {
+ id_code = 34;
+ } else if (!strcmp(id_me,"low") ) {
+ id_code = 35;
+ } else if (!strcmp(id_me,"voltage") || !strcmp(id_me,"volt")) {
+ id_code = 36;
+ } else if (!strcmp(id_me,"frequency") || !strcmp(id_me,"freq")) {
+ id_code = 37;
+ } else if (!strcmp(id_me,"function") || !strcmp(id_me,"func")) {
+ id_code = 38;
+ } else if (!strcmp(id_me,"shape") || !strcmp(id_me,"shap")) {
+ id_code = 39;
+ } else if (!strcmp(id_me,"pulse") || !strcmp(id_me,"puls")) {
+ id_code = 40;
+ } else if (!strcmp(id_me,"period") || !strcmp(id_me,"per")) {
+ id_code = 41;
+ } else if (!strcmp(id_me,"width") || !strcmp(id_me,"widt")) {
+ id_code = 42;
+ } else if (!strcmp(id_me,"dcycle") || !strcmp(id_me,"dcyc")) {
+ id_code = 43;
+ } else if (!strcmp(id_me,"hold") ) {
+ id_code = 44;
+ } else if (!strcmp(id_me,"delay") || !strcmp(id_me,"del")) {
+ id_code = 45;
+ } else if (!strcmp(id_me,"double") || !strcmp(id_me,"doub")) {
+ id_code = 46;
+ } else if (!strcmp(id_me,"polarity") || !strcmp(id_me,"pol")) {
+ id_code = 47;
+ } else if (!strcmp(id_me,"beeper") || !strcmp(id_me,"beep")) {
+ id_code = 48;
+ } else if (!strcmp(id_me,"cw") ) {
+ id_code = 49;
+ } else if (!strcmp(id_me,"fixed") || !strcmp(id_me,"fix")) {
+ id_code = 50;
+ } else if (!strcmp(id_me,"abort") || !strcmp(id_me,"abor")) {
+ id_code = 51;
+ } else if (!strcmp(id_me,"initiate") || !strcmp(id_me,"init")) {
+ id_code = 52;
+ } else if (!strcmp(id_me,"continuous")) {
+ id_code = 53;
+ } else if (!strcmp(id_me,"trigger") || !strcmp(id_me,"trig")) {
+ id_code = 54;
+ } else if (!strcmp(id_me,"integer") || !strcmp(id_me,"int")) {
+ id_code = 55;
+ } else if (!strcmp(id_me,"float") ) {
+ id_code = 56;
+ } else if (!strcmp(id_me,"eprom") ) {
+ id_code = 57;
+ } else if (!strcmp(id_me,"string") ) {
+ id_code = 58;
+ } else if (!strcmp(id_me,"bit") ) {
+ id_code = 59;
+ } else if (!strcmp(id_me,"set") ) {
+ id_code = 60;
+ } else if (!strcmp(id_me,"clear") ) {
+ id_code = 61;
+ } else if (!strcmp(id_me,"shiftreg") ) {
+ id_code = 62;
+ } else if (!strcmp(id_me,"*rcl") ) {
+ id_code = 63;
+ } else if (!strcmp(id_me,"*sav") ) {
+ id_code = 64;
+ } else if (!strcmp(id_me,"gate") ) {
+ id_code = 65;
+ } else if (!strcmp(id_me,"local") || !strcmp(id_me,"logout") || !strcmp(id_me,"exit") || !strcmp(id_me,"quit") ) {
+ id_code = 66;
+ } else if (!strcmp(id_me,"test") ) {
+ id_code = 67;
+ } else if (!strcmp(id_me,"communicate") || !strcmp(id_me,"comm")) {
+ id_code = 68;
+ } else if (!strcmp(id_me,"address") || !strcmp(id_me,"addr")) {
+ id_code = 69;
+ } else if (!strcmp(id_me,"gpib") ) {
+ id_code = 70;
+ } else if (!strcmp(id_me,"serial") || !strcmp(id_me,"ser")) {
+ id_code = 71;
+ } else if (!strcmp(id_me,"receive") || !strcmp(id_me,"rec")) {
+ id_code = 72;
+ } else if (!strcmp(id_me,"baud") ) {
+ id_code = 73;
+ } else if (!strcmp(id_me,"parity") || !strcmp(id_me,"par")) {
+ id_code = 74;
+ } else if (!strcmp(id_me,"type") ) {
+ id_code = 75;
+ } else if (!strcmp(id_me,"bits") ) {
+ id_code = 76;
+ } else if (!strcmp(id_me,"sbits") || !strcmp(id_me,"sbit")) {
+ id_code = 77;
+ } else if (!strcmp(id_me,"echo") ) {
+ id_code = 78;
+ } else if (!strcmp(id_me,"rts") ) {
+ id_code = 79;
+ } else if (!strcmp(id_me,"control") || !strcmp(id_me,"cont")) {
+ id_code = 80;
+ } else if (!strcmp(id_me,"next") ) {
+ id_code = 81;
+ } else if (!strcmp(id_me,"count") || !strcmp(id_me,"coun")) {
+ id_code = 82;
+ } else if (!strcmp(id_me,"display") || !strcmp(id_me,"disp")) {
+ id_code = 83;
+ } else if (!strcmp(id_me,"brightness") || !strcmp(id_me,"brig")) {
+ id_code = 84;
+ } else if (!strcmp(id_me,"load") ) {
+ id_code = 85;
+ } else if (!strcmp(id_me,"measure") || !strcmp(id_me,"meas")) {
+ id_code = 86;
+ } else if (!strcmp(id_me,"char") ) {
+ id_code = 87;
+ } else if (!strcmp(id_me,"calibration") || !strcmp(id_me,"cal")) {
+ id_code = 88;
+ } else if (!strcmp(id_me,"monitor") || !strcmp(id_me,"mon")) {
+ id_code = 89;
+ } else if (!strcmp(id_me,"step") ) {
+ id_code = 90;
+ } else if (!strcmp(id_me,"route") || !strcmp(id_me,"rout")) {
+ id_code = 91;
+ } else if (!strcmp(id_me,"close") || !strcmp(id_me,"clos")) {
+ id_code = 92;
+ } else if (!strcmp(id_me,"point") ) {
+ id_code = 93;
+ } else if (!strcmp(id_me,"shift") ) {
+ id_code = 94;
+ } else if (!strcmp(id_me,"scale") ) {
+ id_code = 95;
+ } else if (!strcmp(id_me,"null") ) {
+ id_code = 96;
+ } else if (!strcmp(id_me,"size") ) {
+ id_code = 97;
+ } else if (!strcmp(id_me,"separation") || !strcmp(id_me,"sep")) {
+ id_code = 98;
+ } else if (!strcmp(id_me,"network") || !strcmp(id_me,"net")) {
+ id_code = 99;
+ } else if (!strcmp(id_me,"password") || !strcmp(id_me,"pass")) {
+ id_code = 100;
+ } else if (!strcmp(id_me,"new") ) {
+ id_code = 101;
+ } else if (!strcmp(id_me,"suspend") ) {
+ id_code = 102;
+ } else if (!strcmp(id_me,"transition") || !strcmp(id_me,"tran")) {
+ id_code = 103;
+ } else if (!strcmp(id_me,"leading") || !strcmp(id_me,"lead")) {
+ id_code = 104;
+ } else if (!strcmp(id_me,"limit") || !strcmp(id_me,"lim")) {
+ id_code = 105;
+ } else if (!strcmp(id_me,"slew") ) {
+ id_code = 106;
+ } else if (!strcmp(id_me,"all") ) {
+ id_code = 107;
+ }
+
+ else {
+ id_code = 9999;
+ }
+
+ if (set_new_channel) {
+ *with_id_code=id_code;
+ }
+
+ return id_code;
+
+}
+
+static int Parser_find_commands(int commands[], int command_depth)
+{
+#define optional 16384 /* set bit high if optional */
+#define opt_mask 16383 /* default bit mask */
+#define max_tokens_in_sentence 7
+#define max_no_of_sentences 110
+
+ /* Valid command -sequences-. The -individual- commands are defined in id_word. */
+
+ static const int sentences[max_no_of_sentences][max_tokens_in_sentence] = {
+ {0}, /* null - error */
+ {1}, /* cls - sentence 1 */
+ {2}, /* ese - sentence 2 */
+ {4}, /* esr - sentence 3 */
+ {5}, /* idn - sentence 4 */
+ {6}, /* opc - sentence 5 */
+ {8}, /* rst - sentence 6 */
+ {9}, /* sre - sentence 7 */
+ {10}, /* stb - sentence 8 */
+ {11}, /* tst - sentence 9 */
+ {12}, /* wai - sentence 10 */
+ {13,14,81|optional}, /* syst:err:next - 11 */
+ {13,15}, /* syst:vers - 12 */
+ {16,17,18|optional}, /* stat:oper:event - 13 */
+ {16,17,19}, /* stat:oper:cond - 14 */
+ {16,17,20}, /* stat:oper:enable - 15 */
+ {16,21,18|optional}, /* stat:ques:event - 16 */
+ {16,21,19}, /* stat:ques:cond - 17 */
+ {16,21,20}, /* stat:ques:enable - 18 */
+ {16,22}, /* stat:preset - 19 */
+ {24,25}, /* output:impedance - 20 */
+ {24,26,27}, /* output:prot:tripped - 21 */
+ {28|optional,29,30|optional,31|optional,32|optional}, /* sour:curr:lev:imm:ampl - 22 */
+ {28|optional,29,30|optional,31|optional,33}, /* sour:curr:lev:imm:offset - 23 - not used */
+ {28|optional,29,30|optional,31|optional,34}, /* sour:curr:lev:imm:high - 24 - not used */
+ {28|optional,29,30|optional,31|optional,35}, /* sour:curr:lev:imm:low - 25 */
+ {28|optional,36,30|optional,31|optional,32|optional}, /* sour:volt:lev:imm:ampl - 26 */
+ {28|optional,36,30|optional,31|optional,33}, /* sour:volt:lev:imm:offset - 27 - not used */
+ {28|optional,36,30|optional,31|optional,34}, /* sour:volt:lev:imm:high - 28 - not used */
+ {28|optional,36,30|optional,31|optional,35}, /* sour:volt:lev:imm:low - 29 */
+ {28|optional,29,26,27}, /* sour:curr:prot:tripped? - 30 */
+ {28|optional,36,26,27}, /* sour:volt:prot:tripped? - 31 */
+ {28|optional,37,49|optional}, /* sour:freq:cw - 32 */
+ {28|optional,37,50|optional}, /* sour:freq:fixed - 33 */
+ {28|optional,38,39|optional}, /* sour:func:shape - 34 */
+ {28|optional,40,41}, /* sour:puls:per - 35 */
+ {28|optional,40,42}, /* sour:puls:width - 36 */
+ {28|optional,40,43}, /* sour:puls:dcyc - 37 */
+ {28|optional,40,44}, /* sour:puls:hold - 38 */
+ {28|optional,40,45}, /* sour:puls:delay - 39 */
+ {28|optional,40,46,16|optional}, /* sour:puls:doub:state - 40 */
+ {28|optional,40,46,45}, /* sour:puls:doub:delay - 41 */
+ {28|optional,40,47}, /* sour:puls:pol - 42 */
+ {13,48,31|optional}, /* syst:beep:imm - 43 - not used */
+ {52,31|optional,53}, /* init:imm:cont - 44 - not used */
+ {51}, /* abort - 45 - not used */
+ {54,31|optional,28}, /* trig:imm:sour - 46 */
+ {23,57,58}, /* diag:eprom:string - 47 */
+ {23,57,55}, /* diag:eprom:int - 48 */
+ {23,57,59,60}, /* diag:eprom:bit:set - 49 - not used */
+ {23,57,59,61}, /* diag:eprom:bit:clear - 50 - not used */
+ {23,57,56}, /* diag:eprom:float - 51 */
+ {23,62}, /* diag:shiftreg - 52 */
+ {63}, /* *rcl - 53 */
+ {64}, /* *sav - 54 */
+ {24,16|optional}, /* output:state - 55 */
+ {28|optional,40,65,75}, /* sour:puls:gate:type - 56 */
+ {66}, /* local (RS232 mode only) - 57 */
+ {23,67,45}, /* diag:test:delay - 58 */
+ {13,68,70,69}, /* syst:comm:gpib:addr - 59 */
+ {13,68,71,72|optional,73}, /* syst:comm:ser:rec:baud - 60 */
+ {13,68,71,72|optional,74,75|optional}, /* syst:comm:ser:rec:parity - 61 */
+ {13,68,71,72|optional,76}, /* syst:comm:ser:rec:bits - 62 */
+ {13,68,71,72|optional,77}, /* syst:comm:ser:rec:sbits - 63 */
+ {13,68,71,80,79}, /* syst:comm:ser:control:rts - 64 */
+ {13,68,71,72|optional,78}, /* syst:comm:ser:rec:echo - 65 */
+ {13,14,82}, /* syst:err:count - 66 */
+ {28|optional,40,65,30}, /* sour:puls:gate:level - 67 */
+ {24,85}, /* output:load - 68 */
+ {86,32}, /* meas:ampl? - 69 */
+ {23,57,87}, /* diag:eprom:char - 70 */
+ {23,88}, /* diag:calib - 71 */
+ {23,32,88,95|optional}, /* diag:ampl:calib:scale - 72 */
+ {23,89,88,95|optional}, /* diag:mon:calib:scale - 73 */
+ {23,89,90}, /* diag:mon:step - 74 */
+ {24,75}, /* output:type - 75 */
+ {23,33,88,95|optional}, /* diag:offset:calib:scale - 76 */
+ {23,40,42,88,94}, /* diag:pulse:width:calib:shift - 77 */
+ {91,92}, /* route:close - 78 */
+ {23,40,42,88,93}, /* diag:pulse:width:calib:point - 79 */
+ {23,40,45,88,93}, /* diag:pulse:delay:calib:point - 80 */
+ {23,40,41,88,93}, /* diag:pulse:period:calib:point - 81 */
+ {23,40,45,88,94}, /* diag:pulse:delay:calib:shift - 82 */
+ {23,32,88,93}, /* diag:ampl:calib:point - 83 */
+ {23,33,88,93}, /* diag:offset:calib:point - 84 */
+ {23,33,96,93}, /* diag:offset:null:point - 85 */
+ {23,57,97}, /* diag:eprom:size - 86 */
+ {83,84}, /* display:brightness - 87 */
+ {28|optional,40,82}, /* sour:puls:count - 88 */
+ {28|optional,40,98}, /* sour:puls:separation - 89 */
+ {23,40,98,88,93}, /* diag:pulse:separation:calib:point - 90 */
+ {13,68,99}, /* system:comm:network - 91 */
+ {13,100,101}, /* system:password:new - 92 */
+ {23,57,102}, /* diag:eprom:suspend - 93 */
+ {28|optional,40,103,104|optional}, /* sour:puls:transition:leading - 94 */
+ {23,40,103,88,93}, /* diag:pulse:transition:calib:point - 95 */
+ {28|optional,29,105,32|optional}, /* sour:curr:limit:ampl - 96 */
+ {23,24,85,88,93}, /* diag:output:load:calib:point - 97 */
+ {28|optional,29,106}, /* sour:curr:slew - 98 */
+ {23,106,88,93}, /* diag:slew:calib:point - 99 */
+ {88,107|optional}, /* calibration:all - 100 */
+ {88,37} /* calibration:frequency - 101 */
+
+ };
+
+
+ int token_num; /* which token in the command[] list is being considered */
+ int sentence_num; /* which sentence is being considered as a match */
+ int sentence_found; /* matching sentence found yet? */
+ int sent_pos; /* position in current sentence */
+ int invalid_match; /* flag if definitely the wrong match */
+ int local_match_pos; /* position (or pos+1, depends) of most-recently-matched token in sentence */
+ int local_match; /* match for current token found yet? */
+ int prev_match; /* were there previous local matches? */
+ int i; /* a counter */
+
+ sentence_num = 1;
+ sent_pos = 0;
+
+ /* check each "sentence" (corresponding to a different routine or function)
+ until a match is found, or until their are no possible sentences left */
+ for (sentence_found = 0; (!sentence_found && sentence_num < max_no_of_sentences); ++sentence_num) {
+ local_match_pos=0;
+ invalid_match=0;
+ prev_match=0;
+ /* start with the first input token, until all have been matched, or one
+ is unmatchable */
+ for (token_num = 0; (token_num < command_depth) && !invalid_match; ++token_num) {
+ /* start after most recent matching token */
+ sent_pos=local_match_pos;
+
+ /* compare current token to the sentence components until a matching component
+ is found, or until there are none left */
+ for (local_match=0; (!local_match) && (sent_pos<max_tokens_in_sentence); ++sent_pos) {
+
+ /* compare here */
+ if (commands[token_num]==((sentences[sentence_num][sent_pos]) & opt_mask)) {
+ /* flag a local token match (not a whole sentence match) */
+ local_match=1;
+ }
+ }
+ if (local_match) {
+ /* if any of the components in the sentence were skipped between the last two
+ matches, make sure that they were optional ones */
+ if (!prev_match) {
+ local_match_pos=-1;
+ }
+ /* if there was no local match previously, then the initial value
+ of local_match_pos is misleading - there was no match at 0. */
+ for (i=(local_match_pos+1); i<(sent_pos-1); ++i) {
+ /* if they weren't optional, the match is not valid */
+ if (!(sentences[sentence_num][i] & optional)) {
+ invalid_match=1;
+ }
+ }
+ /* counteract the last "++i" due to the for loop */
+ local_match_pos = sent_pos - 1;
+ if (local_match && !invalid_match) {
+ prev_match=1;
+ }
+ }
+
+ /* if no match for this one token existed in this sentence, mark this sentence as invalid */
+ if (!local_match) {
+ invalid_match = 1;
+ }
+ }
+ /* if no invalid token match was found for any of the tokens in this sentence,
+ then it's an overall sentence match! */
+ if (!invalid_match) {
+ sentence_found=1;
+ }
+ }
+ --sentence_num;
+
+ if (!sentence_found) {
+ sentence_num = 0;
+ }
+ /* 0 is the no-match value */
+
+ return sentence_num;
+}
+
+
+static int Parser_get_unit(char *parameter,char *units)
+{
+ /* this function takes a parameter like "1e+6 ms" and breaks it into parameter="1e+6" and
+ units="ms" */
+
+ int i;
+ int j;
+ int units_present;
+
+ units_present=0;
+ i=0;
+
+
+ if (isdigit(parameter[0]) || parameter[0]=='+' || parameter[0] == '-' || parameter[0] == '.') {
+ for (i=1; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ if (i < strlen(parameter))
+ if ( parameter[i]=='.' )
+ for (++i; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ /* suck out spaces */
+ while ( (i<strlen(parameter)) && (isspace(parameter[i])) ) {
+ for (j=i; j<strlen(parameter); ++j) {
+ parameter[j]=parameter[j+1];
+ }
+ parameter[j]=0;
+ }
+
+ if (i < strlen(parameter))
+ if ( (parameter[i]=='e' && parameter[i+1]=='-')
+ || (parameter[i]=='e' && parameter[i+1]=='+') )
+ for (i+=2; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+ else if (parameter[i]=='e' && isdigit(parameter[i+1]) )
+ for (i+=2; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ /* suck out spaces */
+ while ( (i<strlen(parameter)) && (isspace(parameter[i])) ) {
+ for (j=i; j<strlen(parameter); ++j) {
+ parameter[j]=parameter[j+1];
+ }
+ parameter[j]=0;
+ }
+
+ if (i != strlen(parameter)) {
+ units_present=1;
+ strcpy(units,parameter+i);
+ parameter[i]=0;
+
+ /* remove trailing spaces */
+ for (j=strlen(units)-1; isspace(units[j]); --j) {
+ units[j]=0;
+ }
+
+ }
+ }
+
+ return units_present;
+}
+
+void Parser_main (char *in, gchar** response, int allow_unrequested_responses, int *error_num)
+{
+ int in_pos; /* this identifies the single character of in being processed */
+ int command_depth; /* how many command words have been parsed */
+ int old_command_depth; /* save this if in case of a compound message */
+ char current_command[max_input_word_length]; /* current command word being processed */
+ int current_command_length; /* length of current command so far */
+ int commands[max_commands_in_input]; /* list of identified command tokens */
+ int old_commands[max_commands_in_input]; /* list of identified command tokens from */
+ /* last non-common, non-colon-started command*/
+ int space_found; /* if true, a space was found. parameter may follow */
+ int parameter_found; /* if true, there is a parameter at the end of the command string */
+ char parameter[max_input_word_length]; /* identified parameter */
+ char units[max_input_word_length]; /* identified units */
+ int semicolon_found; /* to break up lines */
+ int units_found; /* text found after parameter must be units */
+ int i; /* counter */
+ int routine_num; /* routine to execute, based on command */
+ int dont_use_this_header; /* the old head is saved in case of compound message, unless this is set */
+ int compound_message; /* this indicates that at least one semicolon has been found, so */
+ /* the message is a compound one */
+
+// char response[max_output_length];
+
+ int is_query;
+ int command_type; /* combination of is_query, parameter_found, and units_found */
+
+ int channel;
+ int with_id_code;
+
+//printf ("decoding this input: %s\n\r",in);
+
+ // fixme - delete enclosing loop and re-indent
+ if (1) {
+ strcpy(in+strlen(in)," "); /* add white space to the end of the input string */
+
+ in_pos = 0; /* start at the beginning of the input string */
+ semicolon_found = 0;
+ compound_message = 0;
+ command_depth=0;
+ old_command_depth=0;
+ dont_use_this_header=NO;
+
+ while (isspace(in[in_pos]) || in[in_pos]==':' || in[in_pos]==';') {
+ /* ignore leading spaces */
+ ++in_pos;
+ }
+
+
+ /* examine each letter in the string until EOS */
+ while (in[in_pos] != 0) {
+
+ channel=-1;
+ with_id_code=0;
+ space_found = 0;
+ parameter_found = 0; /* no numeric parameters yet */
+ parameter[0] = 0;
+ units_found = 0;
+ is_query = 0;
+ current_command_length = 0;
+
+ if (semicolon_found && !dont_use_this_header) {
+ old_command_depth=command_depth-2;
+ for (i=0; i<old_command_depth; ++i) {
+ old_commands[i]=commands[i];
+ }
+ }
+
+ command_depth=old_command_depth;
+ for (i=0; i<command_depth; ++i) {
+ commands[i]=old_commands[i];
+ }
+
+ semicolon_found=0;
+ dont_use_this_header=NO;
+
+ /* break it up if semicolons are present */
+ while (!semicolon_found && in[in_pos] != 0) {
+
+ in[in_pos]=tolower(in[in_pos]);
+ /* everything to lowercase */
+
+ /* words are separated by white space or colons or semicolons */
+ if ( isspace(in[in_pos]) || in[in_pos] == ':' || in[in_pos] == ';')
+
+ {
+
+ if (in[in_pos] == ';') {
+ ++semicolon_found;
+ }
+ ++compound_message;
+
+ /* if it is a separator, ignore it if it is duplicated */
+ if ( !isspace(in[in_pos-1]) && (in[in_pos-1] != ':') && (in[in_pos-1] != ';')) {
+ /* valid separator, so terminate current command word string */
+ current_command[current_command_length] = '\0';
+
+ if (space_found) {
+ /* Just end things if it is a semicolon */
+ if (in[in_pos]!=';') {
+ current_command[current_command_length] = in[in_pos];
+ ++current_command_length;
+ }
+
+ current_command[current_command_length] = '\0';
+ ++parameter_found;
+ strcpy(parameter,current_command);
+ } else if (!space_found) {
+ /* just a regular command word */
+
+ /* terminate the current command string */
+ current_command_length = 0; /* make room for a new command string */
+ commands[command_depth]=Parser_id_word(current_command,&channel,&with_id_code);
+
+ if ( commands[command_depth]<13
+ || commands[command_depth]==63
+ || commands[command_depth]==64) {
+ dont_use_this_header=YES;
+ commands[0]=commands[command_depth];
+ command_depth=0;
+ }
+
+ ++command_depth; /* indicate that a new command word is ready */
+
+ /* indicate if the separator was a space - next bit parameter then */
+ if (in[in_pos]==' ') {
+ ++space_found;
+ }
+ }
+ } /* non-repeated separator */
+ else if (compound_message && in[in_pos-1]==';' && in[in_pos]==':') {
+ dont_use_this_header=YES;
+ command_depth=0;
+ }
+
+ } /* a separator */
+ else if (in[in_pos]!='?') {
+ /* if not white space or separator, add character to current command word */
+ current_command[current_command_length] = in[in_pos];
+ ++current_command_length;
+ } /* not a separator */
+ else {
+ ++is_query;
+ /* question mark found */
+ }
+
+
+ ++in_pos; /* move pointer to next letter */
+
+ } /* not a semi-colon */
+
+ commands[command_depth]=0;
+ ++command_depth;
+ /* add end of tokens marker (0) */
+
+ *error_num=OK;
+ response[0]=0;
+
+ if (parameter_found) {
+ units_found = Parser_get_unit(parameter,units);
+ *error_num=String_trim_excess_digits(parameter);
+ *error_num=String_trim_excess_digits(units);
+ }
+
+ if (!*error_num) {
+ if (!units_found) {
+ units[0]='\0';
+ }
+ g_strstrip (parameter);
+ command_type=(is_query<<2) | (parameter_found?2:0) | units_found;
+
+ if (commands[0]!=0) {
+ routine_num = Parser_find_commands(commands,command_depth);
+
+ /* check for valid channel number, based on position in command */
+ if ( (*error_num=Parser_channel(&channel,with_id_code,routine_num)) )
+ /* not a valid command due to improper channel suffix */
+ {
+ routine_num=9999;
+ }
+ } else {
+ routine_num=9999;
+ /* ignore empty commands lists, generated by a white space string */
+ }
+
+ switch (routine_num) {
+ case 0:
+ *response = g_strdup_printf("routine_num: %d, channel: %d, parameter: %s, units: %s, command type: %d\n\r",routine_num,channel,parameter,units,command_type);
+ *error_num=Unrecognized;
+ break;
+ case 11:
+ *error_num=Go_syst_err_11(response,channel,parameter,units,command_type);
+ break;
+ case 32:
+ case 33:
+ *error_num=Go_freq_32_33(response,channel,parameter,units,command_type);
+ break;
+ case 66:
+ *error_num=Go_syst_errcnt66(*response,channel,parameter,units,command_type);
+ break;
+
+ case 9999:
+ // was only whitespace, ignore
+ break;
+
+ default:
+ /* valid but not implemented yet */
+ *response = g_strdup_printf("routine_num: %d, channel: %d, parameter: %s, units: %s, command type: %d\n\r",routine_num,channel,parameter,units,command_type);
+ break;
+
+ }
+ }
+
+// int control_mode = 0; //CUSTOM
+
+ if (response[0]) {
+ // IO_output_to_comm_bus(response,control_mode);
+
+
+ }
+
+ if (*error_num) {
+ queue_error_from_parser(response, *error_num);
+ }
+
+ if (!is_query) {
+ Main_update_shift_registers(); /* update values in pulse generator circuit */
+ }
+
+ } /* not EOS */
+
+ /* update display if it wasn't a query, and if the control menu isn't on (this gives the user
+ a chance to press "Go To Local" to override control */
+
+ int Selected_Submenu=0, Submenu1_rem_loc=0, Type_Of_Menu=0, Submenu_On=0;
+
+ if (!is_query && !(Selected_Submenu==Submenu1_rem_loc && Type_Of_Menu==Submenu_On)) {
+ Menu_Update_Display();
+ }
+
+ /* re-run error_check to update min/max values based on actual settings, not proposed settings */
+ Error_check(globals.ChannelState);
+ }
+}
+
+static int Parser_channel (int *channel,int with_id_code,int routine_num)
+{
+ /* return if no channel suffixes appeared */
+ if (*channel==-1) {
+ *channel=0;
+ return OK;
+ }
+
+
+ /* compare to maximum number of channels allowed */
+ if (*channel>1 && *channel>globals.Flash.channels && !globals.Flash.enable_avrq_extra_ampls) {
+ return InvalidChannel;
+ }
+ if (*channel>5 && globals.Flash.enable_avrq_extra_ampls) {
+ return InvalidChannel;
+ }
+
+
+ /* SCPI uses 1-N counting, change to 0 - (N-1) */
+ if (*channel > 0) {
+ --(*channel);
+ } else {
+ return InvalidChannel;
+ }
+
+ return OK;
+}
+
+
+static int Go_freq_32_33(gchar** response, int channel, char *parameter,char *units,int command_type)
+{
+ // this is a typical parser function - there will be many more added later
+
+ float new_freq;
+ int status;
+
+ if ( (status = check_channel_ok (channel, globals.Flash.channels, globals.Flash.ChanKey_frequency))) {
+ return status;
+ }
+
+ new_freq=1.0;
+
+ switch (command_type) {
+ case command_param_units:
+ if ( (status=Handle_Units(&new_freq,units,"hz")) ) {
+ return status;
+ }
+ /* no break */
+
+ case command_withparam:
+ if ( (status = process_float_param (parameter, &new_freq, 1.0, 1.0e6, NORMAL_ZERO)) ) {
+ return status;
+ }
+ return Set_frequency(0,0,0,channel,new_freq);
+ break;
+
+ case query_simple:
+ return query_float(response, globals.ChannelState[channel].frequency);
+ break;
+
+ case query_param:
+ return query_min_max_float (response, parameter, 1.0, 1.0e6);
+ break;
+
+ default:
+ return SyntaxError;
+ break;
+ }
+}
+
+
+static int Handle_Units(float *mult,char *units, char *in_base)
+{
+ int len_base, len_all, pos;
+ char prefix[max_input_word_length];
+ char base[max_input_word_length];
+
+ strcpy (base, in_base);
+
+ *mult=1.0;
+ if (!strcmp(units,base)) {
+ return OK;
+ }
+
+ // match base
+ len_all = strlen (units);
+ if (len_all == 0) {
+ return OK;
+ }
+
+ len_base = strlen (base);
+ pos = len_all - len_base;
+
+ strcpy (prefix, units);
+
+ if (!strcmp(base,"%") && (len_all >= 3) && !strcmp(prefix + len_all - 3,"pct")) {
+ strcpy(base, "pct");
+ prefix[len_all - 3] = 0;
+ } else if (!strcmp(base,"pct") && !strcmp(prefix + len_all - 1,"%")) {
+ strcpy(base, "%");
+ prefix[len_all - 1] = 0;
+ } else if (strcmp(prefix+pos,base)) {
+ return UnknownUnits;
+ } else {
+ prefix[pos]=0;
+ }
+
+ if (strlen(prefix) == 0) {
+ return OK;
+ }
+
+ // special exceptions
+ if (!strcmp(prefix,"m") && !strcmp(base,"ohm")) {
+ *mult=1.0e6;
+ } else if (!strcmp(prefix,"m") && !strcmp(base,"hz")) {
+ *mult=1.0e6;
+ }
+ // normal rules
+ else if (!strcmp(prefix,"ex")) {
+ *mult=1.0e18;
+ } else if (!strcmp(prefix,"pe")) {
+ *mult=1.0e15;
+ } else if (!strcmp(prefix,"t")) {
+ *mult=1.0e12;
+ } else if (!strcmp(prefix,"g")) {
+ *mult=1.0e9;
+ } else if (!strcmp(prefix,"ma")) {
+ *mult=1.0e6;
+ } else if (!strcmp(prefix,"k")) {
+ *mult=1.0e3;
+ } else if (!strcmp(prefix,"m")) {
+ *mult=1.0e-3;
+ } else if (!strcmp(prefix,"u")) {
+ *mult=1.0e-6;
+ } else if (!strcmp(prefix,"n")) {
+ *mult=1.0e-9;
+ } else if (!strcmp(prefix,"p")) {
+ *mult=1.0e-12;
+ } else if (!strcmp(prefix,"f")) {
+ *mult=1.0e-15;
+ } else if (!strcmp(prefix,"a")) {
+ *mult=1.0e-18;
+ } else {
+ return UnknownUnits;
+ }
+
+ return OK;
+}
+
+
+static int Is_Min_Command(gchar *text)
+{
+ return (!strcmp(text,"min") || !strcmp(text,"minimum"));
+}
+
+
+static int Is_Max_Command(char *text)
+{
+ return (!strcmp(text,"max") || !strcmp(text,"maximum"));
+}
+
+
+static int query_min_max_float (gchar** response, char *parameter, float min_val, float max_val)
+{
+ float report_val;
+
+ if (Is_Min_Command(parameter)) {
+ report_val=min_val;
+ } else if (Is_Max_Command(parameter)) {
+ report_val=max_val;
+ } else {
+ return SyntaxError;
+ }
+
+ Float_To_Text(remote_digits_after_decimal,report_val,response);
+ return OK;
+}
+
+static int query_float (gchar** response, float value)
+{
+ Float_To_Text(remote_digits_after_decimal,value,response);
+ return OK;
+}
+
+static int process_float_param (char *parameter, float *value, float min_val, float max_val, int zero_mode)
+{
+ int status;
+ status = OK;
+
+ if (String_is_it_numeric(parameter)) {
+ *value *= atof(parameter);
+
+ if (zero_mode == ALLOW_NEG_ZERO) {
+ /* allow a value of "-0" */
+ if (fabs(*value) < smallest_allowed_number)
+ if (parameter[0] == '-') {
+ *value = -0.1*smallest_allowed_number;
+ }
+ }
+ }
+
+ else if (!strcmp(parameter,"+") && (zero_mode == ALLOW_NEG_ZERO)) {
+ *value = smallest_allowed_number;
+ } else if (!strcmp(parameter,"-") && (zero_mode == ALLOW_NEG_ZERO)) {
+ *value = -smallest_allowed_number;
+ } else if (Is_Min_Command(parameter)) {
+ *value = min_val;
+ } else if (Is_Max_Command(parameter)) {
+ *value = max_val;
+ } else {
+ status=SyntaxError;
+ }
+
+ return status;
+}
+
+static int check_channel_ok (int channel, int enabled_channels, char chankey)
+{
+ /* how many channels overall */
+ if (channel >= enabled_channels) {
+ return InvalidChannel;
+ }
+
+ /* abandon if high channel selected by user but not enabled by firmware for that parameter*/
+ if (channel && !chankey) {
+ return InvalidChannel;
+ }
+
+ return OK;
+}
+
+
+static int Go_syst_err_11(gchar** response, int channel, char *parameter,char *units,int command_type)
+{
+ switch (command_type) {
+ case query_simple:
+ if (globals.number_of_errors==0) {
+ get_error_text(response, OK);
+ } else {
+ get_error_text(response,globals.error_queue[1]);
+ Error_Remove_From_Queue();
+ }
+ return OK;
+ break;
+
+ default:
+ return SyntaxError;
+ break;
+ }
+}
+
+static int Go_syst_errcnt66(gchar* response, int channel, char *parameter,char *units,int command_type)
+{
+ switch (command_type) {
+ case query_simple:
+ return query_int (response, globals.number_of_errors);
+ break;
+
+ default:
+ return SyntaxError;
+ break;
+ }
+}
+
diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..3fef423 --- /dev/null +++ b/parser.h @@ -0,0 +1,34 @@ +#ifndef PARSER_H_ +#define PARSER_H_ + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <glib.h> +#include <math.h> + +#include "globals.h" +#include "string_utils.h" +#include "dummy_functions.h" +#include "device-functions.h" + +/* types of input commands that can be parsed */ + +#define command_simple 0 +#define command_withparam 2 +#define command_param_units 3 +#define query_simple 4 +#define query_param 6 + +/* general formatting */ +#define remote_digits_after_decimal 4 /* how many digits are returned after decimal by query commands */ + +#define NORMAL_ZERO 0 +#define ALLOW_NEG_ZERO 1 + +#define USE_ON_OFF 0 +#define NO_ON_OFF 1 + +void Parser_main (char *in, gchar** response, int allow_unrequested_responses, int* errors); + +#endif
\ No newline at end of file diff --git a/string_utils.c b/string_utils.c new file mode 100644 index 0000000..b5ec2c2 --- /dev/null +++ b/string_utils.c @@ -0,0 +1,237 @@ +/* START LIBRARY DESCRIPTION *********************************************
+FLOAT.LIB
+ Copyright (c) 2006, Avtech Electrosystems Ltd.
+
+DESCRIPTION:
+ Functions that deal with strings and floating point numbers.
+
+SUPPORT LIB'S:
+END DESCRIPTION **********************************************************/
+
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib/gprintf.h>
+#include "globals.h"
+#include "string_utils.h"
+
+void Float_To_Text(int decimal_digits,float number_in, gchar ** text_out)
+{
+ if (fabs(number_in)<1.1*smallest_allowed_number) {
+ if (number_in<0.0) {
+ *text_out = g_strdup("-0.000000000");
+ *text_out[decimal_digits+3]=0;
+ } else {
+ *text_out = g_strdup("0.000000000");
+ *text_out[decimal_digits+2]=0;
+ }
+ }
+
+ if(*text_out == NULL) *text_out = g_strdup_printf("%.*e", decimal_digits, number_in);
+ else g_sprintf (*text_out, "%.*e", decimal_digits, number_in);
+}
+
+
+int String_trim_excess_digits(char *parameter)
+{
+ /* this function takes a parameter like "1.2345678901234567890" and reduces it to "1.234567" */
+ /* so that atof() will work properly */
+
+ gchar* new_string = g_strdup(parameter);
+ memset(new_string, 0, strlen(parameter));
+
+ int i;
+ int j;
+ int sig_digits; /* number of significant digits so far */
+ long exp_power; /* append an exponent of this power */
+ int sign; /* is the exponent negative? */
+ int start_of_exponent; /* location of exponent */
+
+ i=0; /* location in input string */
+ j=0; /* location in output string */
+ sig_digits=0;
+ exp_power=0;
+ sign=NO;
+
+#define max_sig_dig 8
+
+ if (!(isdigit(parameter[0]) || parameter[0]=='+' || parameter[0]=='-' || parameter[0]=='.')) {
+ return OK;
+ }
+
+ /* take care of sign */
+ if (parameter[0]=='+' || parameter[0]=='-') {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ /* leave in leading zeros */
+ while (parameter[i]=='0') {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ /* leave in up to 8 pre-decimal significant digits */
+ while (isdigit(parameter[i]) && sig_digits<max_sig_dig) {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ ++sig_digits;
+ }
+
+ /* if there are remaining digits, truncate and add exponent, and then return immediately */
+ while (isdigit(parameter[i]) && sig_digits==max_sig_dig) {
+ ++i;
+ ++exp_power;
+ }
+ if (exp_power>0) {
+ strcat(new_string+j,"e");
+
+ //replaced itoa (non standard) with sprintf
+ char temp[64];
+ memset(temp, 0, 64);
+ sprintf(temp, "%ld", exp_power);
+
+ strcat(new_string,temp);
+
+ strcpy(parameter,new_string);
+ if (exp_power<38) {
+ return OK;
+ } else {
+ return OutOfRange;
+ }
+ }
+
+ /* leave in decimal point */
+ if (parameter[i]=='.') {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ /* leave in post-decimal zeros if no significant digits yet */
+ while (parameter[i]=='0' && sig_digits==0) {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ /* leave in up to 8 post-decimal significant digits */
+ while (isdigit(parameter[i]) && sig_digits<max_sig_dig) {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ ++sig_digits;
+ }
+
+ /* skip extraneous post-decimal digits */
+ while (isdigit(parameter[i]) && sig_digits==max_sig_dig) {
+ ++i;
+ }
+
+ if (parameter[i]=='e') {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+
+ if (parameter[i]=='+') {
+ sign=NO;
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ } else if (parameter[i]=='-') {
+ sign=YES;
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ if (i<strlen(parameter) && isdigit(parameter[i])) {
+ start_of_exponent=j;
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ while (i<strlen(parameter) && isdigit(parameter[i])) {
+ new_string[j]=parameter[i];
+ ++i;
+ ++j;
+ }
+
+ new_string[j]=0;
+ exp_power=atol(new_string+start_of_exponent);
+
+ if (exp_power>37 && sign==NO) {
+ g_free(new_string);
+ return OutOfRange;
+ }
+ if (exp_power>37 && sign==YES) {
+ strcpy(new_string,"0.0");
+ }
+ }
+
+ new_string[j]=0;
+
+ strcpy(parameter,new_string);
+ g_free(new_string);
+ return OK;
+}
+
+/*----------------------------------------------------------------------------------------------------------*/
+int String_is_it_numeric(char *parameter)
+{
+ /* this function takes a parameter like "1e+6" or "on" and determines if it is numeric or not */
+ /* it is similar to the Parser_get_unit function */
+
+ int i;
+ int j;
+ int is_number;
+
+ is_number=0;
+ i=0;
+
+
+ if (isdigit(parameter[0]) || parameter[0]=='+' || parameter[0] == '-' || parameter[0] == '.') {
+ for (i=1; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ if (i < strlen(parameter))
+ if ( parameter[i]=='.' )
+ for (++i; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ /* suck out spaces */
+ while ( (i<strlen(parameter)) && (isspace(parameter[i])) ) {
+ for(j=i; j<strlen(parameter); ++j) {
+ parameter[j]=parameter[j+1];
+ }
+ parameter[j]=0;
+ }
+
+ if (i < strlen(parameter))
+ if ( (parameter[i]=='e' && parameter[i+1]=='-')
+ || (parameter[i]=='e' && parameter[i+1]=='+') )
+ for (i+=2; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+ else if (parameter[i]=='e' && isdigit(parameter[i+1]) )
+ for (i+=2; (i < strlen(parameter)) && isdigit(parameter[i]); ++i) {}
+
+ /* suck out spaces */
+ while ( (i<strlen(parameter)) && (isspace(parameter[i])) ) {
+ for(j=i; j<strlen(parameter); ++j) {
+ parameter[j]=parameter[j+1];
+ }
+ parameter[j]=0;
+ }
+
+ if (i = strlen(parameter)) {
+ is_number=1;
+ parameter[i]=0;
+ }
+ }
+
+ return is_number;
+}
+
+
diff --git a/string_utils.h b/string_utils.h new file mode 100644 index 0000000..0f946f5 --- /dev/null +++ b/string_utils.h @@ -0,0 +1,12 @@ +#ifndef STRING_UTILS_H_ +#define STRING_UTILS_H_ + +#define smallest_allowed_number 1.0e-18 + + +void Float_To_Text(int decimal_digits,float number_in, gchar** text_out); +int String_trim_excess_digits(char *parameter); +int String_is_it_numeric(char *parameter); + + +#endif |