/******************************************************************** * * * HCS_C XPRESS Compiler * * Version 1.09 Added voice lock/unlock support * Version 1.08 Added Insteon support * Version 1.07 Revamped X10 support * Version 1.06 Added video support * Version 1.05 Added bit set command, made bit command consistent * Version 1.00 X10 support improved, old commands turned off * Version 0.04a HCSNET device command * Version 0.04 HCSNET support, rabbit ethernet support * Version 0.03a Bug fix * Version 0.03 Added HCSNET operands and VOICE, VOICE_RECORD * Version 0.02 New versioning scheme to match the firmware * Version 5.10 * * * June 15, 2000 * * Copyright (C) 2001 Circuit Cellar Incorporated * 4 Park St. * Vernon, CT 06066 * * steve@circuitcellar.com; * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * Copyright (c) 2005, ZetaEngineering * Copyright (c) 1999-2000, Creative Control Concepts * Copyright (c) 1992-1998, Circuit Cellar Inc. * * Version 0.02 R -- May 16,2005 -- Added case, subroutine call * -- direct addressing * -- changing command names for consistency * Version 5.10 R -- Mar 18,2005 -- Making changes for HCS_C * Version 5.03 R -- Aug 27,2002 -- added phone number command * Version 5.02 R -- July 27,2002 -- added logical operators, hex display * Version 5.01 R -- June 24,2002 -- added new operators, inline FPGA regs * Version 1.04 R -- May 24,2002 -- added OUTSTR support for display * Version 1.01 R -- May 24,2002 -- removed HVAC support, added FPGA support rdm * * Version 5.01 -- July 21, 2002 -- Add support for Stat-Link HVAC Interface * Version 4.10 -- June 15, 2000 -- Add support for Stat-Link HVAC Interface * Version 4.01 -- May 1, 2000 -- Add support for CID Name via %N string flag * -- Add support for CID Num via %M string flag * -- Add support for %S fixed size value flag * Version 4.00 -- January 5, 2000 -- Version Increment * Version 3.63 -- December 25, 1999 -- Version Increment * Version 3.62 -- August 25, 1999 * -- Fix 8th Module bug so 8 of each can be used * -- Added more detailed error messages * Version 3.60 -- March 10, 1998 * -- Version change to match update * * Version 3.50 -- April 7, 1997 * -- Final Answer MAN support * * Version 3.05 -- November 3, 1996 * -- Answer MAN support * * Version 3.01 -- May 8, 1995 * -- Version change to match update * * Version 3.00 -- March 16, 1995 * -- Release version * * Version 2.70 -- Version change to match rest of release * Version 2.69 -- Added power fail stuff * Version 2.68 -- Added network module display bitmaps, network string out * Version 2.67 -- Added embedded version, LogSize, and NetByte * Version 2.66 -- Added analog I/O and netbit display bitmaps * Version 2.65 -- Version number change to match rest of beta release * Version 2.64 -- Added more modem and Caller ID stuff * Version 2.63 -- Added Caller ID stuff * Version 2.62 -- Added CONSOLE stuff * Version 2.61 -- Beta release to match rest of suite * -- Upped IF/END array size * * Version 2.55 -- May 18, 1994 * -- Cleaned up CS support for initial beta * Version 2.50 -- First pass at CS support * * Version 2.10 -- December 20, 1993 * -- Release version * * Version 2.00 -- March 3, 1993 * -- Release version * * Version 1.20 -- November 12, 1992 * -- Added MCIR support * -- Added TV-Link support * -- Fix GIF bug * -- Fix tab bug * -- Increase labels to 512 * * Version 1.00 -- March 1992 * -- Release version * * *********************************************************************/ #include #include #include #include #include #include #include #include #define true 1 #define false 0 int verbose_debug = 1; // set to 1 to see debugging output int eqn_debug = 0; // set to 1 to see debugging of equation syntax #define MAX_CHANGEVARS 256 #define NUM_LOC_VARS 256 #define MAX_LINK_LIMIT 100 #define MAX_CHAINLINK_LIMIT 256 #define NUM_HCSNET_DEVICES 16 #define MAX_HCSNET_ADDR 16 #define OPERATOR_TYPE_NORMAL 0 #define OPERATOR_TYPE_NONE 1 #define DONE_TYPE_NORMAL 0 #define DONE_TYPE_THEN 1 #define DONE_TYPE_END 2 #define DONE_TYPE_ELSE 3 #define DONE_TYPE_IS 4 #define DONE_TYPE_EOF 5 #define TOKEN_CFG_OFFSET 0x100 //start of actual token area after cfg stuff #define TOKEN_CFG_TEST 0 //start of actual token area after cfg stuff #define maxtmr 256 #define maxvar 256 #define maxinp 207 #define maxout 207 #define maxadc 135 #define maxdac 31 #define MAX_IFS 1024 #define MAX_IFSTACK 32 #define bell 0x07 #define RET_CHAR 0x0d #define esc 0x1b FILE * fp, *outfile; char *keyp, keyw[80]; /* global token holder */ int version = 109; /* Low two digits must be minor version number */ int linenum = 1; int errors = 0; int numpl = 0; int numir = 0; int numlcd = 0 ; int numdio = 0; int numaman = 0; int numdiop = 0; int sc = 0; int proc_eqn = false; int eqn_end = false; int lparens = 0; int count_parens = 0; int sequence = false; int changevar_count = 0; unsigned int iftable[MAX_IFS][2]; unsigned int curr_backfill; unsigned int ifctr = 0; unsigned int bytectr = 0; unsigned int ifcount = 0; unsigned int endcount = 0; unsigned int iflevel = 0; unsigned int house_used = 0, checksum = 0; unsigned int wait_instance_num; unsigned int wait_start_ptr; unsigned int wait_end_ptr; unsigned int wait_occurred; unsigned int wait_ifctr; // Label is the name to replace with the def value. char label[512][32], def[512][32]; // the hcsnet device array is in the token array configuration space just after version char hcsnet_device_array[TOKEN_EXEC_START]; int hcsnet_device_ptr; char *sptr, substring[128]; int link_count; // FUNCTION PROTOTYPING extern int read_word(); extern int read_prefix(); int atoh(); long longatoh(); void if_error(); void process_then(); void process_equation(); void get_non_comment_keyword(); void backannotate_links(); void dowait(); // functions int open_files (char *input, char *output) { if ((fp = fopen (input, "r")) == NULL) { printf ("\nInput file %s not found", input); errors++; return 1; } if ((outfile = fopen (output, "wb+")) == NULL) { printf ("\nOutput file %s could not be created", output); errors++; return 1; } return 0; } void close_files (void) { fclose (outfile); fclose (fp); } int new_ifctr() { // First, create a stack entry for this IF. This permits nested if // statements. The stack holds the iftable pointer of the current // holding address. When restored, the iftable entry will be // filled with the destination to be backannotated. // The first ifctr location at zero is thrown away (stack push) ifctr++; if (ifctr >= MAX_IFS) { if_error (); ifctr--; } return(ifctr); } //out_file (char ch) // @CHANGE void out_file (int ch) { fputc ((char)ch, outfile); // @CHANGE checksum += (int) ch; bytectr++; } void out_file_no_check (int ch) // @CHANGE { fputc ((char)ch, outfile); //@CHANGE } char get_ch (void) { if (*sptr) return *sptr++; else return fgetc(fp); } void unget_ch (char ch) { if (*sptr) *sptr--; else ungetc (ch, fp); } // replace is a routine that does the DEFINE substitutions // before the read_word routine is called. void replace (char *st) { int i; for (i = 0; *def[i]; i++) { if (strcmp (st, label[i])) continue; strcpy (substring, def[i]); sptr = substring; read_word (st); break; } } //////////////////////////////////////////////////////////////////////// // Read word //////////////////////////////////////////////////////////////////////// // This gets the next word in the file and puts it in // the parameter string. HCS2 had some kind of sensitivity to , this // is removed in HCS_C Xpress. Unfortunately, this routine is rather // obtuse, so I put in some comments to try to make sense of it.. // int read_word (char *input_string) { char ch, *local; int done = false; int leading_whitespace = true; // keep a local copy of the string pointer. local = input_string; // while (!done && ((ch = toupper (get_ch ())) != EOF)) // Now scan the input stream for a word (until end of file) // and convert the word to upper case (so the case statements // dont have to try to check both lower case and upper case // words). leading_whitespace is indicator to skip front // end whitespace. while (!done && ((ch = get_ch ()) != EOF)) // BUG!! msvc toupper calls get_ch twice! { ch = toupper(ch); // library routine that converts to uppercase so that // events.bin can be case insensitive. switch (ch) { case '!': // comment, just ignore through rest of line, then try again while (get_ch () != '\n') // to get a real word. { } linenum++; if (verbose_debug == 1) printf("Line count inc to %d\n",linenum); break; case '\n': linenum++; if (verbose_debug == 1) printf("Line count inc to %d\n",linenum); case '\t': case ',': case ' ': if (leading_whitespace) break; else { done = true; break; } case 0: case ';': if (proc_eqn) { if (leading_whitespace) { *input_string++ = ch; if (ch == '\n') { unget_ch (ch); linenum--; } eqn_end = true; done = true; break; } else { unget_ch (ch); if (ch == '\n') linenum--; eqn_end = true; done = true; break; } } else { if (leading_whitespace) break; else { unget_ch (ch); if (ch == '\n') linenum--; done = true; break; } } case '+': case '~': case '-': case '*': case '/': if (proc_eqn) { if (leading_whitespace) { *input_string++ = ch; done = true; break; } else { unget_ch (ch); done = true; break; } } else { *input_string++ = ch; leading_whitespace = false; // turn off leading_whitespace if not process eqn and get operator break; } case ':': case '"': case '(': case ')': if (leading_whitespace) { *input_string++ = ch; done = true; break; } else { unget_ch (ch); done = true; break; } case '>': case '<': case '=': if (leading_whitespace) { *input_string++ = ch; // ch = toupper (get_ch ()); //@msvc toupper calls get_ch twice! ch = get_ch(); ch = toupper(ch); if ((ch == '>') || (ch == '<') || (ch == '=')) { *input_string++ = ch; done = true; break; } else { unget_ch (ch); done = true; break; } } else { unget_ch (ch); done = true; break; } default: if (iscntrl (ch)) break; *input_string++ = ch; leading_whitespace = false; } } *input_string = '\000'; replace (local); // WARNING THIS WILL SKIP AN APPENDED WORD--must have space return !feof (fp); } //////////////////////////////////////////////////////////////////////// // Read prefix //////////////////////////////////////////////////////////////////////// // This gets the next word in the file and puts it in keyp. It assumes // there may (or may not) be a suffix number portion, so it only reads // up to when a number or space is encountered. It then returns the // value of the number (generally an ID address). // int read_prefix (char *input_string) { char ch, *local; char done; int leading_whitespace; int retval; // keep a local copy of the string pointer. local = input_string; retval = 0; done = false; leading_whitespace = 0; while (!done && ((ch = get_ch ()) != EOF)) // BUG!! msvc toupper calls get_ch twice! { ch = toupper(ch); // library routine that converts to uppercase so that // events.bin can be case insensitive. switch (ch) { case '!': // comment, just ignore through rest of line, then try again while (get_ch () != '\n') // to get a real word. { } linenum++; if (verbose_debug == 1) printf("Line count inc to %d\n",linenum); break; case '\n': linenum++; if (verbose_debug == 1) printf("Line count inc to %d\n",linenum); case '\t': case ',': case ' ': if (leading_whitespace) break; else { done = true; break; } case ')': unget_ch(ch); done = true; break; default: if ((ch < '0') || (ch > '9')) *input_string++ = ch; else { retval = (retval * 10) + (ch & 0xf); break; } leading_whitespace = false; } } *input_string = '\000'; //replace (local); // WARNING THIS WILL SKIP AN APPENDED WORD--must have space return (retval); } int read_line (char *input_string) { char ch; int done = false; // while (!done && ((ch = toupper (fgetc (fp))) != EOF)) //@CHANGE toupper calls get_ch twice! while (!done && ((ch = fgetc (fp)) != EOF)) { ch = toupper(ch); switch (ch) { case '!': unget_ch (ch); done = true; break; case '\n': linenum++; done = true; break; default: if (iscntrl (ch)) break; *input_string++ = ch; } } *input_string = '\000'; return !feof (fp); } int read_string (char *input_string) { char ch; int done = false; while (!done && ((ch = fgetc (fp)) != EOF)) { switch (ch) { case '"': done = true; break; case '\n': linenum++; done = true; break; default: if (iscntrl (ch)) break; *input_string++ = ch; } } *input_string = '\000'; return !feof (fp); } /* 990825 MB - New Error Messages with more detailed info */ void nsyn_error (char *err, char *msg) { printf ("\n* Syntax error in line %i: \"%s\" ", linenum, err); printf ("\n - %s ", msg); errors++; } void nval_error (char *err, char *msg) { printf ("\n* Illegal value in line %i: \"%s\" (%x,%x,%x,%x)", linenum, err, err[0],err[1],err[2],err[3]); printf ("\n - %s \n",msg); errors++; } void syn_error (char *err) { printf ("\n* Syntax error in line %i: \"%s\" ", linenum, err); errors++; } void val_error (char *err) { printf ("\n* Illegal value in line %i: \"%s\" ", linenum, err); errors++; } void if_error (void) { printf ("\n* Too many IFs at line %i", linenum); errors++; } void paren_error (void) { printf ("\n* Parentheses mismatch in line %i.", linenum); errors++; } int bcd (int num) { return (((num / 10) * 16) + (num % 10)); } int atoh(char *ascii_num) { int sum; sum = 0; while (((*ascii_num >= '0') && (*ascii_num <= '9')) || ((*ascii_num >= 'A') && (*ascii_num <= 'F'))) { // If the digit is an ascii letter, treat as hex digit A-F if (*ascii_num > '9') sum = (16 * sum) + ((*ascii_num & 0xf) + 9); else sum = (16 * sum) + (*ascii_num - '0'); ascii_num++; } return(sum); } long longatoh(char *ascii_num) { long sum; sum = 0; while (((*ascii_num >= '0') && (*ascii_num <= '9')) || ((*ascii_num >= 'A') && (*ascii_num <= 'F'))) { // If the digit is an ascii letter, treat as hex digit A-F if (*ascii_num > '9') sum = (16 * sum) + ((*ascii_num & 0xf) + 9); else sum = (16 * sum) + (*ascii_num - '0'); ascii_num++; } return(sum); } int getnumber(char *ascii_num) { if ((*ascii_num == '0') && (*(ascii_num + 1) == 'X')) return(atoh(ascii_num + 2)); else return(atoi(ascii_num)); } ////////////////////////////////////////////////////////////////// // Retrieve operators. This assumes that keyp has a valid word read into // it. The res[] array holds the count of tokens to store and the actual // token data. Do not put unary operators here since they are treated // like operands. If a symbol is both unary and binary, put the binary // handling here, and the unary handling in the operand section. ////////////////////////////////////////////////////////////////// int process_operator (int *res) { get_non_comment_keyword(); // get next valid keyword if (eqn_debug == 1) printf("begun process_operator %s\n",keyp); // These are operators, not operands. OK, whatever. Looks like // just a generic token generation is done without caring whether operands // or operators. Add in the compare tokens so function comparison can be // done in math expressions. if (!strcmp (keyp, "+")) { res[0] = 1; res[1] = 0x75; } else if (!strcmp (keyp, "-")) { res[0] = 1; res[1] = 0x76; } else if (!strcmp (keyp, "*")) { res[0] = 1; res[1] = 0x77; } else if (!strcmp (keyp, "/")) { res[0] = 1; res[1] = 0x78; } // @FPGA added logic to support byte operations // Like C, the &, |, and ~ functions are bit-wise // operations, while the keywords AND, OR,NOT are // logical condition operators. They return 0 // if false and 1 if true. else if (!strcmp (keyp, "&")) { res[0] = 1; res[1] = 0x79; } else if (!strcmp (keyp, "|")) { res[0] = 1; res[1] = 0x7a; } else if (!strcmp (keyp, "BIT")) { res[0] = 1; res[1] = 0x7c; } else if (!strcmp (keyp, "AND")) { res[0] = 1; res[1] = 0x7d; } else if (!strcmp (keyp, "OR")) { res[0] = 1; res[1] = 0x7e; } else if (!strcmp (keyp, "NOT")) { res[0] = 1; res[1] = 0x7f; } // functional compare operators. else if (!strcmp (keyp, "=")) { res[0] = 1; res[1] = 0x01; } else if (!strcmp (keyp, "<>")) { res[0] = 1; res[1] = 0x02; } else if (!strcmp (keyp, "><")) { res[0] = 1; res[1] = 0x02; } else if (!strcmp (keyp, ">")) { res[0] = 1; res[1] = 0x03; } else if (!strcmp (keyp, "<")) { res[0] = 1; res[1] = 0x04; } else if (!strcmp (keyp, ">=")) { res[0] = 1; res[1] = 0x05; } else if (!strcmp (keyp, "=>")) { res[0] = 1; res[1] = 0x05; } else if (!strcmp (keyp, "<=")) { res[0] = 1; res[1] = 0x06; } else if (!strcmp (keyp, "=<")) { res[0] = 1; res[1] = 0x06; } else if (*keyp == 0) { if (verbose_debug == 1) printf("At end of file\n"); return(0); // nothing more in file, so return 0 } else // no operator found { // if (verbose_debug == 1) // printf("ending process_operator type 0, new keyword is %s\n",keyp); return(0); // no operand found, so return 0 } // if (verbose_debug == 1) // printf("ending process_operator type 1, new keyword is %s \n",keyp); return(1); // gets here if found an operator, return 1 } // Skip comments and CRs, refetch the key word. CAUTION: It assumes the keyword // already in the keyp location IS TO BE THROWN AWAY. void get_non_comment_keyword() { keyp = keyw; read_word (keyp); while ((!strcmp (keyp, "!")) || (!strcmp (keyp, "\n"))) { // if (verbose_debug == 1) //printf("Found comment\n"); if (!strcmp (keyp, "!")) { // Since is comment, skip all to after CR while (strcmp (keyp, "\n")) //If not cr, just keep going { keyp = keyw; if (!read_word (keyp)) break; } linenum += 1; } else // Has to be a CR, skip it { keyp = keyw; if (!read_word (keyp)) break; } } // will leave at non comment keyword } ////////////////////////////////////////////////////////////////// // Expression operands // These are used in then (or else) clauses, and now in if expressions. // (this is different than HCS2 which had special IF compare evaluation) // This routine will stop as soon as an unrecognized keyword is read. // This routine assumes that the keyw is invalid and needs a new // value read into keyp. // It returns 0 if no operand/operator is found, 1 if is an operand, // and 2 if an operator. // NOTE!!!! Currently a string operand may set up to 4 tokens, increase // the local token array size if an operand requires more. ////////////////////////////////////////////////////////////////// int process_operand () { int num, bitnum, devnum; int local_tokens[5]; // will leave at non comment keyword get_non_comment_keyword(); if (eqn_debug == 1) printf("begun process_operand %s\n",keyp); // parens are a special case, treat left paren as an enclosed operand if (!strcmp (keyp, "(")) { count_parens++; out_file(TOKEN_LEFTPAREN); process_equation(); // Now must find the right paren if (!strcmp (keyp, ")")) { count_parens--; local_tokens[0] = 1; local_tokens[1] = TOKEN_RIGHTPAREN; } else nsyn_error (keyp, "Expecting \")\""); } else if (!strcmp (keyp, "CHANGED")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); // NOTE: this is a nested equation call. It expects to shut down when the // extra right hand paren (associated with this keyword) occurs. This is the // only way that the equation will stop at the right place if embedded within // another equation. process_equation(); num = changevar_count; changevar_count += 1; if (changevar_count >= MAX_CHANGEVARS) nsyn_error (keyp,"Cannot have more than 256 CHANGE checks in a program\n"); local_tokens[0] = 2; local_tokens[1] = TOKEN_OPRND_CHANGED; local_tokens[2] = num; } else if (!strcmp (keyp, "CHANGE_VALUE")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); // NOTE: this is a nested equation call. It expects to shut down when the // extra right hand paren (associated with this keyword) occurs. This is the // only way that the equation will stop at the right place if embedded within // another equation. process_equation(); num = changevar_count; changevar_count += 1; if (changevar_count >= MAX_CHANGEVARS) nsyn_error (keyp,"Cannot have more than 256 CHANGE checks in a program\n"); local_tokens[0] = 2; local_tokens[1] = TOKEN_OPRND_CHANGE_VALUE; local_tokens[2] = num; } else if (!strcmp (keyp, "VARIABLE")) { get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Variable Operand Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > maxvar)) nval_error (keyp, "Invliad Variable Operand Reference/ID"); read_word (keyp); if (!strcmp (keyp, ")")) { // If done, not a bit var local_tokens[0] = 2; local_tokens[1] = 0x30; local_tokens[2] = num; } else { // If comma, then set the bit in the var bitnum = getnumber (keyp); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Variable Bit Operand Expecting \")\""); local_tokens[0] = 3; local_tokens[1] = 0x31; local_tokens[2] = num; local_tokens[3] = bitnum; } if (verbose_debug == 1) printf("Done with variable set, keyword %s (%x)\n",keyp,keyp[0]); // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > maxvar)) // val_error (keyp); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x30; // local_tokens[2] = num; } else if (!strcmp (keyp, "ADC")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > maxadc)) nval_error (keyp, "Invalid ADC ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x31; local_tokens[2] = num; } else if (!strcmp (keyp, "TIMER")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > maxtmr)) nval_error (keyp, "Invalid Timer ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x32; local_tokens[2] = num; } // 0.04 modification: input mode will require a string to specify device. else if (!strcmp (keyp, "HCSNET")) { num = 0; devnum = 0; read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); devnum = read_prefix (keyp); // Check for remote module names. Right now, support CMB or MIN // (hcs_combo or hcs_mini) if (!strcmp (keyp, "CMB")) { if ((devnum < 0) || (devnum > MAX_HCSNET_ADDR)) nval_error (keyp, "Invalid CMB Device number"); devnum = (devnum << 4) + ID_HCSNET_CMB - 1; num = read_prefix (keyp); if (verbose_debug == 1) printf("Processing CMB operand %c, num %d\n",*keyp,num); if (!strcmp (keyp, "?")) { printf("Got question\n"); num = 23; } else if (!strcmp (keyp, "A")) // Input values { if ((num > 0) && (num < 5)) num = 9 + num - 1; // use 2-5 (A1,A2,A3,A4) else nval_error (keyp, "Invalid CMB input register number"); } else if (!strcmp (keyp, "X")) // Input values { if ((num > 0) && (num < 5)) num = 17 + num - 1; // use 6-9 (A1,A2,A3,A4) else nval_error (keyp, "Invalid CMB input register number"); } else if (!strcmp (keyp, "N")) // Input values { if ((num > 0) && (num < 5)) num = 13 + num - 1; // use 6-9 (A1,A2,A3,A4) else nval_error (keyp, "Invalid CMB input register number"); } else if (!strcmp (keyp, "O")) num = 0; else if (!strcmp (keyp, "P")) num = 1; else if (!strcmp (keyp, "R")) num = 2; else if (!strcmp (keyp, "V")) num = 3; else if (!strcmp (keyp, "K")) num = 4; else if (!strcmp (keyp, "T")) num = 5; else if (!strcmp (keyp, "D")) num = 6; else if (!strcmp (keyp, "I")) num = 7; else if (!strcmp (keyp, "J")) num = 8; else if (!strcmp (keyp, "S")) num = 21; else nsyn_error (keyp, "Invalid CMB Device command"); } else if (!strcmp (keyp, "MIN")) { if ((devnum < 0) || (devnum > MAX_HCSNET_ADDR)) nval_error (keyp, "Invalid MIN Device number"); devnum = (devnum << 4) + ID_HCSNET_MIN - 1; num = read_prefix (keyp); if (verbose_debug == 1) printf("Processing MIN operand %c, num %d\n",*keyp,num); if (!strcmp (keyp, "?")) { printf("Got question\n"); num = 23; } else if (!strcmp (keyp, "K")) num = 0; else if (!strcmp (keyp, "D")) num = 1; else if (!strcmp (keyp, "I")) num = 2; else if (!strcmp (keyp, "J")) num = 3; else if (!strcmp (keyp, "S")) num = 4; else nsyn_error (keyp, "Invalid MIN Device command"); } else if (!strcmp (keyp, "IMG")) { if ((devnum < 0) || (devnum > MAX_HCSNET_ADDR)) nval_error (keyp, "Invalid IMG Device number"); devnum = (devnum << 4) + ID_HCSNET_IMG - 1; num = read_prefix (keyp); if (verbose_debug == 1) printf("Processing IMG operand %c, num %d\n",*keyp,num); if (!strcmp (keyp, "?")) { printf("Got question\n"); num = 23; } else if (!strcmp (keyp, "K")) num = 0; else if (!strcmp (keyp, "D")) num = 1; else if (!strcmp (keyp, "I")) num = 2; else if (!strcmp (keyp, "J")) num = 3; else if (!strcmp (keyp, "S")) num = 4; else nsyn_error (keyp, "Invalid IMG Device command"); } else if (!strcmp (keyp, "TERM")) { if ((devnum < 0) || (devnum > MAX_HCSNET_ADDR)) nval_error (keyp, "Invalid TERM Device number"); devnum = (devnum << 4) + ID_HCSNET_TERM - 1; num = read_prefix (keyp); if (verbose_debug == 1) printf("Processing TERM operand %c, num %d\n",*keyp,num); if (!strcmp (keyp, "?")) { printf("Got question\n"); num = 23; } else if (!strcmp (keyp, "O")) num = 0; else nsyn_error (keyp, "Invalid TERM Device command"); } else if (!strcmp (keyp, "DIO")) { printf ("GOT DIO, devnum %d",devnum); if ((devnum < 0) || (devnum > MAX_HCSNET_ADDR)) nval_error (keyp, "Invalid DIO Device number"); devnum = (devnum << 4) + ID_HCSNET_DIO - 1; num = read_prefix (keyp); if (verbose_debug == 1) printf("Processing DIO operand %c, num %d\n",*keyp,num); if (!strcmp (keyp, "?")) { printf("Got question\n"); num = 23; } else if (!strcmp (keyp, "O")) num = 0; else nsyn_error (keyp, "Invalid DIO Device command"); } read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 3; local_tokens[1] = TOKEN_OPRND_HCSNET; local_tokens[2] = devnum; local_tokens[3] = num; } else if (!strcmp (keyp, "INPUT")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > maxtmr)) nval_error (keyp, "Invalid Input ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x17; local_tokens[2] = num; } // NOT YET IMPLEMENTED //else if (!strcmp (keyp, "IRCODE")) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 511)) // nval_error (keyp, "Valid IR Codes are 0-511"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 3; // local_tokens[1] = 0x33; // local_tokens[2] = num % 256; // local_tokens[3] = num / 256; // } else if (!strcmp (keyp, "TRUE")) { local_tokens[0] = 1; local_tokens[1] = 0x36; } else if (!strcmp (keyp, "ON")) { local_tokens[0] = 1; local_tokens[1] = 0x36; } else if (!strcmp (keyp, "FALSE")) { local_tokens[0] = 1; local_tokens[1] = 0x37; } else if (!strcmp (keyp, "OFF")) { local_tokens[0] = 1; local_tokens[1] = 0x37; } else if (!strcmp (keyp, "RANDOM")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 255)) nval_error (keyp, "RANDOM value should be 0-255"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x38; local_tokens[2] = num; } else if (!strcmp (keyp, "VOICE")) { local_tokens[0] = 2; local_tokens[1] = TOKEN_OPRND_FPGA_IN; local_tokens[0] = 1; } else if (!strcmp (keyp, "MONTH")) { local_tokens[0] = 1; local_tokens[1] = 0x39; } else if (!strcmp (keyp, "DAY")) { local_tokens[0] = 1; local_tokens[1] = 0x3A; } else if (!strcmp (keyp, "YEAR")) { local_tokens[0] = 1; local_tokens[1] = 0x3B; } else if (!strcmp (keyp, "DOW")) { local_tokens[0] = 1; local_tokens[1] = 0x3C; } else if (!strcmp (keyp, "HOUR")) { local_tokens[0] = 1; local_tokens[1] = 0x3D; } else if (!strcmp (keyp, "MINUTE")) { local_tokens[0] = 1; local_tokens[1] = 0x3E; } else if (!strcmp (keyp, "SECOND")) { local_tokens[0] = 1; local_tokens[1] = 0x3F; } // NOT SUPPORTED //else if (!strcmp (keyp, "DTMFDIGIT") & sequence) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 255)) // nval_error (keyp, "Expecting value between 0 and 255"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x40; // local_tokens[2] = num; // } // NOT SUPPORTED // else if (!strcmp (keyp, "DTMFNUMBER") & sequence) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 255)) // nval_error (keyp, "Expecting value between 0 and 255"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x41; // local_tokens[2] = num; // } // NOT SUPPORTED // else if (!strcmp (keyp, "RINGS")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x42; // } // NOT SUPPORTED // else if (!strcmp (keyp, "DIALTONE") & sequence) // { // local_tokens[0] = 1; // local_tokens[1] = 0x43; // } // NOT SUPPORTED // else if (!strcmp (keyp, "CALLPROGRESS") & sequence) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 255)) // nval_error (keyp, "Expecting CALLPROGRESS value between 0 and 255"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x44; // local_tokens[2] = num; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDNEW")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x45; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDMONTH")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x46; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDDAY")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x47; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDHOUR")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x48; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDMINUTE")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x49; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDAREA")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x4A; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDEXCH")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x4B; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CIDNUMBER")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x4C; // } // else if (!strcmp (keyp, "LOGSIZE")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x4D; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "NETBYTE")) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 40)) // nval_error (keyp, "Expecting NETBYTE value between 0 and 40"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x4E; // local_tokens[2] = num; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "ACPOWER")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x4F; // } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "ACFAILED")) // { // local_tokens[0] = 1; // local_tokens[1] = 0x50; // } // NOT SUPPORTED // else if (!strcmp (keyp, "FREQUENCY")) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 7)) // nval_error (keyp, "Expecting FREQUENCY value between 0 and 7"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x51; // local_tokens[2] = num; // } // NOT SUPPORTED // else if (!strcmp (keyp, "TOTAL")) // { // read_word (keyp); // if (strcmp (keyp, "(")) // nsyn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 7)) // nval_error (keyp, "Expecting TOTAL value between 0 and 7"); // read_word (keyp); // if (strcmp (keyp, ")")) // nsyn_error (keyp, "Expecting \")\""); // local_tokens[0] = 2; // local_tokens[1] = 0x52; // local_tokens[2] = num; // } else if (!strcmp (keyp, "KEYDIGIT")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 7)) nval_error (keyp, "Expecting KEYDIGIT value between 0 and 7"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x53; local_tokens[2] = num; } else if (!strcmp (keyp, "KEYNUMBER")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 7)) nval_error (keyp, "Expecting KEYNUMBER value between 0 and 7"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = 0x54; local_tokens[2] = num; } else if (!strcmp (keyp, "HCS_FPGA")) { read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); if ((*keyp >= '0') && (*keyp <= '9')) { num = getnumber (keyp); // FPGA addresses are word offsets if ((num < 0) || (num > 255)) val_error (keyp); read_word (keyp); } else { if (!strcmp (keyp, "FPGA_VOICE")) num = 1; else if (!strcmp (keyp, "FPGA_SPI")) num = 2; else if (!strcmp (keyp, "FPGA_RS232_0")) num = 3; else if (!strcmp (keyp, "FPGA_INSTEON")) num = 3; else if (!strcmp (keyp, "FPGA_RS485_0")) num = 5; else if (!strcmp (keyp, "FPGA_HCSNET")) num = 5; else if (!strcmp (keyp, "FPGA_RS485_1")) num = 6; else if (!strcmp (keyp, "FPGA_FASTNET")) num = 6; else if (!strcmp (keyp, "FPGA_RS485_2")) num = 7; else if (!strcmp (keyp, "FPGA_KEYBD")) num = 8; else if (!strcmp (keyp, "FPGA_X10A")) num = 10; else if (!strcmp (keyp, "FPGA_X10B")) num = 11; else nsyn_error (keyp, "Invalid HCS_FPGA keyword \"=\""); } if ((num < 0) || (num > 255)) nval_error (keyp, "Expecting HCS_FPGA register select between 0 and 255"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); local_tokens[0] = 2; local_tokens[1] = TOKEN_OPRND_FPGA_IN; local_tokens[2] = num; } else if (!strcmp (keyp, "X10")) { local_tokens[0] = 1; local_tokens[1] = TOKEN_OPRND_X10; } else if (!strcmp (keyp, "X10ERROR")) { local_tokens[0] = 1; local_tokens[1] = TOKEN_OPRND_X10ERROR; } else if (!strcmp (keyp, "KEYBD")) { local_tokens[0] = 1; local_tokens[1] = 0x56; } // NOT YET IMPLEMENTED // else if (!strcmp (keyp, "CID")) // { // read_word (keyp); // if (strcmp (keyp, "(")) //syn_error (keyp, "Expecting \"(\""); // read_word (keyp); // num = getnumber (keyp); // if ((num < 0) || (num > 255)) //val_error (keyp, "Expecting CID buffer value between 0 and 255"); // read_word (keyp); // if (strcmp (keyp, ")")) //syn_error (keyp, "Expecting \")\""); // local_tokens[0] = 1; // local_tokens[1] = 0x57; // local_tokens[2] = num; // } else if (!strcmp (keyp, "RESET")) { local_tokens[0] = 1; local_tokens[1] = 0x16; } // Unary operators are treated like an operand with a recursive call // to process_operand else if (!strcmp (keyp, "ABS")) { out_file(TOKEN_OP_ABS); process_operand(); // recursive call will fetch unary operand local_tokens[0] = 0; // nothing to load after unary operator } else if (!strcmp (keyp, "-")) { out_file(TOKEN_OP_NEG); process_operand(); // recursive call will fetch unary operand local_tokens[0] = 0; // nothing to load after unary operator } else if (!strcmp (keyp, "~")) { out_file(TOKEN_OP_LNOT); process_operand(); // recursive call will fetch unary operand local_tokens[0] = 0; // nothing to load after unary operator } // @FPGA added ability to enter number in hex format // else if ((*keyp == '0') && (*(keyp + 1) == 'X')) // { // keyp = keyp + 2; //skip over 0x // num = atoh (keyp); // if ((num >= 0) && (num <= 255)) // { // local_tokens[0] = 2; // local_tokens[1] = 0x34; // local_tokens[2] = num; // } // else // { // local_tokens[0] = 3; // local_tokens[1] = 0x35; // local_tokens[2] = num % 256; // local_tokens[3] = num / 256; // } // } else if (isdigit (keyp[0])) { num = getnumber (keyp); if ((num & 0xff00) == 0) { local_tokens[0] = 2; local_tokens[1] = 0x34; local_tokens[2] = num; } else { local_tokens[0] = 3; local_tokens[1] = 0x35; local_tokens[2] = num & 0xff; local_tokens[3] = (num & 0xff00) >> 8; } } else if (*keyp == 0) { if (verbose_debug == 1) printf("At end of file\n"); return(0); // nothing more in file, so return 0 } else // no operand found { printf("ending process_operand type 0, new keyword is %s \n",keyp); return(0); // no operand found, so return 0 } if (eqn_debug == 1) printf("ending process_operand type 1, new keyword is %s \n",keyp); // store the token and parameters into the events.bin output file. for (num = 1; num <= local_tokens[0]; num++) out_file(local_tokens[num]); return(1); // gets here if found an operand, return 1 } ////////////////////////////////////////////////////////// // Process_equation is used as the then (or else) clause, // and now also for the IF compare expression. This is new // from HCS2, which had a special IF compare expression evaluator. // I got rid of that (process_if) to simplify maintenance and to give // the full power of a math expression in the IF compare clause. // count_parens is a badly done means of tracking mismatched // parens that keeps this from being recursive (global var). // I get around this sort of with the local_parens tracking. // This routine will stop if there is an extra left hand paren. // // There is a problem in that this does not know when to stop // processing. If it reads a terminate token (ELSE/IS/END) it // can stop, but if there are consecutive actions, it does not // have a way to distinguish. For example, the following // // timer(0) = variable(0) // variable(0) = timer(0) // is legal but doesnt have a specific syntactical terminator // between them so equation will not stop. // // So--the fix is to make process_equation check for consecutive // operands. It will terminate either if a keyword is unrecognized // (typically a terminator keyword such as ELSE/IS/END) or if there // are two consecutive operatands. // // process_equation assumes that an old keyword is present in keyp. // and that a new one must be fetched. // process_equation will end with the terminating keyword in the // keyp location. ////////////////////////////////////////////////////////// void process_equation () { // maximum of four bytes in any given operand. Can increase this if need // more. int i; int token_list[5]; int local_paren_count; int loc_eqn_end; if (eqn_debug == 1) printf("Starting equation processing at %x word %s\n",bytectr+TOKEN_CFG_OFFSET, keyp); proc_eqn = true; loc_eqn_end = false; local_paren_count = count_parens; // initialize to current paren count global // now process operands followed by operators. The left paren // is treated like an operand and recursively calls process_equation. while (loc_eqn_end == false) { // process operators and operands. If an operand is not followed by // an operator, or an operator is not followed by an operand, terminate. // This can legally happen if two actions in sequence occur--but must // stop the equation processing. In addition, if the operator is a // unary operator (eg, "-" or "~") then it may follow another operator. if (process_operand() != 1) // retrieve new operand from file { // and save info into token_array loc_eqn_end = true; // stop processing this equation nsyn_error (keyp, "Expecting an operand"); } if (process_operator(token_list) == 1) // retrieve new operator from file { // store the token and parameters into the events.bin output file. // Dont load a right paren if this is a nested equation for (i = 1; i <= token_list[0]; i++) out_file (token_list[i]); // Now can retrieve another keyword (must be operand) } // If the operand is not followed by an operator, then all done, // exit. else { if (verbose_debug == 1) printf("End equation, not followed by operator at %x with keyword %s\n",bytectr+TOKEN_CFG_OFFSET,keyp); loc_eqn_end = true; // stop processing this equation } // and leave terminating word in keyp. } if (count_parens != local_paren_count) // should have balanced parens at this point paren_error (); if (eqn_debug == 1) printf("Ending equation processing at %x, with keyword %s\n",bytectr+TOKEN_CFG_OFFSET,keyp); return; } //////////////////////////////////////////////////////////////////////////////////// // ACTIONS. // All actions must exit with a token word in the keyw register. //////////////////////////////////////////////////////////////////////////////////// void dothentmr (void) { int timer; get_non_comment_keyword(); // skip past TIMER keyword if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); timer = getnumber (keyp); if ((timer < 0) || (timer > maxtmr)) nval_error (keyp, "Invalid Timer ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); read_word (keyp); if (!strcmp (keyp, "OFF")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x00); // specify timer mode } else if (!strcmp (keyp, "ON")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x01); // specify timer mode } else if (!strcmp (keyp, "CLEAR")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x02); // specify timer mode } else if (!strcmp (keyp, "PAUSE")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x03); // specify timer mode } else if (!strcmp (keyp, "CONTINUE")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x04); // specify timer mode } else if (!strcmp (keyp, "MINUTES")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x05); // specify timer mode } else if (!strcmp (keyp, "SECONDS")) { out_file (TOKEN_ACTION_TIMER); out_file (timer); out_file (0x06); // specify timer mode } else nsyn_error (keyp, "Expecting ON, OFF, CLEAR, PAUSE, CONTINUE, SECONDS, or MINUTES"); get_non_comment_keyword(); // get a new keyword for next action } void dothenout (void) { int outnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); outnum = getnumber (keyp); if ((outnum < 0) || (outnum > maxout)) nval_error (keyp, "Invalid Output ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (TOKEN_ACTION_OUT); out_file (outnum); process_equation(); out_file (TOKEN_STOPMATH); } void dothenethreset (void) { get_non_comment_keyword(); out_file (TOKEN_ACTION_ETHRESET); } void doinc (void) { int varnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); if (strcmp (keyp, "VARIABLE")) nsyn_error (keyp, "Expecting Variable Label/Reference"); read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); varnum = getnumber (keyp); if ((varnum < 0) || (varnum > maxvar)) nval_error (keyp, "Invalid Variable Reference"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); out_file (0x80); out_file (varnum); } void dodec (void) { int varnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); if (strcmp (keyp, "VARIABLE")) nsyn_error (keyp, "Expecting Variable Label/Reference"); read_word (keyp); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); varnum = getnumber (keyp); if ((varnum < 0) || (varnum > maxvar)) nval_error (keyp, "Invalid Variable Reference"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); out_file (0x81); out_file (varnum); } void domsg (void) { char *strp, str[160]; int i, j; get_non_comment_keyword(); // skip past previous keyword to quote if (strcmp (keyp, "\"")) nsyn_error (keyp, "Expecting \""); strp = str; read_string (strp); // retrieve the string from the file if (verbose_debug == 1) printf("Got message string %s (%x)\n",strp,strp[0]); if (strcmp (keyp, "\"")) nsyn_error (keyp, "Hmm, Expecting \""); // NOTE!!! STRING ESCAPES ARE NO LONGER COMPILED!! STRINGS ARE STORED AS IS, // HCS_C FIRMWARE NOW EXPANDS THEM. // // Tick defines are permitted, this causes a string substitution. while (*strp != 0) { if (*strp == '`') { printf("Found Tick define %s\n",strp); strp++; // Get the tick define label i = 0; while ((*strp != '`') && (*strp != RET_CHAR)) { str[i] = *strp; strp++; i++; } str[i] = 0; // put string termination to complete the label to search // If gets here, substitue the string with its define for outputting. Search // for the label in the label array, and if found, output the corresponding // definitition. for (i = 0; *def[i]; i++) { // If finds a define match, output the defined equivalant until ends with 0 if (!strcmp (str, label[i])) { j = 0; // replace the label with the definition. // Defines automatically add space at end of string to protect against unintended // expansions of the define string, but this is undesirable for tick defines, so // dont use the space (scan ahead by one for the zero, skipping the assumed space). while (def[i][j + 1] != 0) { out_file (def[i][j]); j += 1; } printf("Tick define %s to %s\n",label[i],def[i]); break; // found define, exit for loop } } printf("+"); } else out_file (*strp); strp++; } out_file (RET_CHAR); get_non_comment_keyword(); if (verbose_debug == 1) printf("Ending message, new keyword %s (%x)\n",keyp,keyp[0]); } void do_hcsnet_msg () { // int hcsnet_num; get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (TOKEN_ACTION_HCSNET); //out_file (hcsnet_num); domsg (); } void do_video_msg () { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (TOKEN_ACTION_VIDEO_STRING); domsg (); } void dodiomsg (void) { int dionum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); dionum = getnumber (keyp); if ((dionum < 0) || (dionum > 7)) nval_error (keyp, "Invalid DIO Module ID (0-7)"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0x89); out_file (dionum); domsg (); } void dotvmsg (void) { int tvnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); tvnum = getnumber (keyp); if ((tvnum < 0) || (tvnum > 7)) nval_error (keyp, "Invalid TV Module ID (0-7)"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0x8A); out_file (tvnum); domsg (); } void doconmsg (void) { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (TOKEN_ACTION_CONS_STRING); domsg (); } void dothenx10 (void) { char modlet; int modnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); modlet = *keyp++; modnum = getnumber (keyp); if ((modlet < 'A') || (modlet > 'P')) nval_error (keyp, "Invalid X10 House Code. Should be A-P"); switch(modlet) { case 'A': modlet = 0x6; break; case 'B': modlet = 0x7; break; case 'C': modlet = 0x4; break; case 'D': modlet = 0x5; break; case 'E': modlet = 0x8; break; case 'F': modlet = 0x9; break; case 'G': modlet = 0xa; break; case 'H': modlet = 0xb; break; case 'I': modlet = 0xe; break; case 'J': modlet = 0xf; break; case 'K': modlet = 0xc; break; case 'L': modlet = 0xd; break; case 'M': modlet = 0x0; break; case 'N': modlet = 0x1; break; case 'O': modlet = 0x2; break; case 'P': modlet = 0x3; break; default: modlet = 0x6; break; } if ((modnum < 1) || (modnum > 16)) nval_error (keyp, "Invalid X10 Unit Code. Should be 1-16"); switch(modnum) { case 1: modnum = 0x60; break; case 2: modnum = 0x70; break; case 3: modnum = 0x40; break; case 4: modnum = 0x50; break; case 5: modnum = 0x80; break; case 6: modnum = 0x90; break; case 7: modnum = 0xa0; break; case 8: modnum = 0xb0; break; case 9: modnum = 0xe0; break; case 10: modnum = 0xf0; break; case 11: modnum = 0xc0; break; case 12: modnum = 0xd0; break; case 13: modnum = 0x00; break; case 14: modnum = 0x10; break; case 15: modnum = 0x20; break; case 16: modnum = 0x30; break; default: modnum = 0x60; break; } read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); read_word (keyp); if (!strcmp (keyp, "ALLOFF")) { out_file(TOKEN_ACTION_X10_FUNCT); out_file(0x000 | modlet); // code 0x30N } else if (!strcmp (keyp, "ALLON")) { out_file(TOKEN_ACTION_X10_FUNCT); out_file(0x080 | modlet); // code 0x38N } else if (!strcmp (keyp, "ON")) { out_file(TOKEN_ACTION_X10_KEY); out_file(modnum | modlet); // code 0x38N out_file(TOKEN_ACTION_X10_FUNCT); out_file(0x40 | modlet); // code 0x38N } else if (!strcmp (keyp, "OFF")) { out_file(TOKEN_ACTION_X10_KEY); out_file(modnum | modlet); // code 0x38N out_file(TOKEN_ACTION_X10_FUNCT); out_file(0xc0 | modlet); // code 0x38N } else if (!strcmp (keyp, "DIM")) { out_file(TOKEN_ACTION_X10_KEY); out_file(modnum | modlet); // code 0x38N out_file(TOKEN_ACTION_X10_FUNCT); out_file(0x20 | modlet); // code 0x38N } else if (!strcmp (keyp, "BRIGHT")) { out_file(TOKEN_ACTION_X10_KEY); out_file(modnum | modlet); // code 0x38N out_file(TOKEN_ACTION_X10_FUNCT); out_file(0xa0 | modlet); // code 0x38N } else nsyn_error (keyp, "Invalid X10 Action. Expecting ALLON, ALLOFF, ON, OFF, DIM, or BRIGHT"); get_non_comment_keyword(); // Now prefetch next keyword for next // action } void dotheninsteon (void) { int dimval; long addr; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Insteon Expecting \"(\""); read_word (keyp); // get first byte of address addr = longatoh (keyp); read_word (keyp); // get comma if (strcmp (keyp, ")")) nsyn_error (keyp, "Insteon Expecting \")\""); read_word (keyp); // get comma if (strcmp (keyp, "=")) nsyn_error (keyp, "Insteon Expecting \"=\""); read_word (keyp); // get dimming value dimval = getnumber (keyp); out_file (TOKEN_ACTION_INSTEON); out_file ((int)((addr & 0xff0000) >> 16)); out_file ((int)((addr & 0xff00) >> 8)); out_file ((int)(addr & 0xff)); out_file (dimval); if (verbose_debug == 1) printf("Done with Insteon set, addr %x %x\n",addr,dimval); get_non_comment_keyword(); } void dothenvar (void) { int num,bitnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Variable Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > maxvar)) nval_error (keyp, "Invliad Variable Reference/ID"); read_word (keyp); if (!strcmp (keyp, ")")) { // If done, not a bit var read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Variable Expecting \"=\""); out_file (TOKEN_ACTION_VAR); out_file (num); process_equation (); out_file (TOKEN_STOPMATH); } else { // If comma, then set the bit in the var bitnum = getnumber (keyp); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Variable Bit Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Variable Bit Expecting \"=\""); out_file (TOKEN_ACTION_VARBIT); out_file (num); out_file (bitnum); process_equation (); out_file (TOKEN_STOPMATH); } if (verbose_debug == 1) printf("Done with variable set, keyword %s (%x)\n",keyp,keyp[0]); } void dorefresh (void) { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa2); process_equation (); out_file (TOKEN_STOPMATH); } void docleartotal (void) { int varnum; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); varnum = getnumber (keyp); if ((varnum < 0) || (varnum > 7)) nval_error (keyp, "Expecting Module ID 0-7"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); out_file (0x9A); out_file (varnum); } // HCS_C Xpress 0.04 expands the LOG keyword to permit several modes of // operation. int dolog (void) { int num; int retval; int logmode; short done; logmode = 0; // default no action get_non_comment_keyword(); if (!strcmp (keyp, "(")) { read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 254)) nval_error (keyp, "Log Event ID should be 0-254"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa4); out_file (num); process_equation (); out_file (TOKEN_STOPMATH); return(retval); } else if (!strcmp (keyp, "MODE")) { done = 0; while (done == 0) { keyp = keyw; read_word (keyp); if (!strcmp (keyp, "ON")) // turn on log mode logmode |= LOG_MODE_ON; if (!strcmp (keyp, "OFF")) // turn off log mode logmode |= LOG_MODE_OFF; if (!strcmp (keyp, "RESET")) // reset the log mode pointer logmode |= LOG_MODE_RESET; if (!strcmp (keyp, "NORMAL")) // normal log mode format time plus flag logmode |= LOG_MODE_NORMAL; if (!strcmp (keyp, "VALUE")) // log a value logmode |= LOG_MODE_VALUE; if (!strcmp (keyp, "TIME")) // log the time logmode |= LOG_MODE_TIME; if (!strcmp (keyp, "ACTIONS")) // log all actions in the events file logmode |= LOG_MODE_ACTIONS; if (!strcmp (keyp, "HCSNET")) // log hcsnet characters logmode |= LOG_MODE_ACTIONS; if (!strcmp (keyp, "X10")) // log X10 data logmode |= LOG_MODE_ACTIONS; else { done = 1; if (logmode == 0) nsyn_error (keyp, "Expecting log mode NORMAL/OFF/SHORT/ACTIONS/HCSNET/X10"); } get_non_comment_keyword(); // Now prefetch next keyword for next // action } out_file (TOKEN_ACTION_LOG_MODE); out_file (logmode); } else nsyn_error (keyp, "Expecting \"(\""); } void domcirmsg (void) { int num; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 7)) nval_error (keyp, "Expecting MCIR ID 0-7"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa3); out_file (num); process_equation (); out_file (TOKEN_STOPMATH); } void domrings (void) { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa5); process_equation (); out_file (TOKEN_STOPMATH); } void docid (void) { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa6); process_equation (); out_file (TOKEN_STOPMATH); } void dothennbyt (void) { int num; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 7)) val_error (keyp); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0xa7); out_file (num); process_equation (); out_file (TOKEN_STOPMATH); } // hcsfpga command writes to the FPGA registers. This expects // a decimal register select void dothenhcsfpga (void) { int num; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); if ((*keyp >= '0') && (*keyp <= '9')) { num = getnumber (keyp); // FPGA addresses are word offsets if ((num < 0) || (num > 255)) nval_error (keyp, "Expecting HCS_FPGA register select between 0 and 255"); read_word (keyp); } else { if (!strcmp (keyp, "FPGA_MODE")) num = 0; else if (!strcmp (keyp, "FPGA_VOICE")) num = 1; else if (!strcmp (keyp, "FPGA_SPI")) num = 2; else if (!strcmp (keyp, "FPGA_INSTEON")) num = 3; else if (!strcmp (keyp, "FPGA_RS232_0")) num = 3; else if (!strcmp (keyp, "FPGA_RS485_0")) num = 5; else if (!strcmp (keyp, "FPGA_HCSNET")) num = 5; else if (!strcmp (keyp, "FPGA_RS485_1")) num = 6; else if (!strcmp (keyp, "FPGA_FASTNET")) num = 6; else if (!strcmp (keyp, "FPGA_RS485_2")) num = 7; else if (!strcmp (keyp, "FPGA_LCD")) num = 8; else if (!strcmp (keyp, "FPGA_X10")) num = 10; else if (!strcmp (keyp, "FPGA_RELAY")) num = 12; else nsyn_error (keyp, "Invalid HCS_FPGA keyword \"=\""); } if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0x9b); out_file (num); process_equation (); out_file (TOKEN_STOPMATH); // get_non_comment_keyword(); // Now prefetch next keyword for next // action } // Do_voice command initiates a voice playback. Multiple commands will // override prior commands. void do_voice (void) { int num; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); // FPGA addresses are word offsets if ((num < 0) || (num > 1023)) val_error (keyp); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); read_word (keyp); if (!strcmp (keyp, "OFF")) out_file (TOKEN_ACTION_VOICE_STOP); else if (!strcmp (keyp, "LOCK")) out_file (TOKEN_ACTION_VOICE_LOCK); else if (!strcmp (keyp, "UNLOCK")) out_file (TOKEN_ACTION_VOICE_UNLOCK); else if (!strcmp (keyp, "ON")) { out_file (TOKEN_ACTION_VOICE); out_file (num & 0xff); out_file ((num >> 8) & 0xff); } else if (!strcmp (keyp, "RECORD")) { out_file (TOKEN_ACTION_VOICE_RECORD); out_file (num & 0xff); out_file ((num >> 8) & 0xff); } else nsyn_error (keyp, "Expecting voice command OFF/ON/LOCK/UNLOCK/RECORD"); get_non_comment_keyword(); // Now prefetch next keyword for next // action } void dothenhcsstr (void) { get_non_comment_keyword(); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0x9c); domsg(); } void dothenalert (void) { int alertnum; get_non_comment_keyword(); // skip past TIMER keyword if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); alertnum = getnumber (keyp); if ((alertnum < 0) || (alertnum > 15)) nval_error (keyp, "Invalid ALERT ID"); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); read_word (keyp); if (!strcmp (keyp, "OFF")) { out_file (TOKEN_ACTION_ALERT_OFF); out_file (alertnum); } else if (!strcmp (keyp, "ON")) { out_file (TOKEN_ACTION_ALERT_ON); out_file (alertnum); } else nsyn_error (keyp, "Expecting ON | OFF"); get_non_comment_keyword(); } void dothenphone (void) { int num; get_non_comment_keyword(); if (strcmp (keyp, "(")) nsyn_error (keyp, "Expecting \"(\""); read_word (keyp); num = getnumber (keyp); if ((num < 0) || (num > 50)) val_error (keyp); read_word (keyp); if (strcmp (keyp, ")")) nsyn_error (keyp, "Expecting \")\""); read_word (keyp); if (strcmp (keyp, "=")) nsyn_error (keyp, "Expecting \"=\""); out_file (0x9d); out_file (num); domsg(); } void dowait_secs (void) { out_file (TOKEN_ACTION_WAIT_SECS); dowait(); } void dowait_mins (void) { out_file (TOKEN_ACTION_WAIT_MINUTES); dowait(); } void dowait (void) { int prev_end_ptr_loc; // get_non_comment_keyword(); // if (!strcmp (keyp, "UNTIL")) // { // out_file (TOKEN_ACTION_WAIT_UNTIL); // out_file (wait_instance_num); // out_file (wait_start_ptr); // out_file (wait_start_ptr >> 8); // must backannotate end address here // wait_ifctr = new_ifctr(); // iftable[wait_ifctr][0] = bytectr + TOKEN_CFG_OFFSET; // set location of backfill // if (verbose_debug == 1) //intf(" backannotate WAIT WHILE ptr %x loc %x\n",wait_ifctr,bytectr); // out_file (0x00); // end of backfill chain // out_file (0x00); // process_equation (); // out_file (TOKEN_STOPMATH); // } // else if (!strcmp (keyp, "WHILE")) // { // out_file (TOKEN_ACTION_WAIT_WHILE); // out_file (wait_instance_num); // out_file (wait_start_ptr); // out_file (wait_start_ptr >> 8); // // must backannotate end address here // wait_ifctr = new_ifctr(); // iftable[wait_ifctr][0] = bytectr + TOKEN_CFG_OFFSET; // set location of backfill // if (verbose_debug == 1) //intf(" backannotate WAIT WHILE ptr %x loc %x\n",wait_ifctr,bytectr); // out_file (0); // out_file (0); // process_equation (); // out_file (TOKEN_STOPMATH); // } // else { // wait_time = getnumber (keyp); out_file (wait_instance_num); process_equation (); out_file (TOKEN_STOPMATH); // out_file (wait_time); // out_file (wait_time >> 8); out_file (wait_start_ptr); out_file (wait_start_ptr >> 8); // END pointers for all waits have to be backannotated. If there is only one WAIT // in this module, this is initialized to zero and indicates the end of the back- // chaining of end pointers. If there is more than one WAIT, and this is not the // first, must allow back-chaining, so make this value stored here the previous // WAIT end pointer back-annotate value. This will only work if the iftable is // zeroed out at the start of compiling. // If this is not the first wait of an IF module, do not create a new backannotate // link ptr, just use the old one. Replace its backannotate location with the // new one, but put in a chained backannotate link so the previous one will get // backannotated. if (wait_occurred == 1) { prev_end_ptr_loc = iftable[wait_ifctr][0]; if (verbose_debug == 1) printf(" back-chain old WAIT