diff options
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 2022 |
1 files changed, 1011 insertions, 1011 deletions
@@ -1,1011 +1,1011 @@ -/* 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_int (gchar** response, int n);
-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" */
-
- if (*parameter == NULL) {
- *parameter = g_strdup ("");
- }
-
- g_assert (*units == NULL);
-
- gchar *end_ptr;
- g_strtod (*parameter, &end_ptr);
-
- if (end_ptr == *parameter) {
- *units = g_strdup ("");
- } else {
- *units = g_strdup (end_ptr);
- end_ptr[0] = 0; // truncates parameter
- }
-
- g_strstrip (*units);
- g_strstrip (*parameter);
-
- int units_present = (*units[0] != 0);
- return units_present;
-}
-
-void Parser_main (char *raw_in, int interactive_terminal, void(*cbfunc)(gpointer, gchar *), gpointer user_data)
-{
- 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 */
- 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 */
-
-
- int is_query;
- int command_type; /* combination of is_query, parameter_found, and units_found */
-
- int channel;
- int with_id_code;
-
- g_strstrip (raw_in);
-
- // add white space to the end of the input string - FIXME?
- gchar *in = g_strdup_printf ("%s ", raw_in);
-
- 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) {
-
- gchar *units = NULL;
- gchar *response = NULL;
- gchar *error_response = NULL;
- gchar *parameter = NULL;
-
- channel=-1;
- with_id_code=0;
- space_found = 0;
- parameter_found = 0; /* no numeric parameters yet */
- 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;
- parameter = g_strdup (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) */
-
- int error_num=OK;
-
- units_found = Parser_get_unit(¶meter,&units);
-
- if (!error_num) {
- 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",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",routine_num,channel,parameter,units,command_type);
- break;
-
- }
- }
-
- if (error_num) {
- queue_error_from_parser(&error_response, error_num);
- if (interactive_terminal) {
- (*cbfunc)(user_data, error_response);
- }
- } else {
- (*cbfunc)(user_data, response);
- }
-
- g_free (units);
- g_free (response);
- g_free (error_response);
- g_free (parameter);
-
- 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);
-
- // trigger a prompt
- if (interactive_terminal) {
- (*cbfunc)(user_data, "");
- }
-
- g_free (in);
-}
-
-
-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_int (gchar** response, int n)
-{
- *response = g_strdup_printf ("%d", n);
- return OK;
-}
-
-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;
- }
-}
-
+/* 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_int (gchar** response, int n); +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" */ + + if (*parameter == NULL) { + *parameter = g_strdup (""); + } + + g_assert (*units == NULL); + + gchar *end_ptr; + g_strtod (*parameter, &end_ptr); + + if (end_ptr == *parameter) { + *units = g_strdup (""); + } else { + *units = g_strdup (end_ptr); + end_ptr[0] = 0; // truncates parameter + } + + g_strstrip (*units); + g_strstrip (*parameter); + + int units_present = (*units[0] != 0); + return units_present; +} + +void Parser_main (char *raw_in, int interactive_terminal, void(*cbfunc)(gpointer, gchar *), gpointer user_data) +{ + 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 */ + 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 */ + + + int is_query; + int command_type; /* combination of is_query, parameter_found, and units_found */ + + int channel; + int with_id_code; + + g_strstrip (raw_in); + + // add white space to the end of the input string - FIXME? + gchar *in = g_strdup_printf ("%s ", raw_in); + + 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) { + + gchar *units = NULL; + gchar *response = NULL; + gchar *error_response = NULL; + gchar *parameter = NULL; + + channel=-1; + with_id_code=0; + space_found = 0; + parameter_found = 0; /* no numeric parameters yet */ + 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; + parameter = g_strdup (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) */ + + int error_num=OK; + + units_found = Parser_get_unit(¶meter,&units); + + if (!error_num) { + 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",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",routine_num,channel,parameter,units,command_type); + break; + + } + } + + if (error_num) { + queue_error_from_parser(&error_response, error_num); + if (interactive_terminal) { + (*cbfunc)(user_data, error_response); + } + } else { + (*cbfunc)(user_data, response); + } + + g_free (units); + g_free (response); + g_free (error_response); + g_free (parameter); + + 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); + + // trigger a prompt + if (interactive_terminal) { + (*cbfunc)(user_data, ""); + } + + g_free (in); +} + + +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_int (gchar** response, int n) +{ + *response = g_strdup_printf ("%d", n); + return OK; +} + +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; + } +} + |