/*   cardisplay.c                                                             */
/*   (Copyright All rights Reserved September, October, November 2008)        */
/*   Author: Mauro Grassi.                                                    */
/*   Car Scrolling Display (Silicon Chip project) interface                   */
/*   program...                                                               */
/* Compiled with Dev-Cpp 4.9.9.2 linked with libsetupapi.a                    */

#include <windows.h>
#include <math.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h> 
#include <time.h>
#include "_mpusbapi.h"
#include <fstream.h>
#include <conio.h>

using namespace std;

/*

 As of version 10.97 there is auto sizing of map symbol variables- ie. extracted from the
 map table information.

*/     

#define HOSTVERHIGH         		13
#define HOSTVERLOW          		00
#define TARGET_HI_VERSION   		1
#define TARGET_LO_VERSION   		256
//
// some imodes other than zero
//
#define LOGGING_MODE				1
#define FLASHWRITE_MODE				2
//
// These three describe the RAM area of device (firmware)
// used to automatically get variable sizes from the MAP address information!
//
#define BIG_FONT_MIN		    0x20
#define BIG_FONT_MAX			0x7A
//
#define DEVICE_TOTAL_RAM        2048
#define DEVICE_LOW_RAM          0x000   // the lowest RAM address
#define DEVICE_HIGH_RAM         0x7FF   // the highest RAM address
#define MAX_SETTINGS_RAM        32000
#define SETTINGS_LINE_LENGTH    16
//
#define DEFAULT_DIVIDER_UPPER	56000.0 // in Ohms
#define DEFAULT_DIVIDER_LOWER	10000.0	// in Ohms
#define VOLTAGEREF				5.0
#define VOLTAGE_RANGE			VOLTAGEREF*(1.0+(DEFAULT_DIVIDER_UPPER/DEFAULT_DIVIDER_LOWER))	// this is the maximum voltage range for battery sense, approx 33V
#define FIXED_POINT_SCALE		255.0
#define DEFAULT_BATTSCALING		(FIXED_POINT_SCALE-SCALE_OFFSET)
#define SCALE_OFFSET		    128.0
#define BATTSCALE				(VOLTAGE_RANGE/255.0)
#define DEFAULT_BATTMIN			(4.0/BATTSCALE)
#define DEFAULT_BATTMAX			(9.0/BATTSCALE)
#define VOLTAGE_RANGE_SCALE		(VOLTAGE_RANGE/1023.0)
//
#define FREQ_MAX                10000.0
#define DEFAULT_DIV_U			22000.0			    // in Ohms (this is for the analog channels excluding the battery)
#define DEFAULT_DIV_L			10000.0			    // in Ohms
#define DEFAULT_ANALOG_SCALE    ((1.0+(DEFAULT_DIV_U/DEFAULT_DIV_L))*VOLTAGEREF)      // this is the default for polynomial (deg 0) for analog vars (Note: 3.2=22k and 10k divider)
#define DEFAULT_FREQUENCY_SCALE (FREQ_MAX)          // this is the default for polynomial (deg 0) for frequency vars
#define DEFAULT_DUTY_SCALE		100.0
//
#define MAXEEVARSIZE            12    // above this the system var processor gives size error, for safety
#define TOP_EE_ADDRESS          0xFF
#define BOTTOM_EE_ADDRESS       0x00
#define RETRIES                 20
#define IMODE_DELAY             500   // in ms
//
#define SCALE_OFFSET            128.0	// for internal battery scaling
#define MINPERCENT_REF          0.26    // should be >25%
#define MAXPERCENT_REF          0.74    // should be <75%
#define MINREFV        			(MINPERCENT_REF*2.0*VOLTAGEREF) // this is the minimum ref voltage allowed
#define MAXREFV        			(MAXPERCENT_REF*2.0*VOLTAGEREF) // this is the maximum ref voltage allowed
//
#define HYST_SCALE				250.0						// number of steps in the hysteresis
#define HYST_FULLSCALE			0.25		    				// the maximum hyseteresis as a fraction... 
#define DEFAULT_HYSTERESIS		0.5*(HYST_SCALE*HYST_FULLSCALE) // the default is set at half of full scale...
//
#define MINOR_DELAY_MS			250
#define MAJOR_DELAY_MS			750
#define MAX_NUM_OUTPUTS         8
//
#define ANALOG_VAR				0				// variable type is analog
#define FREQUENCY_VAR 			1				// variable type is frequency/duty cycle
#define DEPENDENT_VAR           2
#define SILENT_VAR              3
//
#define MAX_DATALOG_SAMPLES 	32000	 // maximum number of samples to log
#define RESET_DELAY             15.0     // in seconds
#define AUTO_DELAY              10.0     // in seconds
//
#define EPSIZE              112   //  endpoint packet size in bytes (on 16 byte boundary)
#define USBTIMEOUT          1500  // in milliseconds (too low a value will fail, around 2sec is ok)
#define FLASHWR_DELAYMS     25    // delay as not to overwhelm the flash write server on the device 25ms is ok
//
#define OVER_HEAD           16    // Overhead in the datapacket header
#define DATA_SIZE           (EPSIZE-OVER_HEAD)
#define MAX_SYMBOLS         4000
#define STRINGPKSIZE        64  // must be a multiple of 64
#define MAX_STRING_SIZE     2048
#define MAXSTRINGSSIZE      2048
#define VAR_BATT			6
#define VAR_LDR				7
//
#define MAXPRIORITY         32767
#define NUM_STRINGS_PER_VAR 4
#define VALUE_INDEX	        0
#define DUTY_INDEX	        1
#define DELTA_INDEX	        2
#define DELTA_DT_INDEX	    3
#define NUM_VALUES	        4	// the total number
#define NUM_RAW 	        2
#define NUM_SCALING         2
#define NUM_VARS	        6
#define ANALOG_VARS         4
#define NUM_UPDATE_VARS     8
//
#define SIZEAUTO            0
#define SIZEINT             2
#define SIZEDOUBLE          4
#define SIZEBYTE            1
#define SIZECHARP           2
#define SIZEFARCHARP        3
#define SIZELONG            4
#define DOUBLE              float
#define INT                 short 
#define CHARP               short
#define FARCHARP            long
//
#define SRAW                1
#define SSCALING            2
#define SINTDEG             4
#define SDECP               8
#define SINTERNAL           16
#define SHYST               32
#define SPOLY               64
#define SSETTINGS           128
//
#define SNORMAL             0
//
#define VALUE_TAB           40
#define VALUE2_TAB          54
#define GI2_TAB             20
#define SYSTEM_TAB          88
#define COMMAND_TAB         57
#define FIRST_TAB           57
#define VAR_TAB		        57
#define SECOND_TAB          78
#define QUESTION_TAB        78
#define STRING_TAB          120
#define NAME_TRUNCATION     38
#define NAME_TRUNCATION_OUTPUTS   16
//
#define MAX_POLY_INDEXES    (NUM_VARS*NUM_RAW)+1
#define MAX_POLY	        51	// a 50 point polynomial coefficient memory (doubles) (the extra point is for the tail)
#define CAL_POINTS_PER_LINE 5   // this is the number of DOUBLES per line of the calibration File
#define CAL_HEADER_SIZE     3   // this is the minimum information on each line of the calibration file required for the line to be valid
#define CAL_DATA_SIZE       (CAL_POINTS_PER_LINE-CAL_HEADER_SIZE)
#define CAL_VARN_INDEX       0
#define CAL_INDEX_INDEX      1
#define CAL_IS_DEFAULT_INDEX 2
#define CAL_X_INDEX          3
#define CAL_Y_INDEX          4
//
#define MAXUFQ               8.0 // in Hz, this is the max settable variable update Frequency
#define MINUFQ               0.2 // in Hz, this is the min settable variable update Frequency
#define STRING_DELIMITER     ':'
//
#define READ_DIR	           0
#define WRITE_DIR	           1
//
#define MODE_NORMAL          0
#define MODE_AVG             1
// bit 0= 0 direct sampling 1=averaging acquisition
// bit 7, 6, 5, 4
// a 1 indicates value[x] is loggable 0 not loggable
// bits 3 indicates that acc is loggable
// bit 2  indicates the following:
// 0= don't log min max
// 1= log min and max on chosen variables
#define MODE_LOGMASK        0xF0
#define MODE_LOGACC         0x08
#define MODE_LOGMINMAX      0x04
//
#define VARIABLE_MODE	     0
#define SYSTEM_MODE	         1
#define NAME_INDEX           0
#define UNIT_INDEX           1
#define TOTAL_INDEX          2
//
#define MAGIC_VALUE						0x76		// should not be 0xFF or 0x00 but any other value is ok!
#define MAGIC_VALUE_ADR					0			// offset to EEPROM memory
#define START_PERSISTENT_ADR			1
#define NUM_PERSISTENT_SETTINGS			25
//
#define MINBRIGHTNESS_ADR				1			// offset to EEPROM memory
#define MAXBRIGHTNESS_ADR				2
#define SCROLLSPEED_ADR					3
#define DISPLAYOBJECT_ADR				4
#define DISPLAYMODE_ADR					5
#define TMR0CON_ADR						6
#define TMR0CONLOG_ADR					7
#define TMR0HPERIOD_ADR					8
#define ROUNDINGMODE_ADR				9
#define SYSTEMDECP_ADR					10
#define BATTSCALINGL_ADR				11
#define BATTMIN_ADR						12
#define BATTMAX_ADR						13
#define SYSTEMNAMEL_ADR					14
#define SYSTEMNAMEH_ADR					15
#define ZEROACC_ADR						16
#define OUTPUT1_ADR						17
#define OUTPUT2_ADR						18
#define CHECKPERIOD_ADR					19
#define BEEPPERIOD_ADR					20
#define MINORDELAY_ADR					21
#define MAJORDELAY_ADR					22
#define INVERTMASK_ADR                  23
#define BATTSLEEPMODE_ADR               24
#define BATTWAKEUPMODE_ADR              25
#define LIMITPERIOD_ADR                 26
#define DISPLAY_OBJS_ADR				27
//
#define POLY_TABLE_ADR					39
#define POLY_MEMORY_ADR					(POLY_TABLE_ADR+MAX_POLY_INDEXES)
//
#define OUTPUT1							0x02          // PORT E bit 1
#define OUTPUT2							0x04          // PORT E bit 2
//
#define NO_FORMAT  0         // for marking the end of the list
#define FORMAT_X2  1         // hexadecimal byte
#define FORMAT_X4  2         // hexadecimal word
#define FORMAT_D   3         // decimal number (integer)
#define FORMAT_F1  4         // floating point 1 decimal point
#define FORMAT_F3  5         // floating point 3 decimal points
#define FORMAT_S   6         // string
#define FORMAT_B   7	     // boolean 0=Disable 1=Enable
#define FORMAT_F2  8         // floating point 2 decimal points
#define FORMAT_F6  9	     // floating point 6 decimal points
//
#define NO_TYPE        	 0  // none
#define RD_TYPE			 1  // read only variable
#define WR_TYPE			 2  // read and write variable (write to EE)
#define SHOW_TYPE        4  // show variable
#define SET_TYPE		 8  // set type variable
#define COMPUTE_TYPE    16  // compute (for dependent variables)
#define SETTING_TYPE    32  // these are saved and restored from the settings file
#define UPDATE_TYPE     64  // update type 
#define END_TYPE		128 // to indicate the last record in the system vars array
//
#define NO  0
#define RO	(RD_TYPE)	                          // read only (do not show)
#define SO  (SHOW_TYPE)                           // show only type
#define CO  (COMPUTE_TYPE)                        // compute only
#define CS  (COMPUTE_TYPE | SHOW_TYPE)            // compute and show
#define RS	(RD_TYPE | SHOW_TYPE)	              // read only and show
#define RW	(RD_TYPE | WR_TYPE)		              // read and write
#define RWS (RD_TYPE | SHOW_TYPE | WR_TYPE)       // readwrite and show
#define CWS (COMPUTE_TYPE | WR_TYPE | SHOW_TYPE)  // compute write and show type
#define RUS (RD_TYPE | UPDATE_TYPE | SHOW_TYPE)
#define RWUS (RD_TYPE | UPDATE_TYPE | SHOW_TYPE | WR_TYPE)

#define ROF   (RO  | SETTING_TYPE) // read only (do not show)
#define SOF   (SO  | SETTING_TYPE) // show only type
#define COF   (CO  | SETTING_TYPE) // compute only
#define CSF   (CS  | SETTING_TYPE) // compute and show
#define RSF   (RS  | SETTING_TYPE) // read only and show
#define RWF	  (RW  | SETTING_TYPE) // read and write
#define RWSF  (RWS | SETTING_TYPE) // readwrite and show
#define CWSF  (CWS | SETTING_TYPE) // compute write and show type
#define RWUSF (RWUS | SETTING_TYPE)

#define MAX_NUM_DISPLAY_OBJECTS   64

typedef enum
{
			CAR_DISPLAY_RW_RAM	    =0xA0,
			CAR_DISPLAY_RW_ROM   	=0xA1,
			CAR_DISPLAY_RW_EE	    =0xA2,
            CAR_DISPLAY_SET_IMODE   =0xA3,
            CAR_DISPLAY_RESET       =0xA4,
			RESET                   =0xFF
} CMD;

typedef struct
{
                BYTE low;                   // Little-endian order
                BYTE high;
                BYTE upper;
                BYTE upperhigh;
} ADR;
        
typedef union _BOOT_DATA_PACKET
{
    BYTE _byte[EPSIZE];                     // For Byte Access
    struct
    {
        ADR  pAdrRam;
        ADR  pAdr;
        BYTE cmd;
        BYTE dir;
        BYTE varn;
        BYTE index;
        INT  len;
        INT  iarg;
        BYTE data[DATA_SIZE];
    };
} BOOT_DATA_PACKET;

typedef struct
{
    char name[MAX_STRING_SIZE];
    DWORD pAdr;
    BYTE  size;
    BYTE  noAutoSize;
} SYMBOL;

typedef struct
{
    SYMBOL symbol[MAX_SYMBOLS];
    // used to automatically get the sizes of all the variables!
    BYTE ramMap[DEVICE_TOTAL_RAM];
    INT mapTableSize;
    INT autSize;            // number of symbols with automatically computed address!
    INT autSizeTotalRam;    // total ram automatically sized (in bytes)
} MAPTABLE;

typedef struct
{
    DOUBLE x;
    DOUBLE y;
} VALUEPAIR;

typedef struct SYSTEMVAR
{
    INT  type;
    INT  priority;
    char name[MAX_STRING_SIZE];
    char title[MAX_STRING_SIZE];         // title of the quantity under review!
    char unit[MAX_STRING_SIZE];          // units
    INT  format;             // format to display value
    BYTE* ptr;
    INT   size;
    DOUBLE minValue;
    DOUBLE maxValue;
    DOUBLE *array;
    INT    nvalues;
    INT    eeAdr;
    DOUBLE (*showFunction)(SYSTEMVAR*, char*, int);
    DOUBLE (*function)(DOUBLE);
    DOUBLE (*inverseFunction)(DOUBLE);
    DOUBLE (*setFunction)(SYSTEMVAR*, DWORD* error);
    DOUBLE inputValue;
} SYSTEMVAR;

typedef struct MENU
{
   char question[MAX_STRING_SIZE];
   DOUBLE (*actionF)(int, int, int);        
} MENU;

typedef struct
{
DOUBLE value[NUM_VALUES];
DOUBLE raw[NUM_RAW];
DOUBLE scaling[NUM_SCALING];
DOUBLE acc;
DOUBLE max[NUM_VALUES];
DOUBLE min[NUM_VALUES];
BYTE decp[NUM_RAW];
BYTE interpolation[NUM_RAW];
BYTE type;				// type bits 1,0= ANALOG_VAR or FREQUENCY_VAR or DEPENDENT_VAR or SILENT_VAR
                        // type bits 5,4= index value of channel var (for dependent valueindex 0 only)
                        // type bits 7,6= index value of channel var (for dependent valueindex 1 only)
BYTE index;				// extra information for the variable
						// bit 7=delta/deltadt values apply to valueindex 0 or 1?
                        // bit 6=averaging enabled on delta/delta dt values?
                        // bits 5,4 = index value for accumulator
                        // bits 3,2,1,0= input channel (for ANALOG_VAR= 2 bits are significant)
                        //                             (for FREQUENCY_VAR = 1 bit is significant)
                        //                             (for DEPENDENT_VAR = 3 bits are significant)
CHARP name[NUM_STRINGS_PER_VAR];
LONG updateTime;	
LONG updatePeriod;
BYTE updated;		// bit 0 = 1 when the values have been digitized and variable updated bit 1=1 when the polynomial has been computed for the points!
BYTE invert;       //
BYTE mode;         
    // bit 0= 0 direct sampling 1=averaging acquisition
    // bit 7, 6, 5, 4
    // a 1 indicates value index is loggable 0 not loggable (there are four value indeces)
    // bit 3 indicates that acc is loggable or not
    // bit 2  indicates the following:
    // 0= don't log min max
    // 1= log min and max on chosen variables
BYTE hysteresis;   // for the output switching thresholds...
//
//
// the following are virtual on the firmware actual on the host PC program (ie locally emulated)
//
//
//
LONG oldupdateTime;
DOUBLE updateRealTime;
DOUBLE calibrationPoints[MAX_POLY+2][NUM_RAW][CAL_DATA_SIZE];
INT calibrationPointIsDefault[NUM_RAW];
INT numCalibrationPoints[NUM_RAW];
INT cmptotal;
INT displayed[NUM_VALUES];
INT displayedTotal;
INT relativeStringIndex[NUM_STRINGS_PER_VAR];
//INT loggable[NUM_VALUES];
//INT minmaxloggable[NUM_VALUES];
} VARIABLE;

typedef struct MAPPOINT
{
DOUBLE value[NUM_VALUES];
DOUBLE raw[NUM_RAW];
DOUBLE scaling[NUM_SCALING];
//BYTE channel;
//BYTE done;
} MAPPOINT;

BYTE systemDecp;
BYTE displayObj[MAX_NUM_DISPLAY_OBJECTS];
BYTE output[MAX_NUM_OUTPUTS];
BYTE porte;
BYTE settingsRAM[MAX_SETTINGS_RAM];
INT settingsSize;
INT systemName;
DOUBLE battVoltage;
BYTE battMin;
BYTE battMax;
DOUBLE battMaxVoltage;
DOUBLE battMinVoltage;
char printBuffer[MAX_STRING_SIZE*4], statBuffer[MAX_STRING_SIZE];
MAPPOINT freezePoints[MAX_POLY];
BYTE pushVariable;
//ofstream datalog;
//ifstream mapfile;
//ifstream isettingsFile;
//ofstream osettingsFile;
//fstream calibrationfile;
//ofstream outcalibrationfile;
BYTE minorDelay, majorDelay;
DOUBLE fosc4;
INT fosc4div1000;
DOUBLE fosc4MHz;
BYTE tmr0con, tmr0conlog, t0con;

BYTE pie1, pir1, ccp1con;

BYTE tmr0HPeriod;
DOUBLE tmr0Period;
INT ldrLevel, ldrPercent10, battLevel;
DOUBLE battRefCorrection, battRef;
DOUBLE ldrPercent;
BYTE scrollSpeed;
BYTE minBrightness, maxBrightness, screenOnPeriod;
BYTE roundingMode;
DOUBLE varUpdateFreq, logUpdateFreq;
BYTE displayObject;
BYTE displayMode;
//DOUBLE ibattScaling;
BYTE battScaling;
BYTE reqReset;
//
int polyUpdate=0;
int currentVariableNumber=0;
int currentIndexNumber=0;
int globalcontrolcode;
int finalSystemWrite;
//
DOUBLE ftemp;
char ctemp;
BYTE szVariable;
BYTE checkPeriod;
BYTE beepPeriod;
//
// Global Vars
//
DWORD autoSizeErrors;
DOUBLE timeElapsed, totalTimeElapsed, samplingFreq;
clock_t startt, endt, totalt;
BYTE LabelIndex[NUM_VALUES*2];
DWORD temp;
char vid_pid[]= "vid_04d8&pid_000c";    
char out_pipe[]= "\\MCHP_EP1";
char in_pipe[]= "\\MCHP_EP1";
HANDLE myOutPipe;
HANDLE myInPipe;
INT endIndex;
INT stringMemInUse;
tm theLocalTime;
tm myUSBTime;
tm myLastTime;
int open=0;
BYTE current_command;                   // default value...
BOOLEAN bQuit=false;
char selection;
BYTE zeroAcc;
BYTE battSleepMode;
DOUBLE battSleepDelay;
BYTE battLow;
BYTE battWakeUpMode;
BYTE limitPeriod;
BYTE limitCounter;
BYTE limitObj;
BYTE invertMask;
DWORD maxn;
DWORD res;
DWORD nb;
BOOT_DATA_PACKET datapacket;
BOOT_DATA_PACKET indatapacket;
VARIABLE variable[NUM_UPDATE_VARS];
//VARIABLE cmpvariable[NUM_VARS];
//int rawvaluescale=32767;
//DOUBLE decimalPointScale=1000.0;
//
VARIABLE DataLogger[NUM_UPDATE_VARS][MAX_DATALOG_SAMPLES];
MAPTABLE mapTable;
double matrix[MAX_POLY+2][MAX_POLY+2];
double result[MAX_POLY+2][MAX_POLY+2];
double original[MAX_POLY+2][MAX_POLY+2];
double inversematrix[MAX_POLY+2][MAX_POLY+2];
BYTE verhigh, verlow;
INT addressStringFlash, addressVariableFlash, maxStringSize;
INT stringsSize;
INT polyTable[MAX_POLY_INDEXES];
DOUBLE polyMemory[MAX_POLY+2];
INT polyMemoryUsed;
INT polyMemoryUsedPercent;
DOUBLE polyTemp[MAX_POLY+2];
BYTE StringsCmp[MAXSTRINGSSIZE];  // holds a replica for comparisons
BYTE Strings[MAXSTRINGSSIZE];     // this is the local copy  
// declarations
DOUBLE setUpBeep(int, int, int);
DOUBLE setUpRelay(int, int, int);
DOUBLE notImplemented(int, int, int);
DOUBLE disableAllOutputs(int, int, int);
DOUBLE exitSave(int, int, int);
DOUBLE idActionF(int, int, int);
DOUBLE changeNameAndUnit(int, int, int);
DOUBLE changeWelcomeString(int, int, int);
DOUBLE changeMinAndMax(int, int, int);
DOUBLE changeDisplayParametersVar(int, int, int);
DOUBLE changeAcquisitionParametersVar(int, int, int);
DOUBLE changeLoggingParameters(int, int, int);
DOUBLE calibrateSupplyRefAuto(int, int, int);
DOUBLE calibrateSupplyRefManual(int, int, int);
DOUBLE calibrateVariableMainMenu(int, int, int);
int getNameAndUnit(char*, char*, int, int, int);
DOUBLE computeDisplayed(DOUBLE);
int enterString(char*, char*, int, int, char*);
int updateTime(void);
void updatePolyMemory(DWORD*);
void updateVariable(int, DWORD*);
void showSystemVar(char*);
void doDots(char*);
void doDotsSys(char*, char);
void doDotsX(char*, int);
void doDotsQuestion(char*, int);
void doDotsVar(char *, char);
DWORD readRamVariable(char*, DWORD, int , DWORD*);
void getVarTypeString(char*, int);
void sprintFormat(char*,BYTE*,int,int);
void sprintFDecimal(char*,DOUBLE,int);
void getValueIndexString(char*, int, int);
void getOrderString(char*, int);
DOUBLE changeDisplaySettings(int, int, int);
int putInfo(SYSTEMVAR*, int, int, DWORD*);
DWORD addCalibrationPoint(int, int, MAPPOINT*, DWORD*, DWORD*);
DOUBLE renormalizeSensor(int,int,int);
DOUBLE renormalizeSensorInternal(int,int,int);
DWORD showPolyInfo();
DOUBLE computeBattMax(DOUBLE);
DOUBLE inverseBattMax(DOUBLE);
DOUBLE setBattMax(SYSTEMVAR*, DWORD*);
DOUBLE computeBattMin(DOUBLE);
DOUBLE inverseBattMin(DOUBLE);
DOUBLE setBattMin(SYSTEMVAR*, DWORD*);

char *valueStrings[]= 
{ "Value(0)", "Value(1)", "Value(2)", "Value(3)" };

char *rawStrings[]= 
{ "Raw(0)", "Raw(1)" };

char *scalingStrings[]=
{ "Scaling(0)", "Scaling(1)" };

char *interpolationStrings[]=
{ "Interpolation Degree(0)", "Interpolation Degree(1)" };

char *decimalPointStrings[]=
{ "Decimal Points(0)", "Decimal Points(1)" };

char *charPointerStrings[]=
{ "Char Pointer(0)", "Char Pointer(1)", "Char Pointer(2)", "Char Pointer(3)" };

char *polynomialStrings[]=
{ "Polynomial(0)", "Polynomial(1)" };

char *outputStrings[]=
{ "Output(0)", "Output(1)" };

int alignNumberBoundary(int N, int size)
{
    // returns the number of total bytes to write N bytes in blocks of min
    // size size bytes
    // eg for flash program writing
    //
    int i;
    //
    i=(N/size);
    if((N % size)!=0)i+=1;
    return i*size;
    // we assert here that the return value R=i*size has the property that
    // R >= N always
    // proof:
    //
    // if N is divisible by size then R=N since R=N/size*size=N
    // otherwise R> N 
}

int mygetch(int *controlcode)
{
    char c;
    c=_getch();
    if((c==0)||(c==-32)){ *controlcode=1; c=_getch(); }
    else
    { *controlcode=0; 
    }
    return (int)c;
}

void DelayMs(int milliseconds)
{
    clock_t tendt, tstartt;
    long diff;
     
    diff=0;   
    tstartt=clock();
    while(diff<=milliseconds)
    {
        tendt=clock();
        diff=(tendt-tstartt)*1000/CLOCKS_PER_SEC;
    }
}

int stringLength(char *ptr)
{
 int i;
    i=0;
    while((*ptr++)!='\0')i++;
    return i+1;      
}

char* stringLengthPtr(char *ptr)
{
    int i;
    i=0;
    while((*ptr++)!='\0')i++;
    ptr--;
    return ptr;      
}

void doDotsX(char *str, int tabwidth)
{
     int j;
     
     j=stringLength(str);
     printf("%s",str);
     while(j<tabwidth)
     {
         printf(".");
         j++;
     }
}

/*
void padString(char *outstr, char* instr, char padding, int maxchars)
{
    int i;
    char buffer[MAX_STRING_SIZE];
    char *instring;
    
    sprintf(buffer, "%s", instr);
    instring=(char*)&buffer[0];
    i=0;
    while((i<maxchars)&&((*instring)!=0))
    {
        *outstr=*instring;
        instring++;
        outstr++;
        i++;
    }
    while(i<maxchars)
    {
        *outstr=padding;
        outstr++;
        i++;
    }
}
*/

void doDotsQuestion(char *str, int tabwidth)
{
     int j;
     
     j=stringLength(str);
     printf("%s", str);
     while(j<tabwidth)
     {
         printf(".");
         j++;
     }
     printf(" ");
}

void doDotsSys(char *str, char* c)
{
     doDotsX(str, SYSTEM_TAB);
     printf("%s ", c);
}

void doDotsVar(char *str, char* c)
{
     doDotsX(str, VAR_TAB);
     printf("%s ", c);
}

void sdoDotsX(char* ostr, char *istr, int tabwidth)
{
     int j, k;
     char c;

     k=stringLength(istr);
     j=0;
     while(j<tabwidth)
     {
       if(j<k){ c=*istr; istr++; } else c='.';
       *ostr=c;
       ostr++;
       j++;
     }
}

void sdoDots(char *ostr, char* istr, int tabwidth, char c)
{
     int j;
     char ibuffer[MAX_STRING_SIZE];

     sprintf(ibuffer, "%s", istr);
     j=stringLength(ibuffer);
     sprintf(ostr, "%s",ibuffer);
     while(j<tabwidth)
     {
         sprintf(ostr, "%s%c", ostr, c);
         j++;
     }
}

void doDotsCommand(char *str, char* c)
{
     doDotsX(str, COMMAND_TAB);
     printf("%s ", c);
}

void doDots(char *str)
{
     doDotsX(str, VALUE_TAB);
}

void swapRows(int ra, int rb, int deg)
{
	// swaps the rows ra and rb
	int i;
	double x;
	if(ra!=rb)
	{
	for(i=0; i<(deg+1);i++)
	{
	x=matrix[ra][i];
	matrix[ra][i]=matrix[rb][i];
	matrix[rb][i]=x;
	x=inversematrix[ra][i];
	inversematrix[ra][i]=inversematrix[rb][i];
	inversematrix[rb][i]=x;
	}
	}
}

void scaleRow(int ra, double factor, int deg)
{
	// performs the row operation ra=ra * factor
	int i;
	for(i=0; i<(deg+1); i++)
	{
	matrix[ra][i]*=factor;
	inversematrix[ra][i]*=factor;
	}
}

void minusScaledRow(int ra, int rb, double factor, int deg)
{
	// performs the row operation ra=ra- factor*rb
	int i;
	if(ra!=rb)
	{
		for(i=0; i<(deg+1);i++)
		{
		matrix[ra][i]-=factor*matrix[rb][i];
		inversematrix[ra][i]-=factor*inversematrix[rb][i];
		}
	}
}

int findNonZeroEntry(int col, int deg)
{
	// returns the row number of first non zero entry in column col from row col to bottom
	// returns -1 if none
	int i, j;
	j=-1;
	for(i=col; i<(deg+1);i++)
	{
	if(matrix[i][col]!=0.0){ j=i; break; }
	}
	return j;
}

int findInverse(int deg)
{
	// finds the inverse matrix for the matrix matrix[][]
	// returns 0 if success or -1 otherwise (if the matrix is not invertible)

	int i, j, k;
	double f;
 	int good;
    double error;
    
    for(i=0; i<(deg+1); i++)
    {
             for(j=0; j<(deg+1); j++)
             {
                      original[i][j]=matrix[i][j];
             }
    }
    
    // initialise the inversematrix to the identity matrix
	for(i=0; i<(deg+1);i++)
	{
		for(j=0;j<(deg+1);j++)
		{
		if(i==j)inversematrix[i][j]=1.0; else	inversematrix[i][j]=0.0;
		}
	}
	// start
	for(i=0; i<(deg+1);i++)
	{
		// i tracks the column
		j=findNonZeroEntry(i, deg);
		if(j<0)return -1;
		swapRows(j, i, deg); 						// swap the rows
		scaleRow(i, 1.0/(matrix[i][i]),deg);		// normalize	
		j++;
		while(j<(deg+1))
		{
		minusScaledRow(j,i,matrix[j][i],deg);		// minus the row to make it a zero...
		j++;
		}
	}
	// now we have an upper triangular matrix?
	for(i=1; i<(deg+1);i++)
	{
		// i tracks the columns
		for(j=0; j<i;j++)
		{
			// j tracks the rows				
			minusScaledRow(j, i, matrix[j][i],deg);	// make zero
		}
	}
	//
    // done!
	// now we check whether the inverse was found, ie. whether
	// the original matrix was indeed invertible (determinant non zero)
	//
	// if not, then we return 1 else return 0
	//
	for(i=0; i<(deg+1);i++)
	{
             // i tracks the row
             
             for(j=0; j<(deg+1); j++)
             {
                   // j tracks the column
                   f=0.0;
                   for(k=0; k<(deg+1); k++)
                   {
                     f+=(original[i][k]*inversematrix[k][j]);
                   }
                   result[i][j]=f;
                   //printf("%6.6f ", result[i][j]);
             }
            //printf("\nOne\n");
    }
    good=0;
    /*
    for(i=0; i<(deg+1); i++)
    {
             for(j=0; j<(deg+1); j++)
             {
               if(i==j)result[i][j]=result[i][j]-1.0;
               if(result[i][j]<0)result[i][j]=-result[i][j];
             }
    }
    
    error=0.1;
    for(i=0; i<(deg+1); i++)
    {
             for(j=0; j<(deg+1); j++)
             {
             printf("%6.6f ", result[i][j]);
             if(result[i][j]>=error)good=1;                 // error is the threshold error
             }
             error*=error;
             printf("\n");
    }
    */

    for(i=0; i<(deg+1); i++)
    {
             for(j=0; j<(deg+1); j++)
             {
             if(i==j)error=1.0; else error=0.0;
             if((matrix[i][j]-error)>0.0001)good=1;    
             }
             //printf("\n");
    }
    return good;
}

INT getPolyTableAddress(int varn, int index)
{
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_RAW)index=NUM_RAW-1;
	return NUM_RAW*varn+index;
}

INT getInterpolationDegree(int varn, int index)
{
	int a;
    a=getPolyTableAddress(varn, index);
    return (polyTable[a+1]-polyTable[a]-1);
}

DOUBLE getCoefficient(int varn, int index, int degree)
{
	int a;
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_RAW)index=NUM_RAW-1;
    a=polyTable[getPolyTableAddress(varn, index)];
	return polyMemory[a+degree];
}

int copyVarPolynomial(DOUBLE* outpoly, int varn, int index)
{
    // copy the variable polynomial to polynomial pointer at outpoly
    // return the degree of the copied poly
    int i, deg;
    DOUBLE f;
    //
    deg=variable[varn].interpolation[index];
    //printf("CopyVar Poly, deg: %d.\n", deg);
    for(i=0; i<(deg+1); i++)
    {
    f=getCoefficient(varn, index, i);
    *outpoly=f;
    outpoly++;
    }
    return deg;
}

void clearPolyMemory(void)
{
	int i;
	for(i=0; i<MAX_POLY; i++)
	{
	if(i<(MAX_POLY_INDEXES))
	{ 
	polyTable[i]=i; 
	polyMemory[i]=1.0;
	}
    else polyMemory[i]=0.0;
    }	
}

void handleInsertPolynomialError(DWORD error)
{
    if(error==0)
    printf("Ok.\n");
    else
    if(error==1)
    printf("Poly Table Integrity Error.\n");
    else
    if(error==2)
    printf("Out of Poly Memory Error.\n");
    else
    printf("Error.\n");
}

DWORD insertPolynomial(INT varn, INT index, INT length, DOUBLE* ptr, DWORD* error)
{
    // inserts the polynomial of length "length" (doubles) beginning at ptr into
    // the polynomial memory for variable varn and index returns 0 error if ok
    // otherwise non zero for error (for eg. if we have run out of poly memory)
    DOUBLE tempMemory[MAX_POLY];
    INT i, oldsize, diff;
    INT a, b, c, d;
    //
    c=getPolyTableAddress(varn, index);
    b=polyTable[c+1];
    a=polyTable[c];
    d=polyTable[MAX_POLY_INDEXES-1];    // the tail
    oldsize=1+getInterpolationDegree(varn, index); // this is the current size in doubles
    diff=length-oldsize;
    //
    //printf("Before Inserting Polynomial Diff: %d.\n", diff);
    //showPolyInfo();
    // diffsize>0 means we are expanding... <0 means we are contracting
    if((polyMemoryUsed+diff)>=(MAX_POLY))
    {
        // we don't have enough memory for this operation to complete...
        // so we abort and give an error...
        *error=2;               // out of memory error!
        return 0;
    } else
    {
        // we do have enough memory so we attempt the operation
        if(diff==0)
        {
            // same size just replace the coefficients (the polyTable remains the same)
            i=0;
            while(i<length)
            {
             polyMemory[a]=*ptr++;
             a++;
             i++;   
            }
            // done!
        } else
        if(diff<0)
        {
            // changing to smaller size
            // shift b down by -diff places
            while(b<=d)
            {
                polyMemory[b+diff]=polyMemory[b];
                b++;
            } // done shifting...
            i=0;
            while(i<length)
            {
                polyMemory[a]=*ptr++;
                a++;
                i++;
            } // copied and done!
            i=c+1;
            while(i<(MAX_POLY_INDEXES))
            {
                polyTable[i]+=diff;
                i++;
            }
            polyMemoryUsed+=diff;   // update free space
        } else
        if(diff>0)
        {
            // changing to bigger size
            while(d>=b)
            {
                polyMemory[d+diff]=polyMemory[d];
                d--;
            }   // done shifting!
            i=0;
            while(i<length)
            {
                polyMemory[a]=*ptr++;
                a++;
                i++;
            } // copied and done!
            i=c+1;
            while(i<(MAX_POLY_INDEXES))
            {
                polyTable[i]+=diff;
                i++;
            }
            polyMemoryUsed+=diff;
            // done!
        }
    }
    if(polyMemoryUsed!=polyTable[MAX_POLY_INDEXES-1])*error=1; else *error=0; // integrity error!
    //printf("After Inserting Polynomial Diff: %d.\n", diff);
    //showPolyInfo();
    return 0;
}

void showMatrix(int deg)
{
     int i, j;
     
     for(i=0; i<(deg+1); i++)
     {
              printf("[ \t");
      for(j=0; j<(deg+1); j++)
      {
        printf("%4.4g ",matrix[i][j]);
               
      }
      printf(" \t|\t ");
      for(j=0; j<(deg+1); j++)
      {
        printf("%4.4g ",inversematrix[i][j]);
      }
      printf(" \t]\n");
     }     
     printf("\n");
}

void showResult(int deg)
{
     int i,j;
     
     for(i=0; i<(deg+1); i++)
     {
      printf("[ \t");
      for(j=0; j<(deg+1); j++)
      {
      printf("%3.3g ",result[i][j]);
      }
      printf(" \t]\n");
     }     
     printf("\n");
}     

int getNumberOfCalibrationPoints(void)
{
    // returns the total number of calibration points loaded
    int v,i,n;
       
       n=0;
       for(v=0; v<NUM_VARS;v++)
       {
                for(i=0; i<NUM_RAW; i++)
                {
                         n+=variable[v].numCalibrationPoints[i];
                }
       }
       return n;
}

int computeAlphaPolynomial(DOUBLE* inpoly, int deg, double alpha)
{
    // adjusts the polynomial for the alpha value
    int i;
    double f;
    //
    f=1.0;
    for(i=0; i<(deg+1); i++)
    {
    (*inpoly)*=f;
    f*=alpha;
    inpoly++;
    }
    return 0;
}
             
double computePolynomialValue(DOUBLE* poly, int deg, DOUBLE x)
{
    double f,g, res;
    int j;

    res=1.0;
    if(deg==0)
    {
      res= (x*(*poly));
    } else
    if(deg>0)
    {
	 g=0.0;					// running total MAC
	 f=1.0;
	 for(j=deg; j>=0; j--)
	 {
	 g+=(f*(*poly));
     poly++;
	 f*=x;
	 }
     res=g;
    }
    return res;
}

double findRootPolynomial(DOUBLE* inpoly, int indeg, double min, double max, double epsilon, int* result)
{
    //
    // finds a root between min and max on the x axis (if there is one)
    // using the bisection method, epsilon is required accuracy...
    //
    // result=1 if a root found or 0 if none found
    double left, right, fleft, fmid, fright;
    double mid, error;
    
    *result=0;
    left=min;
    right=max;
    error=1.0+2*epsilon;
    fleft=computePolynomialValue(inpoly, indeg, left);
    fright=computePolynomialValue(inpoly, indeg, right);
    if((fright*fleft)>0.0)
    {

   
    }
    else
    {
    while(error > (2.0*epsilon))
    {
    mid = (right + left) / 2.0;
    fleft=computePolynomialValue(inpoly, indeg, left);
    fmid=computePolynomialValue(inpoly, indeg, mid);
    if((fleft * fmid) > 0.0)left=mid;
    else right=mid;
    error=right-left;
    if(error<0.0)error=-error;
    }
    *result=1;
    }
    return (right + left) / 2.0;
}


double findAlpha(DOUBLE* inpoly, int indeg, double x0, double q0, double epsilon, double range, int* resulting)
{
    // using the x range from 0 to range (only in the positive half line)
    // find the alpha value to correct the horizontal scale
    // for polynomial at inpoly of degree indeg
    // where we know that the correct poly should go through x0, q0
    // and with accuracy epsilon 
    // result =0 no alpha found result=1 alpha value found
    long tries;
    double root, x, dx;
    double ftemp, alpha;
    long i;
    int result;

    ftemp=(double)(*inpoly);
    (*inpoly)-=q0;
    x=0.0;
    tries=(long)(2.0/epsilon);
    dx=range/(double)tries;
    result=0;
    alpha=1.0;  // default
    i=0;
    while((i<tries)&&(result==0))
    {
    root=findRootPolynomial(inpoly, indeg, x, x+dx, epsilon, &result);
    if(result==1)
        {
        alpha=root/x0;
        } 
    x+=dx;
    i++;
    }
    *resulting=result;    
    (*inpoly)=(DOUBLE)ftemp;
    return alpha;
}

int findInversePolynomial(DOUBLE* inpoly, int indeg, DOUBLE* outpoly, int* outdeg)
{
    //
    // puts in outpoly the inverse polynomial to inpoly of degree indeg
    //
    //
    // the way we do this is by swapping the x and y coordinates of the
    // polynomial and then fitting another polynomial to it.
    //
    // The function may not be able to find the inverse function.
    //
    // indeg=0 means a scaling transformation
    //
    // return 0 if ok or non-zero if error
    int res, i, j;
    int matdeg;
    double x, y, f;

    *outdeg=indeg;
    res=0;
    if(indeg==0)
    {
      if((*inpoly)!=0.0){ *outpoly=1.0/(*inpoly); } else { *outpoly=1.0; res=1; }
    } else
    if(indeg>0)
    {
            //
            // now compute the polynomial going through the points generated
            // by swapping the x and y values...
            //
            // so we populate the matrix to invert
            *outdeg=10;
            matdeg=(*outdeg)+1;
            x=0.1;
    	    for(i=0; i<matdeg; i++)
	        {
                 // i tracks the row
                 y=(double)computePolynomialValue(inpoly, indeg, x);
                 f=1.0;
                 for(j=(matdeg-1); j>=0; j--)
                 {
                                      // j tracks the column
                 matrix[i][j]=f;      // put the entry
                 f*=y;
     
                 }
                 x+=0.1;
            }
            // the matrix is now populated so find the inverse!

        //showMatrix(matdeg-1);
        i=findInverse(matdeg-1);
        //printf("FindPolyInverse Good: %d\n",i);
        //showResult(matdeg-1);
        //showMatrix(matdeg-1);
        // multiply the inverse by the column n+1 x 1 matrix consisting of y values
        //
        if(i==0)
        {
        for(i=0; i<matdeg; i++)
        {
          f=0.0;           
          y=0.1;                                        // running total
          for(j=0; j<matdeg; j++)
           {
           f+=inversematrix[i][j]*y;
           y+=0.1;
           }
          *(outpoly+matdeg-1-i)=f;          // put the result
          }
        } 
        else
        { 
          res=3; 
        }
    } else res=2;       // negative degree so do nothing!
    return res;
}

int reducePolynomial(DOUBLE* inpoly, int indeg)
{
    // this is a recursive function!
    DOUBLE* ptr;
    DOUBLE error;

    //printf("@Reducing the POlynomial @%d!!\n", indeg);
    error=0.000001;         // error threshold
    if(indeg>1)
    {
        // attempt to reduce the polynomial...
        // look at the leading term (coefficient)
        // if it is 0 then reduce that polynomial...
        ptr=(inpoly+indeg);
        if(((*ptr)<=error)&&(((*ptr)>=(-error))))return reducePolynomial(inpoly, indeg-1);
        else
        return indeg;
    } else
    if(indeg==1)
    {
            // if degree 1 then look to see if it can be reduced to a scaling transformation.
            // ie if the constant term is zero?
            ptr=(inpoly+indeg);
            if(((*ptr)<=error)&&((*ptr)>=(-error)))
            {
                (*inpoly)=(*(inpoly+1));
                return 0;
            }    
            else
            return indeg;
    } else
    {
        return 0;
    }
    return indeg;
}

void showCalibrationPointsLoaded(int varn, int index)
{
    int i, j;
    DOUBLE x,y;
    char typestring[MAX_STRING_SIZE];
    //
    printf("\nThe Following Calibration Points Are Currently Loaded:\n");
    i=0;
    while(i<variable[varn].numCalibrationPoints[index])
    {
    x=variable[varn].calibrationPoints[i][index][0];
    y=variable[varn].calibrationPoints[i][index][1];
    printf("Point #%-3.0d: (%+10.5f,%+-10.5f)\n", i+1, x, y);
    i++;
    }
    if(variable[varn].calibrationPointIsDefault[index]==0)
    {
    sprintf(typestring, "All Are Data Points");
    } 
    else
    {
    sprintf(typestring, "Some Data Points were Internally Generated");
    }
    printf("Done: %s.\n", typestring);
}

int computePolynomial(int varn, int index, int deg)
{
    //
    // deg=0 means a scaling tranformation (1 point required)
    // deg=1 means a linear transformation (2 points required)
    // deg=2 means a quadratic transformation (3 points required)
    // etc...
    // once the calibration points have been loaded, we use this
    // function to compute the polynomial corresponding to those
    // points. varn= variable number index= index, deg= required degree
    // note that if there are not enough points for the required degree
    // this function will return only a smaller degree polynomial (biggest
    // we can get out of the calibration data.
    // the returned value is the degree of the polynomial.
    // remember here that degree=0 means a scaling factor (not a constant poly)
    //
    // Behaviour in the three cases:
    //
    // deg+1 > #points  (return a polynomial of deg #points instead)
    // deg+1 < #points  (return a polynomial based on the first points available only, ie
    //                  (some points will be ignored then!)
    // deg+1 = #points
    //
    // the polynomial is returned in the temporary coefficient buffer polyTemp[]
    //
    //
    int i, j;
    int reqpoints;
    int npoints;
    int actualdeg;
    double f, x, y;
    
    if(deg<0)deg=0;
    // first initialize default
    actualdeg=0;
    polyTemp[0]=1.0;
    i=1;
    while(i<MAX_POLY)
    {
       polyTemp[i]=0.0;
       i++;
    }    
    // done!
    
    reqpoints=deg+1;                                      // the number of required points
    npoints=variable[varn].numCalibrationPoints[index];   // the number of calibration points available
    showCalibrationPointsLoaded(varn, index);
    if(reqpoints>npoints)
    {
            reqpoints=npoints;                     // truncated!
    }
    // so now we are sure that reqpoints<=npoints!
    actualdeg=reqpoints-1;      // this is the actual degree of the poly produced
    // now populate the matrix
    if(actualdeg==0)
	{
		//
        // special scaling case (implied origin and linear)
		// a scalar transformation only
		// in this case we compute the polyTemp[0] value as the ratio of the
		// y value (rise) over the x value (run)
		//
		if((variable[varn].calibrationPoints[0][index][0])!=0.0)
		{
		polyTemp[0]=(double)((double)variable[varn].calibrationPoints[0][index][1]/(double)variable[varn].calibrationPoints[0][index][0]);
        } else polyTemp[0]=0.0; // if divide by 0 error!                    
	}
	else
	{
	    // now we populate the matrix to invert as follows
	    //
	    // [ x0^n x0^(n-1) .... x0 1 ]
	    // [ x1^n x1^(n-1) .... x1 1 ] etc... is an n+1 x n+1 matrix
	    // [         ..........      ]
	    // [ xn^n xn^(n-1) .... xn 1 ] where n=actualdeg and x0, x1, etc xn are the n+1 X-points
	    //
	    for(i=0; i<reqpoints; i++)
	    {
                 // i tracks the row
                 x=(double)variable[varn].calibrationPoints[i][index][0]; // 0 selects the X value
                 // printf("x=%6.6f\n",x);
                 f=1.0;
                 for(j=(reqpoints-1); j>=0; j--)
                 {
                          // j tracks the column
                 matrix[i][j]=f;      // put the entry
                 f*=x;   
                 }      
        }
        // done!
        // now find the inverse
        //showMatrix(actualdeg);
        i=findInverse(actualdeg);
        //printf("Good: %d\n",i);
        //showResult(actualdeg);
        //showMatrix(actualdeg);
        // multiply the inverse by the column n+1 x 1 matrix consisting of y values
        //
        //printf("Good: %d\n",i);
        
        if(i==0)
        {
          //printf("Actual Deg: %d\n", actualdeg);
          for(i=0; i<reqpoints; i++)
         {
          f=0.0;                                                   // running total
          for(j=0; j<reqpoints; j++)
           {
                   y=(double)variable[varn].calibrationPoints[j][index][1]; // 1 selects the y value
                   f+=inversematrix[i][j]*y;
           }
          polyTemp[actualdeg-i]=f;          // put the result
          }
        }
        else
        {
        // if the inverse not found correctly, force unity scaling 
          //printf("Here Instead\n");
          polyTemp[0]=1.0;
          actualdeg=0;
        }
        // done!
    }
    // reduce the polynomial...
    actualdeg=reducePolynomial((DOUBLE*)&polyTemp[0], actualdeg);
    return actualdeg;   // return the actual degree of the polynomial computed.
}

double computeValue(int var_num, int index, double rw)
{
	double f, g;
	int j;
	int dg;
	int a;

	a=polyTable[NUM_RAW*var_num+index];
	dg=variable[var_num].interpolation[index];
	if(dg==0)
	{
		// special scaling case (implied origin and linear)
		// a scalar transformation only
		g=rw*polyMemory[a];
	}
	else
	{
		g=0.0;					// running total
		f=1.0;
		for(j=dg; j>=0; j--)
		{
		g+=(f*polyMemory[a]);
		a++;
		f*=rw;
		}
	}
	return g;
}

DWORD computeInsertAllPolynomials(void)
{
      int v, i, deg;
      DWORD locerr, runningerr;
      //
      // computes and Inserts all polynomials given the loaded
      // calibration data in the variables
      //
      runningerr=0;
      for(v=0; v<NUM_VARS; v++)
      {
               for(i=0; i<NUM_RAW; i++)
               {
                        deg=computePolynomial(v,i,(variable[v].interpolation[i]));
                        insertPolynomial(v, i, deg+1, (DOUBLE*)&polyTemp[0], &locerr);
                        runningerr|=locerr;
                        if(runningerr==0)
                        {
                          variable[v].interpolation[i]=deg;
                        }   
/*
  printf("Inserting @ (%d, %d) Polynomial of degree: %d...", v,i,deg);
                        if(locerr!=0)
                        {
                                     // there was an error
                                     printf("Error.\n");
                        } else
                        {
                                     // all Ok
                                     printf("Ok.\n");
                        }
*/
               }
      }
      return runningerr;
}

//************************************************************************************

void GetSummary(void)
{
    HANDLE tempPipe = INVALID_HANDLE_VALUE;
    DWORD count = 0;
    DWORD max_count;

    max_count = MPUSBGetDeviceCount(vid_pid);

    printf("\r\n%d device(s) with %s currently attached\r\n",max_count,vid_pid);

    // Note:
    // The total number of devices using the generic driver could be
    // bigger than max_count. They could have different vid & pid numbers.
    // This means if max_count is 2, the valid instance index do not
    // necessary have to be '0' and '1'.
    //
    // Below is a sample code for searching for all valid instance indexes.
    // MAX_NUM_MPUSB_DEV is defined in _mpusbapi.h
    
    count = 0;
    for(int i = 0; i < MAX_NUM_MPUSB_DEV; i++)
    {
        tempPipe = MPUSBOpen(i,vid_pid,NULL,MP_READ,0);
        if(tempPipe != INVALID_HANDLE_VALUE)
        {
            printf("Instance Index # %d\r\n",i);
            MPUSBClose(tempPipe);
            count++;
        }
        if(count == max_count) break;
    }//end for
    printf("\r\n");
}//end GetSummary

int copyPtr(BYTE* source, BYTE* dest, int len, int dir)
{
        int i;
        i=0;
        while(i<len)
            {
            if(dir==READ_DIR)*dest=*source; else *source=*dest;
            dest++;
            source++;
            i++;
            }
     return i;
}

int copyCmpPtr(BYTE* source, BYTE* dest, int len, int dir, int *cmptotal)
{
        // copy and compare , cmptotal= number of bytes copied which are different!
        int i;
        i=0;
        *cmptotal=0;
        while(i<len)
            {
            if((*dest)!=(*source))(*cmptotal)=(*cmptotal)+1;
            if(dir==READ_DIR)
            {
                 *dest=*source; 
            } 
            else 
            {
                 *source=*dest;
            }
            dest++;
            source++;
            i++;
            }
     return i;
}

int cmpPtr(BYTE* source, BYTE* dest, int len)
{
     // compares the two buffers, byte by byte
     // returns the number of bytes that are different
     // return value of 0 means they are actually the same
     int i, result;

     result=0;
     i=0;
     while(i<len)
            {
            if(*dest!=*source)result++;
            dest++;
            source++;
            i++;
            }
     return result;
}

DOUBLE getDouble(BYTE* inptr, int size)
{
    DWORD pA;
    DOUBLE fx;
    
    if(size<SIZEDOUBLE)
    {
    pA=0;
    copyPtr(inptr, (BYTE*)&pA, size, READ_DIR);
    fx=(DOUBLE)pA;
    } else
    copyPtr(inptr, (BYTE*)&fx, SIZEDOUBLE, READ_DIR);
    return fx;
}

DOUBLE putDouble(BYTE* inptr, DOUBLE f, int size)
{
    DWORD pA;
    
    if(size<SIZEDOUBLE)
    {
    pA=(DWORD)f;
    copyPtr(inptr, (BYTE*)&pA, size, WRITE_DIR);
    } else
    copyPtr(inptr, (BYTE*)&f, SIZEDOUBLE, WRITE_DIR);
    return f;    
}


char* getStringSubIndexGeneral(char* ptr, int subindex, char delimiter)
{
	int i;
	i=0;
	while(i<subindex)
	{
		while(((*ptr)!='\0')&&((*ptr)!=delimiter))ptr++;
		if((*ptr)!='\0')ptr++; else break;
		i++;
	}
	return ptr;
}

void copyStringSubIndexGeneral(char* tostr, char* ptr, int subindex, char delimiter)
{
	int i;
	i=0;
    char* inptr;

    // get start pointer!
    inptr=getStringSubIndexGeneral(ptr, subindex, delimiter);
    // copy!
	while(((*inptr)!='\0')&&((*inptr)!=delimiter))
    {
    *tostr=*inptr;
    inptr++;
    tostr++;
    }
	*tostr='\0';
}

int getStringsSubIndex(int addr, int subindex, char delimiter)
{
	int i;
	i=0;
	while(i<subindex)
	{
		while((addr<stringsSize)&&((Strings[addr])!=delimiter))addr++;
		if(addr<stringsSize)addr++; else break;
		i++;
	}
	return addr;
}

int getStringsPointer(CHARP addr, char delimiter)
{
       int end;
       end=getStringsSubIndex(0, endIndex, delimiter);    // go to the end...
       if((addr>=addressStringFlash)&&(addr<(addressStringFlash+end)))
       {
       addr-=addressStringFlash;
       return (int)addr;
       } else return -1;
}

void sprintString(char* tostr, CHARP addr, int subindex, char delimiter, int maximumchars)
{
    int ptr;
    int i;
    
    i=0;
    if(maximumchars<=0)maximumchars=MAX_STRING_SIZE;
    if(maximumchars>MAX_STRING_SIZE)maximumchars=MAX_STRING_SIZE;
    *tostr='\0';
    // check if within range!
    addr=getStringsPointer(addr, delimiter);
    if(addr>=0)
    {
    addr=getStringsSubIndex(addr, subindex, delimiter);
    i=0;
    while((i<maximumchars)&&((Strings[addr])!='\0')&&((Strings[addr])!=delimiter)){ i++; sprintf(tostr, "%s%c", tostr, Strings[addr++]); }
    if(i>=maximumchars)sprintf(tostr, "%s~", tostr);
    }
}

int copyString(char *ptrd, char *ptrs, char delimiter, int maxsize)
{
    int i;
    i=0;
    while((i<(maxsize))&&((*ptrs)!=delimiter)&&((*ptrs)!='\0'))
        {
           *ptrd++=*ptrs++;
           i++;
        }
    *ptrd++='\0';        
    return i;
}

char systemString[]="Battery:V:Ambient Light:%:Car Scrolling Display::";
	
void sprintStringVar(char* tostr, VARIABLE* v, int varn, int index, int subindex, char delimiter, int maximumchars)
{
    char *ptr;
    int addr;
    int i;
        
    if(maximumchars<=0)maximumchars=MAX_STRING_SIZE;
    if(maximumchars>MAX_STRING_SIZE)maximumchars=MAX_STRING_SIZE;
    if(varn>=NUM_VARS)
	{
	varn-=NUM_VARS;
    if((systemName>=0)&&(systemName<stringsSize))
                                                {
                                                sprintString(tostr, systemName+addressStringFlash, subindex+(varn<<1), delimiter, maximumchars);
                                                } else
                                                {
                                                ptr=getStringSubIndexGeneral(&systemString[0], subindex+(varn<<1), delimiter);
                                                copyString(tostr, ptr, delimiter, maximumchars);
                                                }
	} else
	{
	sprintString(tostr, v->name[index], subindex, delimiter, maximumchars);
	if(*tostr=='\0')
    {
    if(subindex==0)sprintf(tostr, "Var%d(%d)", varn, index);     
    else
    sprintf(tostr,"Unit%d(%d)", varn, index);
    }
	}
}

void sprintStringWelcome(char *tostr, char delimiter, int maximumchars)
{
    char* ptr;
    // returns the system Welcome string!
    if((systemName>=0)&&(systemName<stringsSize))
                                                {
                                                sprintString(tostr, systemName+addressStringFlash, 4, delimiter, maximumchars);
                                                } else
                                                {
                                                ptr=getStringSubIndexGeneral(&systemString[0], 4, delimiter);
                                                copyString(tostr, ptr, delimiter, maximumchars);
                                                }
}

INT computeEndIndex(BYTE* inptr, int size, char delimiter)
{
    int i,j;
    
    j=0;
    i=0;
    while(j<size)
    {
    if((*inptr)==(BYTE)delimiter)i++;
    j++;
    inptr++;    
    }
    return i;
}

void deletesString(int addr, char delimiter, int number)
{
    // delete the string at addr, to the end of delimiter
    // from the string flash memory pointed to by ptr
    int end;
    int start;
    int i;
    
    end=getStringsSubIndex(addr, number, delimiter);  // go to the end of this string...
    start=addr;
    // now delete it!
    if(start>=end)
    {
    // empty anyway so do nothing.
     
    } else
    {
     // shift everything to the left from the end to the start
     i=end;
     while(i<stringsSize)
     {
     Strings[i-end+start]=Strings[i];     
     i++;                    
     }
     // done!     
     
     } 
     // recompute endindex value (not necessarily is it endindex--, what if the string deleted had a delimiter char?
     endIndex=computeEndIndex((BYTE*)Strings, stringsSize, STRING_DELIMITER);
}

INT insertsString(char *instr, int subindex, char delimiter, DWORD* error)
{
    //
    // insert the string at instr, at subindex 
    // returns non zero error if out of memory
    //
    int end;
    int start;
    int length;
    int i;
    
    *error=0;
    start=getStringsSubIndex(0, subindex, delimiter);  // go to the point at which to insert
    end=getStringsSubIndex(0, endIndex, delimiter);    // go to the end...
    length=stringLength(instr);       
/*
    printf("Length: %d\n", length);
    printf("end: %d\n", end);
    printf("start: %d\n", start);
*/
    if(end+length>=(stringsSize))
    {
    // out of memory error!
    
    *error=1;
    start=0;
    }
    else
    {                        
    // shift everything to the right from start for length
    i=end;
    while(i>=start)
    {
    Strings[i+length]=Strings[i];     
    i--;                    
    }
    // done shifting, now copy...
    i=0;
    while(i<(length-1))
       { 
       Strings[start+i]=(BYTE)*instr++; 
       i++; 
       }
       // now add the delimiter at the end!
       Strings[start+length-1]=':';
       // recompute endindex value (not necessarily is it endindex--, what if the string deleted had a delimiter char?
       endIndex=computeEndIndex((BYTE*)Strings, stringsSize, STRING_DELIMITER);
    } 
    return start;
}

INT forceStringDelimiter(char *instr, int delimiter, int number)
{
    // force the string at instr to have number number of delimiters delimiter
    int i;
    int j, k;
    char *ostr;
    
    j=0;
    i=0;
    if(number<0)number=0;
    ostr=instr;
    k=stringLength(instr)-1;
    number++;
    while((j<k)&&(i!=number))
    {
    if((*ostr)==(BYTE)delimiter)i++;
    j++;
    ostr++;    
    }
    // i is now the number we have
    if(i==number)
    {
                
    }
    else
    if(i<number){
        while(i<number)
        {
            *ostr=(char)delimiter;
            ostr++;
            i++;
        }
        
    }
    ostr--;
    *ostr=0;
    //printf("Forced to %d: %s. i is: %d\n", number-1, instr, i);
    return (number-i);
}

void computeRelativeStringAddresses(int direction)
{
    // computes the string index from the charp name
    int i, j, k, addr;
    
    if(direction==READ_DIR)
    {
    for(i=0; i<NUM_VARS; i++)
    {
        for(j=0; j<NUM_STRINGS_PER_VAR; j++)
        {
            addr=getStringsPointer(variable[i].name[j], STRING_DELIMITER);
            if(addr>=0)
            {
              k=computeEndIndex((BYTE*)Strings, addr, STRING_DELIMITER);
              variable[i].relativeStringIndex[j]=k;
            } else
            {
              variable[i].relativeStringIndex[j]=addr;   
            }
        }
    }
    } else
    {
    // opposite direction!
    for(i=0; i<NUM_VARS; i++)
    {
        for(j=0; j<NUM_STRINGS_PER_VAR; j++)
        {
            if(variable[i].relativeStringIndex[j]>=0)
            {
              k=getStringsSubIndex(0, variable[i].relativeStringIndex[j], STRING_DELIMITER);
              addr=k+addressStringFlash;
              if(variable[i].name[j]!=addr)
              {
                    variable[i].name[j]=addr;
                    variable[i].cmptotal++;
              }
              } else
              {
              //variable[i].name[j]=addr;   
              }
        }
    }
  }
}

void showRelativeStringAddresses(void)
{
    int i, j;
    for(i=0; i<NUM_VARS; i++)
    {
        for(j=0; j<NUM_STRINGS_PER_VAR; j++)
        {
        printf("Var(%d)(%d) Relative Address: 0x%4.4x Name: 0x%4.4x \n", i, j, variable[i].relativeStringIndex[j], variable[i].name[j]);
        }
    }
}

INT putVarString(char *instr, int varn, int index, char delimiter, DWORD* error)
{
   // puts the var string pointed to by instr for variable varn and value index  index
   // first check whether the string is loaded.
   int addr, res;
   DWORD localerror;
   
   *error=0;
   addr=getStringsPointer(variable[varn].name[index], delimiter);
   if(addr>=0)
   {
           // the string is in range, so first delete the old one and then reinsert the new one...
           computeRelativeStringAddresses(READ_DIR);
           //showRelativeStringAddresses();
           deletesString(addr, delimiter, (TOTAL_INDEX));
           res=forceStringDelimiter(instr, delimiter, (TOTAL_INDEX-1));
           res=insertsString(instr, addr, delimiter, &localerror);
           *error=localerror;
           if(localerror==0)
           {
                computeRelativeStringAddresses(WRITE_DIR);
                //printf("After\n");
                //showRelativeStringAddresses();
            }

   } else
   {
        // the string is out of range so insert it...
        res=forceStringDelimiter(instr, delimiter, (TOTAL_INDEX-1));
        res=insertsString(instr, (INT)computeEndIndex((BYTE*)Strings, stringsSize, delimiter), delimiter, &localerror);
        *error=localerror;
        variable[varn].name[index]=res+addressStringFlash;
        variable[varn].cmptotal++;
   }
   return 0;
}

INT putSystemString(char *instr, char delimiter, DWORD* error)
{
   // puts the var string pointed to by instr for variable varn and value index  index
   // first check whether the string is loaded.
   int addr, res;
   DWORD localerror;
   //
   //printf("Putting System String: %s\n", instr);
   *error=0;
   addr=getStringsPointer(systemName+addressStringFlash, delimiter);
   if(addr>=0)
   {
           // the string is in range, so first delete the old one and then reinsert the new one...
           computeRelativeStringAddresses(READ_DIR);
           //showRelativeStringAddresses();
           deletesString(addr, delimiter, (5));
           res=forceStringDelimiter(instr, delimiter, (4));
           //printf("@@@instr= %s\n", instr);
           res=insertsString(instr, addr, delimiter, &localerror);
           *error=localerror;
           if(localerror==0)
           {
                computeRelativeStringAddresses(WRITE_DIR);
            }
   } else
   {
        // the string is out of range so insert it...
        res=forceStringDelimiter(instr, delimiter, (4));
        //printf("instr= %s\n", instr);
        res=insertsString(instr, (INT)computeEndIndex((BYTE*)Strings, stringsSize, delimiter), delimiter, &localerror);
        *error=localerror;
        systemName=res;
   }
   return 0;
}

int loadMapTable(void)
{
    
    char linebuffer[MAX_STRING_SIZE];
    char filename[MAX_STRING_SIZE];
    char type[MAX_STRING_SIZE];
    char *p;
    DWORD dwadr;
    char c;
    int i;
    int j, k, l;
    ifstream mapfile;
    // initial defaults are size of byte
    for(i=0; i<MAX_SYMBOLS; i++)
    {
        mapTable.symbol[i].size=SIZEBYTE;       
        // default size of 1 (byte size) which is good for the access 
        // ram too (above 0x7FF on the PIC18F4550!)
        mapTable.symbol[i].noAutoSize=1;
    }
    // clear ram map
    for(i=0; i<DEVICE_TOTAL_RAM; i++)mapTable.ramMap[i]=0;
    mapTable.autSize=0;
    mapTable.autSizeTotalRam=0;
    //

    mapTable.mapTableSize=0;

    sprintf(filename, "cardisplay.map");
    mapfile.open(filename, ifstream::in);

    i=0;
    if(mapfile.good())
    {
    mapfile.seekg(0, ios::beg);
    p=NULL;
    i=0;
    while((!mapfile.eof())&&(p==NULL))
    {
    mapfile.getline(linebuffer, MAX_STRING_SIZE);
    p=strstr(&linebuffer[0],"Symbols - Sorted by Name"); 
    }
    if(mapfile.eof())
    {
        sprintf(statBuffer, "Parse Error.\n"); 
    }
    else 
    {
        sprintf(statBuffer, "Ok.\n");   
        mapfile.getline(linebuffer,MAX_STRING_SIZE);
        mapfile.getline(linebuffer,MAX_STRING_SIZE);
        // skip two lines and now start reading them!
        mapfile >> skipws;
        linebuffer[0]=0x1;
        while(linebuffer[0]!='\0')
        {
        mapfile >> linebuffer >> hex >> dwadr >> type;

        if(i<MAX_SYMBOLS)
        {
        strcpy(mapTable.symbol[i].name, linebuffer);
        mapTable.symbol[i].pAdr=dwadr;
        if((type[0]=='d')&&((dwadr>=DEVICE_LOW_RAM)&&(dwadr<=DEVICE_HIGH_RAM)))
            {
             // only auto size 'data' not 'program' etc
             //printf("Marking %s @ %4.4x\n", linebuffer, dwadr);
             mapTable.ramMap[dwadr]=1;          // mark
             mapTable.symbol[i].noAutoSize=0;
            }
        i++;
        } else
        {
            sprintf(statBuffer, "Max Symbol Memory Exceeded!\n");
        }       
        mapfile.getline(linebuffer, MAX_STRING_SIZE);
//        printf("linebuffer= %s \n", linebuffer);
        }        
    }
    } else sprintf(statBuffer, "Error.\n");
    
    if(i>0){ i-=1; mapTable.mapTableSize=i; } else mapTable.mapTableSize=0;
    mapfile.close();
    // now compute the sizes automatically...
    mapTable.autSize=0;
    j=0;
    while(j<mapTable.mapTableSize)
    {
        if(mapTable.symbol[j].noAutoSize==0)
        {
            // try to get the size
            k=mapTable.symbol[j].pAdr+1;
            if(k>=DEVICE_LOW_RAM)
            {
                l=1;
                while((k<=DEVICE_HIGH_RAM)&&(mapTable.ramMap[k]==0))
                {
                    l++;             
                    k++;
                }
                // l is now the automatically derived size of the symbol
                mapTable.autSize++;
                mapTable.symbol[j].size=l;
                mapTable.autSizeTotalRam+=l;
            }            
        }
        j++;
    }

    if(mapTable.mapTableSize>0)l=100*mapTable.autSize/mapTable.mapTableSize; else l=0;
    sprintf(printBuffer, "Loading Map File: %s. Symbols Loaded: %d Auto Sized: %d%c (Total: %0.2fkB)", filename, mapTable.mapTableSize, l, '%', mapTable.autSizeTotalRam/1000.0);
    doDotsSys(printBuffer, ":");
    printf("%s", statBuffer);
    mapfile.close();
    return i;
}

SYMBOL* lookUpSymbol(char *symname)
{
    int i, j;
  
//  printf("Searching for %s ", symname);
    if(mapTable.mapTableSize<1)mapTable.mapTableSize=1;
    i=-1;
    j=1;
    while((j!=0)&&(i<mapTable.mapTableSize))
    {
    i++;
    j=strcmp(mapTable.symbol[i].name, symname);
//  printf("%s cmp 4 \n", mapTable[i].name, symname);
    }
//  printf("Index Finished: %d, %s @ %4.4X \n",i, mapTable[i].name, mapTable[i].pAdr);
    if(i<mapTable.mapTableSize)return &mapTable.symbol[i];
    return 0;
}


int autoSize(SYSTEMVAR* inptr)
{
    SYMBOL* symp;

    if(inptr->size==SIZEAUTO)
    {
        symp=lookUpSymbol(inptr->name);
        if(symp!=0)
        {
        return symp->size;
        } else
        {
        printf("autoSize Error!\n");      
        autoSizeErrors++;
        return SIZEBYTE;  // the fall back default!       
        }
                              
    } else return inptr->size;
}

int autoSizeName(char* name)
{
    SYMBOL* symp;
    symp=lookUpSymbol(name);
    if(symp!=0)
    {
    return symp->size;
    } else
    {
    printf("autoSizeName Error!\n");      
    autoSizeErrors++;
    }
    return SIZEBYTE;  // the fall back default!       
}

DWORD lookUpSymbolAdr(char *symname)
{
    SYMBOL* ptr;
    ptr=lookUpSymbol(symname);
    if(ptr!=0)return ptr->pAdr; else return 0;
}

BYTE* updateVariableInfo(BYTE* ptr, int varn, int direction, int* cmptotal)
{
    int i, localcmptotal;
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;

    *cmptotal=0;
    localcmptotal=0;
    for(i=0; i<NUM_VALUES;i++)
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].value[i], SIZEDOUBLE, direction, &localcmptotal);
    }
    for(i=0; i<NUM_RAW; i++)
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].raw[i], SIZEDOUBLE, direction, &localcmptotal);
    }
    for(i=0; i<NUM_SCALING; i++)
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].scaling[i], SIZEDOUBLE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    }
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].acc, SIZEDOUBLE, direction, &localcmptotal);

    for(i=0; i<NUM_VALUES; i++)
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].max[i], SIZEDOUBLE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    }
 
    for(i=0; i<NUM_VALUES;i++)    
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].min[i], SIZEDOUBLE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    }
    for(i=0; i<NUM_RAW; i++)
    {
        ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].decp[i], SIZEBYTE, direction, &localcmptotal);
        (*cmptotal)=(*cmptotal)+localcmptotal;
    }
    for(i=0; i<NUM_RAW; i++)
    {
             ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].interpolation[i], SIZEBYTE, direction, &localcmptotal);
             (*cmptotal)=(*cmptotal)+localcmptotal;
    }
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].type, SIZEBYTE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].index, SIZEBYTE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    for(i=0; i<NUM_STRINGS_PER_VAR; i++)
    {
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].name[i], SIZECHARP, direction, &localcmptotal);   
    (*cmptotal)=(*cmptotal)+localcmptotal;
    }
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].updateTime, SIZELONG, direction, &localcmptotal);
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].updatePeriod, SIZELONG, direction, &localcmptotal);
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].updated, SIZEBYTE, direction, &localcmptotal);
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].invert, SIZEBYTE, direction, &localcmptotal);
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].mode, SIZEBYTE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    ptr+=copyCmpPtr(ptr, (BYTE*)&variable[varn].hysteresis, SIZEBYTE, direction, &localcmptotal);
    (*cmptotal)=(*cmptotal)+localcmptotal;
    return ptr;
}

void copyToDataLogger(int varn, long index)
{
    // copy the variable to the datalogger memory
    long i;

    for(i=0; i<NUM_VALUES;i++)
    {
        DataLogger[varn][index].value[i]=variable[varn].value[i];
        if(i<NUM_RAW)DataLogger[varn][index].raw[i]=variable[varn].raw[i];
        if(i<NUM_SCALING)DataLogger[varn][index].scaling[i]=variable[varn].scaling[i];
    }
    DataLogger[varn][index].acc=variable[varn].acc;
    for(i=0; i<NUM_VALUES;i++)
    {
    DataLogger[varn][index].max[i]=variable[varn].max[i];
    DataLogger[varn][index].min[i]=variable[varn].min[i];
    }
    for(i=0; i<NUM_RAW; i++)
    {
    DataLogger[varn][index].interpolation[i]=variable[varn].interpolation[i];
    DataLogger[varn][index].decp[i]=variable[varn].decp[i];
    }
    DataLogger[varn][index].type=variable[varn].type;
    DataLogger[varn][index].index=variable[varn].index;
    for(i=0; i<NUM_STRINGS_PER_VAR;i++)DataLogger[varn][index].name[i]=variable[varn].name[i];
    DataLogger[varn][index].mode=variable[varn].mode;
    DataLogger[varn][index].updateTime=variable[varn].updateTime;
    DataLogger[varn][index].updatePeriod=variable[varn].updatePeriod;
    DataLogger[varn][index].updateRealTime=totalTimeElapsed;
}

DWORD readString(int varn, int index)
{
    // reads the indexed string of variable varn into &indatapacket.data[0]
    int i;

//    datapacket.cmd=CAR_DISPLAY_READ_STRING;
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_STRINGS_PER_VAR)index=NUM_STRINGS_PER_VAR-1;
    datapacket.varn=varn;
    datapacket.index=index;
    res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
    if(res==MPUSB_SUCCESS)
    {
    for(i=0; i<maxStringSize;i++)indatapacket.data[i]='\0';
    res=MPUSBRead(myInPipe, &indatapacket, EPSIZE, &nb, 500);
    } 
    return res;
}

/*
void showPolyTemp(int deg)
{
     int i;
     DOUBLE f;
     
     if(deg<0)deg=0;
     if(deg==0)
     {
          f=polyTemp[0];
          if(f<0.0){ printf("-"); f=-f; } else printf("+");
          printf("%6.6f* (Scaling)",f);
     }
     else
     {
      for(i=0; i<(deg+1); i++)
      {         
      f=polyTemp[(deg-i)];
      if(f!=0.0)
      {
            if(f<0.0){ printf("-"); f=-f; } else printf("+");
            printf("%6.6f",f);
            if((deg-i)>1)printf("X^%d", deg-i); else if((deg-i)==1)printf("X");
      }
     }
    }
    return;
}
*/

void sprintPolynomialPtr(char* tostr, DOUBLE* inpoly, int deg)
{
    int terms,i;
    DOUBLE f;
    //
    sprintf(tostr, "");
    terms=0;
    if(deg>0)
    {
    for(i=0; i<(deg+1); i++)
	{
    f=*(inpoly+deg-i);
    if(f!=0.0)
    {
    if((deg-i)<=4)sprintf(tostr, "%s%+-4.4f",tostr, f); else sprintf(tostr, "%s%+-4.4g", tostr, f);
    terms++;
    if((deg-i)>1)sprintf(tostr, "%sX^%d ",tostr, deg-i); else if((deg-i)==1)sprintf(tostr, "%sX ", tostr);
    }
   	}
   	if(terms==0)sprintf(tostr, "%s0", tostr);
    } 
    else
    {
     f=*(inpoly);
     sprintf(tostr, "*%+-4.4f (Scaling)", f);
    }
}

void printPolynomialPtr(DOUBLE* inpoly, int deg)
{
   char buffer[MAX_STRING_SIZE];
   sprintPolynomialPtr((char*)&buffer[0], inpoly, deg);
   printf("%s", buffer);
}

int isNumericInternal(char c)
{
    if((c>='0')&&(c<='9'))return 1;
    else
    if(c=='.')return 1;
    return 0;
}

int isNumeric(char c)
{
    if((c>='0')&&(c<='9'))return 1;
    else
    if(c=='.')return 1;
    else
    if(c=='+')return 1;
    else
    if(c=='-')return 1;
    else
    return 0;
}

int isNumericOnly(char c)
{
    if((c>='0')&&(c<='9'))return 1;
    else
    return 0;
}

int isNumericHex(char c)
{
    if((c>='0')&&(c<='9'))return 1;
    else
    if((c>='A')&&(c<='F'))return 1;
    else
    if((c>='a')&&(c<='f'))return 1;
    else
    if(c=='x')return 1;
    else
    if(c=='X')return 1;
    else
    return 0;
}

void stripSpaces(char *optr, char *inptr)
{
    while((*inptr)!='\0')
    {
    if((*inptr)!=' ')*optr++=*inptr;
    inptr++;
    }
    *optr='\0';
}

char* getPolynomialToken(char *instring, DOUBLE* coefficient, int* degree, int *syntaxerror)
{
    // scan a token from instring 
    // a token is of the form
    // (floating point number).X^n
    // syntax error=0 is no error non zero : syntax error at index 
    int j;
    char *ptr;
    char buffer[MAX_STRING_SIZE];
    DOUBLE f;
    int anumber, asign;
    //
    *syntaxerror=0;   
    ptr=instring;
    // first skip white spaces
    //printf("Skip White");
    j=0;
    while((j<MAX_STRING_SIZE)&&((*ptr)!=0)&&((*ptr)==' '))
    {
        ptr++;
        j++;
        //printf("One J: %d\n", j);
    }
    j=0;
    while((j<MAX_STRING_SIZE)&&((*ptr)!=0)&&((isNumeric(*ptr))==0))
    {
        ptr++;
        j++;
        //printf("Two J: %d\n", j);
    }
    
    j=0;
    asign=0;
    while(((*ptr)!=0)&&(isNumeric(*ptr))&&(isNumericInternal(*ptr)==0))
    {
        //printf("Or: %c\n", *ptr);
        if(asign==0)buffer[0]=*ptr;
        else if((*ptr)=='-')buffer[0]='+'+'-'-buffer[0];
        asign=1;
        j=1;
        //printf("Here a sign!");
        ptr++;
    }
    anumber=0;
    while((j<MAX_STRING_SIZE)&&((*ptr)!=0)&&(isNumericInternal(*ptr)))
    {
        anumber++;
        buffer[j++]=*ptr;
        ptr++;
        //printf("Three J: %d\n", j);
    }
    buffer[j]=0;
    if(anumber>0)f=(DOUBLE)atof((char*)&buffer[0]); else f=1.0;
    *coefficient=f;
    if(((*ptr)==0)||(isNumeric(*ptr)))
    {
        // a degree zero polynomial
        *degree=0;
        *syntaxerror=0;
        return ptr;
    }
    else
    if(((*ptr)=='X')||((*ptr)=='x'))
    {
       // now we must have a ^ character
        ptr++;
        if((*ptr)=='^')
        {
            ptr++;
            j=0;
            while((j<MAX_STRING_SIZE)&&(isNumericOnly(*ptr)))
            {
                buffer[j]=*ptr;
                ptr++;
                j++;
            }
            buffer[j]=0;
            f=(DOUBLE)atof((char*)&buffer[0]);
            *degree=(int)f;
            *syntaxerror=0;
            return ptr;
        } else
        {
            // degree 1!
            *syntaxerror=0;
            *degree=1;
            return ptr;
        }
    }
    else
    {
        *syntaxerror=1;
        *degree=0;
        return ptr;
    }
    *syntaxerror=1;
    return ptr;
}

int getPolynomialPtr(char* instringarg, DOUBLE* outpoly, int maxoutdeg, int* outdeg, int *erroratindex)
{
    // maxoutdeg= max out poly degree!
    // attempts to parse the string in instring for a polynomial the
    // result is put in outpoly a polynomial of degree outdeg
    // allows the user to type in their own polynomials (arbitrary polynomials)
    // returns 0 if ok or non zero if syntax error! the index is then indicated by erroratindex
    int i;
    int syntaxerror;
    DOUBLE coefficient;
    int degree;
    int maxdegree;
    char* instring;
    char* endptr;
    //
    instring=instringarg;
    for(i=0; i<maxoutdeg; i++)
    {
     *(outpoly+i)=0.0;   
    }
    *outdeg=0;
    syntaxerror=0;
    maxdegree=-1;
    endptr=stringLengthPtr(instringarg);
    //printf("Endptr: %d Instring: %d\n", (int)endptr, (int)instring);
    
    while((syntaxerror==0)&&(((int)instring)<((int)endptr)))
    {
        //printf("Instring %d Enptr %d less %d Currently At ... \n", (int)instring, (int)endptr, (int)(((int)instring)<((int)endptr)));
        instring=getPolynomialToken(instring, &coefficient, &degree, &syntaxerror);  
        //printf("Next At %s... \n", instring);
        //printf("Extracted Coefficient: %6.6f, Degree: %d Syntaxerror: %d\n", coefficient, degree, syntaxerror);
        if((syntaxerror==0)&&(degree<maxoutdeg))
        {
            if(degree>maxdegree)maxdegree=degree;
            //printf("Here Maxdegree: %d \n", maxdegree);
            *(outpoly+degree)=coefficient;          // put the data;
        }
        
    }
    //printf("Out of the loop!\n");
    maxdegree=reducePolynomial(outpoly, maxdegree);
    *erroratindex=(int)(instring-instringarg);
    *outdeg=maxdegree;
    //printf("Out of here");
    return syntaxerror;
}

void sprintPolynomial(char* tostr, int varn, int index)
{
    int terms,i;
    int deg;
    DOUBLE f;
    
    sprintf(tostr, "");
    terms=0;
    deg=variable[varn].interpolation[index];
    if(deg>0)
    {
    for(i=0; i<(deg+1); i++)
	{
    f=getCoefficient(varn, index, deg-i);
    if(f!=0.0)
    {
    if((deg-i)<=4)sprintf(tostr, "%s%+-4.4f", tostr, f); else sprintf(tostr, "%s%+-4.4g",tostr, f); 
    terms++;
    if((deg-i)>1)sprintf(tostr, "%sX^%d ", tostr, deg-i); else if((deg-i)==1)sprintf(tostr, "%sX ", tostr);
    }
   	}
   	if(terms==0)sprintf(tostr, "%s0", tostr);
    } 
    else
    {
     f=getCoefficient(varn, index, 0);
     sprintf(tostr, "*%+-4.4f (Scaling)", f);
    }
}

void sprintPolynomialInternal(char* tostr, int varn, int index)
{
    int terms,i;
    int deg;
    DOUBLE f;
    // same as above but prints a true polynomial (when deg=0 it makes it a aX+0 poly)
    sprintf(tostr, "");
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_RAW)index=NUM_RAW-1;
    terms=0;
    deg=variable[varn].interpolation[index];
    if(deg>0)
    {
    for(i=0; i<(deg+1); i++)
	{
    f=getCoefficient(varn, index, deg-i);
//    f=((int)(f*decimalPointScale+0.5))/decimalPointScale;
    if(f!=0.0)
    {
    if((deg-i)<=4)sprintf(tostr, "%s%+-4.4f",tostr, f); else sprintf(tostr, "%s%+-4.4g", tostr, f);
    terms++; 
    if((deg-i)>1)sprintf(tostr, "%sX^%d ", tostr, deg-i); else if((deg-i)==1)sprintf(tostr, "%sX ", tostr);
    }
   	}
   	if(terms==0)sprintf(tostr, "%s0", tostr);
    } 
    else
    {
     f=getCoefficient(varn, index, 0);
     sprintf(tostr, "%s%+3.3gX ",tostr, f);
    }
}

void printPolynomial(int varn, int index)
{
    char buffer[MAX_STRING_SIZE];
    sprintPolynomial(buffer, varn, index);
    printf("%s", buffer);
}

DOUBLE getHysteresisPercent(DOUBLE inbytevalue)
{
    return 100.0*(DOUBLE)HYST_FULLSCALE*((DOUBLE)inbytevalue/(DOUBLE)HYST_SCALE);
}

DOUBLE inverseHysteresisPercent(DOUBLE inpercent)
{
    return ((inpercent*(DOUBLE)HYST_SCALE)/(100.0*((DOUBLE)HYST_FULLSCALE)));
}

void showVariableInfo(int varn, int valueshow, int displayTotal, int priority)
{
    int i, j;
    DWORD restemp;
    char ibuffer[NUM_VALUES][2][MAX_STRING_SIZE];
    char buffer[2][MAX_STRING_SIZE];
    double f;
    INT oS, noS;
    DWORD localerror;
    BYTE channel, vartype, avgmode, valueindex;
    BYTE deltachannel, deltaavg, accchannel;
    
    if(varn<NUM_UPDATE_VARS)
    {
    (void)getVarTypeString(buffer[0], varn);
    printf("\nCurrent Settings For: %s\n", buffer[0]);
    vartype=variable[varn].type & 3;
    avgmode=variable[varn].mode & 1;
    channel=variable[varn].index & 7;
    valueindex=(variable[varn].type>>4) & 0x0f;
    deltachannel=(variable[varn].index>>7 ) & 1;
    deltaavg=(variable[varn].index>> 6 ) & 1;
    accchannel=(variable[varn].index>>4) & 3;
    
    printf("\n");
    if(valueshow!=0)
    {
    j=1;
    for(i=0; i<NUM_VALUES;i++)
    {
    sprintStringVar(ibuffer[i][0], &variable[varn], varn, i, VALUE_INDEX, STRING_DELIMITER, VALUE_TAB );
    sprintStringVar(ibuffer[i][1], &variable[varn], varn, i, UNIT_INDEX, STRING_DELIMITER, VALUE_TAB);
    if((j & valueshow)!=0)
    {
    sdoDots(buffer[0], ibuffer[i][0], VALUE_TAB, '.');
    if((displayTotal & j)!=0)sprintf(printBuffer, "%s: %+6.3f", buffer[0], variable[varn].value[i]);
    else sprintf(printBuffer, "%s: N/A", buffer[0]);
    sprintf(printBuffer, "%s %s", printBuffer, ibuffer[i][1]);
    sdoDots(printBuffer, printBuffer, COMMAND_TAB, ' ');
    printf("%s (Min-Max: %8.3f - %-8.3f) \n", printBuffer, variable[varn].min[i], variable[varn].max[i]);   
    }
    j=j<<1;
    }
    } else 
    {
    // nothing!
    }

    if((priority & SRAW)!=0)
    {
     printf("\n");
     for(i=0; i<NUM_RAW;i++)
     {
     doDots(rawStrings[i]); printf(": %+6.3f\n", variable[varn].raw[i]);   
     }
    }

    if((priority & SSETTINGS)!=0)
    {
    printf("\n");
    sprintFormat(buffer[0], (BYTE*)&avgmode, FORMAT_B, SIZEBYTE);
    doDots("Acquisition Averaging Mode"); 
    printf(": %s\n", buffer[0]);
    sprintFormat(buffer[0], (BYTE*)&deltaavg, FORMAT_B, SIZEBYTE);
    doDots("Averaging Mode on Delta/Integral Values");
    printf(": %s\n", buffer[0]);
    doDots("Delta/Integral Values Apply To");
    printf(": %-32.32s\n", ibuffer[deltachannel][0]);
    }

    if((priority & SHYST)!=0)
    {
    printf("\n");
    doDots("Hysteresis For Limit Conditions"); printf(": %+-3.1f%c\n",  getHysteresisPercent(variable[varn].hysteresis), '%');
    }
        
    if((priority & SSCALING)!=0)
    {
     printf("\n");
     for(i=0; i<NUM_SCALING;i++)
     {
     doDots(scalingStrings[i]); printf(": %+6.3f\n", variable[varn].scaling[i]);   
     }
     doDots("Accumulator"); printf(": %+-6.3f\n", variable[varn].acc);
     doDots("Accumulator Applies To"); printf(": %-32.32s\n", ibuffer[valueindex][0]);
    }
    
    if((priority & SDECP)!=0)
    {
     printf("\n");
     for(i=0; i<NUM_RAW; i++)
     {
     doDots(decimalPointStrings[i]); printf(": %d\n", variable[varn].decp[i]);
     }
    }
      
    if((priority & SINTERNAL)!=0)
    {
    printf("\n");
    doDots("Update Time"); printf(": %d\n", variable[varn].updateTime);
    doDots("Update Period"); printf(": %d\n", variable[varn].updatePeriod);
    doDots("Invert"); printf(": 0x%2.2x\n", variable[varn].invert);
    doDots("Updated"); printf(": 0x%2.2x\n", variable[varn].updated);
    printf("\n");
    
    for(i=0;i<NUM_STRINGS_PER_VAR;i++)
    {
    doDots(charPointerStrings[i]); printf(": %d\n", (int)variable[varn].name[i]);
    }
    }
    
    if((priority & SINTDEG)!=0)
    {
    printf("\n");
    for(i=0; i<NUM_RAW; i++)
    {
    doDots(interpolationStrings[i]); printf(": %d\n", variable[varn].interpolation[i]);
    }
    }
    
    if((priority & SPOLY)!=0)
    {
    printf("\n");
    for(i=0; i<NUM_RAW; i++)
    {
    doDots(polynomialStrings[i]); printf(": ");
    printPolynomial(varn, i);
    printf("\n");
    }
    }
   }
}

void showVariableInfoNice(int varn)
{
    int i, j;
    DWORD restemp;
    char ibuffer[NUM_VALUES][2][MAX_STRING_SIZE];
    char buffer[4][MAX_STRING_SIZE];
    double f;
    INT oS, noS;
    DWORD localerror;
    BYTE channel, vartype, avgmode, valueindex;
    BYTE deltachannel, deltaavg, accchannel;
    int displayTotal;
    int decp;
    //
    if(varn<NUM_UPDATE_VARS)
    {
    (void)getVarTypeString(buffer[0], varn);
    printf("\nCurrent Settings For: %s\n", buffer[0]);
    vartype=variable[varn].type & 3;
    avgmode=variable[varn].mode & 1;
    channel=variable[varn].index & 7;
    valueindex=(variable[varn].type>>4) & 0x0F;
    deltachannel=(variable[varn].index>>7 ) & 1;
    deltaavg=(variable[varn].index>> 6 ) & 1;
    accchannel=(variable[varn].index>>4) & 3;
    //
    displayTotal=variable[varn].displayedTotal;
    j=1;
    for(i=0; i<NUM_VALUES;i++)
    {
    printf("\n");
    sprintStringVar(ibuffer[i][0], &variable[varn], varn, i, VALUE_INDEX, STRING_DELIMITER, VALUE_TAB );
    sprintStringVar(ibuffer[i][1], &variable[varn], varn, i, UNIT_INDEX, STRING_DELIMITER, VALUE_TAB);

    if((vartype==ANALOG_VAR)||(vartype==FREQUENCY_VAR))
    {
    sdoDots(buffer[0], ibuffer[i][0], VALUE_TAB, '.');
    if(i<NUM_RAW)decp=variable[varn].decp[i]; else decp=systemDecp;
    sprintFDecimal(buffer[1], variable[varn].value[i], decp);
    sprintf(printBuffer, "%s: %-10.10s", buffer[0], buffer[1]);
    sprintf(printBuffer, "%s %s", printBuffer, ibuffer[i][1]);
    sdoDots(printBuffer, printBuffer, COMMAND_TAB, ' ');
    printf("%s (Min-Max: %+8.3f - %+-8.3f) \n", printBuffer, variable[varn].min[i], variable[varn].max[i]);   
    doDots("Measures");
    getValueIndexString(printBuffer, varn, i);
    (void)getOrderString(buffer[1],variable[varn].displayed[i]);
    printf(": %-19.19s (Display Order: %-4.4s)\n", printBuffer, buffer[1]);
    // optional data for the value index
    } else
    if(vartype==SILENT_VAR)
    {
    // for a silent variable we show differently!
    getValueIndexString(buffer[0], varn, i);
    sdoDots(printBuffer, buffer[0], VALUE_TAB, '.');
    sprintf(printBuffer, "%s: %-40.40s", printBuffer, ibuffer[i][0]);
    printf("%s\n", printBuffer);
    //
    (void)getOrderString(buffer[1],variable[varn].displayed[i]);
    printf("Display Order: %-4.4s\n", buffer[1]);
    }
    else
    if(vartype==DEPENDENT_VAR)
    {
     sdoDots(buffer[0], ibuffer[i][0], VALUE_TAB, '.');
     if(i<NUM_RAW)decp=variable[varn].decp[i]; else decp=systemDecp;
     sprintFDecimal(buffer[1], variable[varn].value[i], decp);
     sprintf(printBuffer, "%s: %-10.10s", buffer[0], buffer[1]);
     sprintf(printBuffer, "%s %s", printBuffer, ibuffer[i][1]);
     sdoDots(printBuffer, printBuffer, COMMAND_TAB, ' ');
     printf("%s (Min-Max: %+8.3f - %+-8.3f) \n", printBuffer, variable[varn].min[i], variable[varn].max[i]);    
     if(i==0)
     {
     sprintStringVar(buffer[0], &variable[channel], channel, valueindex & 3 , VALUE_INDEX, STRING_DELIMITER, VALUE_TAB );
     doDots("Depends On");
     (void)getOrderString(buffer[1],variable[varn].displayed[i]);
     printf(": %-19.19s (Display Order: %-4.4s)\n", buffer[0], buffer[1]);
     } else
     if(i==1)
     {
     sprintStringVar(buffer[0], &variable[channel], channel, (valueindex>>2) & 3 , VALUE_INDEX, STRING_DELIMITER, VALUE_TAB );
     doDots("Depends On");
     (void)getOrderString(buffer[1],variable[varn].displayed[i]);
     printf(": %-19.19s (Display Order: %-4.4s)\n", buffer[0], buffer[1]);
     } else
     {
     //
     doDots("Measures");
     getValueIndexString(printBuffer, varn, i);
     (void)getOrderString(buffer[1],variable[varn].displayed[i]);
     printf(": %-19.19s (Display Order: %-4.4s)\n", printBuffer, buffer[1]);
     }
    }
    //
    if(vartype!=SILENT_VAR)
    {
    if(i<NUM_RAW)
    {
    doDots("Polynomial"); 
    printf(": ");
    printPolynomial(varn, i);
    printf("\n");
    }
    else
    {
    doDots("Scaling Factor");
    printf(": ");
    f=variable[varn].scaling[i-2];
    printf("*%+-4.4f (Scaling)\n", f);
    }
    }
    j=j<<1;
    }

    if(vartype!=SILENT_VAR)
    {
    printf("\n");
    doDots("Hysteresis For Limit Conditions"); printf(": %+-3.1f%c\n",  getHysteresisPercent(variable[varn].hysteresis), '%');
    sprintFormat(buffer[0], (BYTE*)&avgmode, FORMAT_B, SIZEBYTE);
    doDots("Acquisition Averaging Mode"); 
    printf(": %s\n", buffer[0]);
    sprintFormat(buffer[0], (BYTE*)&deltaavg, FORMAT_B, SIZEBYTE);
    doDots("Averaging Mode on Delta/Integral Values");
    printf(": %s\n", buffer[0]);
    doDots("Delta/Integral Values Apply To");
    printf(": %-32.32s\n", ibuffer[deltachannel][0]);
    printf("\n");
    doDots("Accumulator"); printf(": %+-6.3g\n", variable[varn].acc);
    doDots("Accumulator Applies To"); printf(": %-32.32s\n", ibuffer[valueindex][0]);
    }
    printf("\n");
    }
}

void showPacket(BYTE* datap, int total)
{
    int i;
    int j;
    //
    j=0;
    for(i=0; i< total; i++)
    {
    if((i % 16)==0)printf("\n Adr: 0x%4.4x.....", i);
    printf("0x%2.2x ",*datap);
    datap++;
    j++;
    }
    printf("\n");
    //
}

void showPacketASCII(BYTE* datap, int total)
{
    int i;
    int j;
    //
    j=0;
    for(i=0; i< total; i++)
    {
    if((i % 16)==0)printf("\n Adr: 0x%4.4x.....", i);
    if(((*datap)!=0x0D)&&((*datap)!='\b'))printf("%c",*datap); else printf("#");
    datap++;
    j++;
    }
    printf("\n");
    //
}

int updateTime(void)
{
        int i;
        time_t t;
        const time_t *ltm;
        t=time(NULL);
        ltm=&t;
        theLocalTime=*localtime(ltm);
        i=theLocalTime.tm_sec;
        while(i==theLocalTime.tm_sec){
            t=time(NULL);
            ltm=&t;
            theLocalTime=*localtime(ltm);
        }
//      printf("Hours: %d Minutes: %d Seconds: %d\r\n",theLocalTime->tm_hour, theLocalTime->tm_min, theLocalTime->tm_sec);
        return 0;
}

DOUBLE showPolyMemoryInUse(DOUBLE x)
{
 printf("%d", (int)polyMemoryUsedPercent);
 return x;
}
   
void showTime(void)
{
        updateTime();
        printf("Time is: ");
        printf("%s", asctime(&theLocalTime));
}

int showHelpScreen(void)
{
        int i;
        printf("Usage: cardisplay.exe <option>\n");
        printf("\n");
        printf("Option                Function\n");
        printf("-i                  : to show system settings\n");
        printf("-e                  : to show extended system settings\n");
        printf("-d                  : to change display settings\n");
        printf("-v                  : to change variable settings\n");
        printf("-c                  : to change calibration settings\n");
		printf("-o                  : to change digital output settings\n");
        printf("-s                  : to change system settings\n");
        printf("-q:<N>              : to show information for variable number N, eg. -q:0\n");
        printf("-x:<N>              : to show information for variable number N (Debug), eg. -x:0\n");
        printf("-r                  : reset the Car Scrolling Display and restore all defaults, eg. cardisplay -r\n");
        printf("-r:<filename>       : read settings from file <filename>, eg. -rMySettings                       \n");
        printf("-w:<filename>       : write settings to file <filename>, eg. -wMySettings                        \n");
        printf("-u:<N>              : collect N samples (data logging) to time-stapped-named file\n");
        printf("-l:<N>              : collect N samples (data logging) and prompt for filename\n");
        printf("-l:<N>:<filename>   : collect N samples (data logging) to file <filename>\n");
        printf("-z:<N>              : wait for N ms and recover Normal Update Mode, eg. -z:1000\n");
        printf("\n");
        printf("Notes: Use double quotes (%c) to specify arguments with spaces.\n", '"');
        printf("       Use the -z option if the Display is stuck in Logging Mode (blank)");
}

int openDevice(void)
{
    int i;
 if(open==0){
               maxn = MPUSBGetDeviceCount(vid_pid);
               i=0;
               while(i<MAX_NUM_MPUSB_DEV)
               {
               myOutPipe = INVALID_HANDLE_VALUE;
               myOutPipe = MPUSBOpen(i,vid_pid,out_pipe,MP_WRITE,0);
               myInPipe  = INVALID_HANDLE_VALUE;
               myInPipe  = MPUSBOpen(i,vid_pid,in_pipe,MP_READ,0);
//               printf("I: %d\n", i);
               i++;
               if((myInPipe!=INVALID_HANDLE_VALUE)&&(myOutPipe!=INVALID_HANDLE_VALUE))break;
               }
  //             printf("USB Device Open...... ");
               if((myInPipe!=INVALID_HANDLE_VALUE)&&(myOutPipe!=INVALID_HANDLE_VALUE))
               {
    //            printf("Ok.\n");
                open=1;
                }
                else
                {
                //printf("Error.\n");
                open=0;
                }
               }
                //else printf("Device is already open.\n");
   return open;
}

void printFailedToOpenDeviceMessage(void)
{
printf("Failed to Open Device. Is the Device Connected? If so, try unplugging and reconnecting it.\n");
}

void stripWS(char *optr, char *inptr)
{
    while((*inptr)!='\0')
    {
    if(((*inptr)!=' ')&&((*inptr)!='\n')&&((*inptr)!=':')&&((*inptr)!=0x0D)&&((*inptr)!='.')&&((*inptr)!=','))*optr++=*inptr;
    inptr++;
    }
    *optr='\0';
}

void stripWSNotSpace(char *optr, char *inptr)
{
    while((*inptr)!='\0')
    {
    if(((*inptr)!='\n')&&((*inptr)!=':')&&((*inptr)!=0x0D)&&((*inptr)!='.')&&((*inptr)!=','))*optr++=*inptr;
    inptr++;
    }
    *optr='\0';
}

void stripString(char *instring)
{
    // strip in place...
    char buffer[MAX_STRING_SIZE*2];
    sprintf(buffer, "%s", instring);
    stripWS(instring, buffer);
}

void stripStringNotSpace(char *instring)
{
    // strip in place...
    char buffer[MAX_STRING_SIZE*2];
    sprintf(buffer, "%s", instring);
    stripWSNotSpace(instring, buffer);
}

void writeDataLoggerToFile(long nsamples, long totalsamples, char* filename, int mode)
{
    char filename1[MAX_STRING_SIZE];
    char buffer[4][MAX_STRING_SIZE];
    char bufferOut[MAX_STRING_SIZE*32];
    char *fptr;
    BYTE *pptr;
    long d, i, j, k;
    long h;
    DWORD restemp;
    int idecp;
    long progress, oldprogress;
    BYTE logmask;
    BYTE logcomp[NUM_UPDATE_VARS];
    BYTE logcompare;
    ofstream datalog;

    updateTime();
    sprintf(buffer[0], "%s", asctime(&theLocalTime));
    stripString(buffer[0]); 

    if(mode==0)
    {
        sprintf(filename1, "data%s.csv", buffer[0]);
    
    } else
    {
     if((*filename)==0)
     {
         // prompt for filename
         sprintf(filename1, "data%s.csv", buffer[0]);
         d=enterString(filename1, "Enter Filename>", STRING_TAB, STRING_DELIMITER, "\n");
     } else
     {
        sprintf(filename1, "%s.csv", filename);
     }
    }
    oldprogress=-1;
    progress=0;
    datalog.open(filename1, ios::trunc);
    h=DataLogger[0][0].updateTime;
    getNameAndUnit(buffer[0], buffer[1], VAR_BATT, 0, MAX_STRING_SIZE);
    getNameAndUnit(buffer[2], buffer[3], VAR_LDR, 0, MAX_STRING_SIZE);
    // strip all commas
    stripStringNotSpace(buffer[0]);
    stripStringNotSpace(buffer[1]);
    stripStringNotSpace(buffer[2]);
    stripStringNotSpace(buffer[3]);
    sprintf(bufferOut,"Sample,Time (sec),%s (%s),%s (%s)", buffer[0], buffer[1], buffer[2], buffer[3]);
    for(i=0; i<NUM_VARS; i++)
    {
       logcomp[i]=variable[i].mode;
       logmask=(logcomp[i] & MODE_LOGMASK)>>4;
       for(j=0; j<NUM_VALUES; j++)
       {
        logcompare=(1<<j);
        if((logmask & logcompare)!=0)
        {
        getNameAndUnit(buffer[0], buffer[1], i, j, MAX_STRING_SIZE);
        stripStringNotSpace(buffer[0]);
        stripStringNotSpace(buffer[1]);
        sprintf(bufferOut, "%s,%s (%s)", bufferOut, buffer[0], buffer[1]);
         if((logcomp[i] & MODE_LOGMINMAX)!=0)
         {
          sprintf(bufferOut,"%s,%s (Min/Max)", bufferOut, buffer[0]);
         }
        }
       }
       if((logcomp[i] & MODE_LOGACC)!=0)
        {
        sprintf(bufferOut, "%s,Acc(%d)", bufferOut, i);
        }
    }
    datalog << bufferOut << "\n";
    // title done!
    for(j=0; j<nsamples; j++)
    {
    if(oldprogress!=progress)
    {
    sprintf(printBuffer, "Writing Log to File: %s. Total Written", filename1);
    doDotsSys(printBuffer, ":");
    printf("%d%c\r",progress,'%');
    oldprogress=progress;
    progress=(int)(100*(j+1)/totalsamples);
    }
      datalog.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
      datalog.precision(3);
      datalog << j << "," << ((DOUBLE)DataLogger[0][j].updateRealTime);
      datalog.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
      datalog.precision(systemDecp);
      datalog << "," << DataLogger[VAR_BATT][j].value[0] << "," << DataLogger[VAR_LDR][j].value[0];
      for(i=0; i<NUM_VARS; i++)
      {
        logmask=(logcomp[i] & MODE_LOGMASK)>>4;
        for(k=0; k<NUM_VALUES; k++)
        {
            logcompare=(1<<k);
            if((logmask & logcompare)!=0)
            {
                if(k<NUM_RAW)
                {
                idecp=variable[i].decp[k];
                } else
                {
                idecp=systemDecp;
                }
                datalog.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
                datalog.precision(idecp);
                datalog << "," << DataLogger[i][j].value[k];
                if((logcomp[i] & MODE_LOGMINMAX)!=0)
                {
                if(DataLogger[i][j].value[k]>DataLogger[i][j].max[k])
                datalog << ",>MAX";
                else
                if(DataLogger[i][j].value[k]<DataLogger[i][j].min[k])
                datalog << ",<MIN";
                else
                datalog << ",Normal";
                }
            }
        }
        if((logcomp[i] & MODE_LOGACC)!=0)
        {
            datalog.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
            datalog.precision(systemDecp);
            datalog << "," << DataLogger[i][j].acc;
        }
      }
    datalog << "\n";
    }
    sprintf(printBuffer, "Writing Log to File: %s. Total Written", filename1);
    doDotsSys(printBuffer, ":");
    printf("%d%c\n", progress,'%');
    datalog.close();
    return;
}

DWORD sendCommand(BOOT_DATA_PACKET* datap, DWORD* nb, DWORD* error)
{
    int i;
    DWORD address, addresstop;
    int addressfault;
    
    *error=0;
    addressfault=0;
    i=openDevice();
    if(i==0)
    {
    *error=1;                    // failed to open device
    } 
    else
    if(i==1)
    {
     if((datap->cmd==CAR_DISPLAY_RW_ROM)&&(datap->dir==WRITE_DIR))
     {
     
     address=((datap->pAdr.high)<<8)+(datap->pAdr.low);
     addresstop=address+datap->len;
     addressfault=address;
     
     if((address>=addressStringFlash) && (address<=(addressStringFlash+stringsSize)) &&
     (addresstop>=addressStringFlash) && (addresstop<=(addressStringFlash+stringsSize)))addressfault=0;
     
     

     if((address>=addressVariableFlash) && (address<=(addressVariableFlash+(NUM_VARS*alignNumberBoundary(szVariable, 32)))) &&
     (addresstop>=addressVariableFlash) && (addresstop<=(addressVariableFlash+(NUM_VARS*alignNumberBoundary(szVariable, 32)))))addressfault=0;
       
     
     } else
     if((datap->cmd==CAR_DISPLAY_RW_EE)&&(datap->dir==WRITE_DIR))
     {
     address=datap->iarg;
     addresstop=datap->iarg+datap->len;
     addressfault=address;
     if((address>=BOTTOM_EE_ADDRESS)&&(address<=TOP_EE_ADDRESS) && (addresstop>=BOTTOM_EE_ADDRESS) && (addresstop<=TOP_EE_ADDRESS))addressfault=0;
     }
     if(addressfault!=0){ res=MPUSB_FAIL; printf("Address Fault At: 0x%8.8x. ", addressfault); }
     else res=MPUSBWrite(myOutPipe,datap,EPSIZE,nb,USBTIMEOUT);
     if(res==MPUSB_SUCCESS)
     {
     res=MPUSBRead(myInPipe, &indatapacket, EPSIZE, nb, USBTIMEOUT);
        if(res==MPUSB_SUCCESS)
        {
  
        } else *error=2;         // read error
    } else *error=3;             // write error
    }
    return *error;
}

DWORD readRamVariable(char *symname, DWORD offset, int size, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;
    //    
    *error=0;
    pA=lookUpSymbolAdr(symname);
    if(pA==0)*error=1;
    pA+=offset;
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=size;
    datapacket.dir=READ_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=0;
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror; 
    pA=0;
    if(size<SIZEDOUBLE)copyPtr(&indatapacket.data[0], (BYTE*)&pA, size, READ_DIR);
    if((*error)==0)return pA; else return 0;
}

DWORD readRamVariableAutoSize(char *symname, DWORD offset, BYTE* mptr, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;
    SYMBOL *ptr;

    // this is the same as readRamVariable except uses the automatically sized value for the size
    *error=0;
    ptr=lookUpSymbol(symname);
    if(ptr==NULL)
    {
        *error=1;
        return 0;
    }
    pA=ptr->pAdr;
    pA+=offset;
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=ptr->size;
    datapacket.dir=READ_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=0;
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror; 
    pA=0;
    if(ptr->size==0)printf("Error!\n");
    if((ptr->size)<SIZEDOUBLE)copyPtr(&indatapacket.data[0], (BYTE*)&pA, ptr->size, READ_DIR);
    else if(ptr->size<DATA_SIZE)copyPtr(&indatapacket.data[0], mptr, ptr->size, READ_DIR);
    if((*error)==0)return pA; else return 0;
}

DWORD writeRamVariableAutoSize(char *symname, DWORD value, BYTE* mptr, DWORD offset, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;
    SYMBOL* ptr;
    //
    *error=0;
    ptr=lookUpSymbol(symname);
    if(ptr==NULL)
    {
        *error=1;
        return 0;
    }
    *error=0;
    pA=value;
    if(ptr->size<SIZEDOUBLE)copyPtr(&datapacket.data[0], (BYTE *)&pA, ptr->size, WRITE_DIR);
    else if(ptr->size<DATA_SIZE)copyPtr(&datapacket.data[0], mptr, ptr->size, WRITE_DIR);
    pA=lookUpSymbolAdr(symname);
    if(pA==0)*error=1;
    pA+=offset;
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=ptr->size;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror;
    //
    return *error;
}

DWORD writeRamVariable(char *symname, DWORD value, DWORD offset, int size, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;
    //
    *error=0;
    pA=value;
    if(size<DATA_SIZE)copyPtr(&datapacket.data[0], (BYTE *)&pA, size, WRITE_DIR);
    pA=lookUpSymbolAdr(symname);
    if(pA==0)*error=1;
    pA+=offset;
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=size;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror;
    //
    return *error;
}

DWORD writeRamMemory(char *symname, DWORD offset, int size, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;

    *error=0;
    pA=lookUpSymbolAdr(symname);
    if(pA==0)*error=1;
    pA+=offset;
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=size;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror; 
    return *error;
}

DOUBLE computeLdrPercent(DOUBLE x)
{
    return ldrPercent10/10.0;
}

DOUBLE computeBattVoltage(DOUBLE x)
{
    return battLevel*VOLTAGE_RANGE_SCALE;
}

DWORD readVariable(int varn, DWORD* error)
{
    DWORD localerror;
    int i;
    //
    *error=0;    
    if((varn>=0)&&(varn<NUM_VARS))
    {
    i=readRamVariable("variable", (DWORD)(varn*szVariable), szVariable, &localerror);
    if(localerror==0)(void)updateVariableInfo(&indatapacket.data[0], varn, READ_DIR, &i);
    } else
    if((varn==VAR_BATT)||(varn==VAR_LDR))
    {
        if(varn==VAR_BATT)
        {
        // read battery voltage!
        battLevel=readRamVariableAutoSize("battLevel", 0,(BYTE*)&battLevel, &localerror);
        battVoltage=computeBattVoltage(battLevel);
        variable[VAR_BATT].value[0]=battVoltage;
        //printf("Here Batt Voltage: %6.6f\n", battVoltage);
        } else
        {
        // read LDR!
        ldrPercent10=readRamVariableAutoSize("ldrPercent10", 0, (BYTE*)&ldrPercent10, &localerror);
        ldrPercent=computeLdrPercent(ldrPercent10);
        variable[VAR_LDR].value[0]=ldrPercent;
        //printf("Here LDR Level: %6.6f\n", ldrPercent);
        }
    }
    *error=localerror;
    return 0;
}

DWORD writeVariable(int varn, DWORD* error)
{
    DWORD localerror;
    int err;
    int i;
    DWORD pA;
    // to RAM only
    localerror=0;
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    (void)updateVariableInfo(&datapacket.data[0], varn, WRITE_DIR, &i);
    pA=lookUpSymbolAdr("variable");
    if(pA==0)*error=1;
    pA+=(varn*alignNumberBoundary(szVariable, 32));
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=szVariable;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    *error=localerror;
    return 0;
}


/*
DWORD getStringFlashAddress(int varn, int index)
{
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_STRINGS_PER_VAR)index=NUM_STRINGS_PER_VAR-1;
    return addressStringFlash+(maxStringSize*(varn*NUM_STRINGS_PER_VAR+index));
}
*/

DWORD getVariableFlashAddress(int varn)
{
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    return addressVariableFlash+varn*alignNumberBoundary(szVariable, 32);
}

DWORD putVariable(int varn, DWORD* error)
{
    DWORD localerror;
    int err, i;
    DWORD pA;
    // to Flash and RAM
    localerror=0;
    *error=0;
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(variable[varn].cmptotal==0)
    {
       // do nothing
    } else
    {
//    printf("Committing Variable\n");
    (void)updateVariableInfo(&datapacket.data[0], varn, WRITE_DIR, &i);
    pA=lookUpSymbolAdr("variable");
    if(pA==0)*error=1;
    pA+=(varn*szVariable);
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=szVariable;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    *error=localerror;
    if(localerror!=0)return 0;
    (void)updateVariableInfo(&datapacket.data[0], varn, WRITE_DIR, &i);
    pA=getVariableFlashAddress(varn);
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=szVariable;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    *error=localerror;
    if(localerror==0)variable[varn].cmptotal=0;
    }
    return 0;    
}

DWORD putVariableRamOnly(int varn, DWORD* error)
{
    DWORD localerror;
    int err, i;
    DWORD pA;
    // to Flash and RAM
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    (void)updateVariableInfo(&datapacket.data[0], varn, WRITE_DIR, &i);
    pA=lookUpSymbolAdr("variable");
    if(pA==0)*error=1;
    pA+=(varn*szVariable);
    datapacket.cmd=CAR_DISPLAY_RW_RAM;
    datapacket.len=szVariable;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdrRam.low=(pA);
    datapacket.pAdrRam.high=(pA>>8);
    datapacket.pAdrRam.upper=(pA>>16);
    err=sendCommand(&datapacket, &nb, &localerror); 
    *error=localerror;
    return 0;    
}

BYTE* updatePolyTableInfo(BYTE* ptr, int size, int direction)
{
    int i;
    
    for(i=0; i<size;i++)
    {
    ptr+=copyPtr(ptr, (BYTE*)&polyTable[i], SIZEBYTE, direction);
    }
    return ptr;
}

DWORD getPolyTableInfo(DWORD* error)
{
    DWORD localerror;
    int i;
    //
    i=readRamVariable("polyTable",0, MAX_POLY_INDEXES, &localerror);
    if(localerror==0)updatePolyTableInfo((BYTE*)&indatapacket.data[0], MAX_POLY_INDEXES, READ_DIR);
    *error=localerror;
    return 0;
    //
}


DWORD putPolyTableInfo(DWORD* error)
{
    DWORD localerror;
    int i;
    //
    updatePolyTableInfo((BYTE*)&datapacket.data[0], MAX_POLY_INDEXES, WRITE_DIR);
    i=writeRamMemory("polyTable",0,MAX_POLY_INDEXES, &localerror);
    *error=localerror;
    return 0;
    //
}

BYTE* updatePolyMemoryInfo(BYTE* ptr, int offset, int size, int direction)
{
    int i;
    
    for(i=0; i<size;i++)
    {
    ptr+=copyPtr(ptr, (BYTE*)(&polyMemory[offset+i]), SIZEDOUBLE, direction);
    }
    return ptr;
}

DWORD getPolyMemoryInfo(DWORD* error)
{
    DWORD localerror;
    int i;
    int n, total;
    
    total=MAX_POLY;
    n=0;
    localerror=0;
    while((localerror==0)&&(n<total))
    {
    i=readRamVariable("polyMemory", n*SIZEDOUBLE, SIZEDOUBLE, &localerror);
    if(localerror==0)updatePolyMemoryInfo(&indatapacket.data[0], n, 1, READ_DIR);
    n++;                                
    }
    *error=localerror;
    return 0;
}
      
DWORD putPolyMemoryInfo(DWORD* error)
{
    DWORD localerror;
    int i;
    int n, total;
    
    total=MAX_POLY;
    n=0;
    localerror=0;
    while((localerror==0)&&(n<total))
    {
    updatePolyMemoryInfo(&datapacket.data[0], n, 1, WRITE_DIR);
    i=writeRamMemory("polyMemory", n*SIZEDOUBLE, SIZEDOUBLE, &localerror);
    n++;                                
    }
    *error=localerror;
    return 0;
}

void updateFreezePointInfo(MAPPOINT* ptr, int varn)
{
    int i;
    for(i=0; i<NUM_VALUES;i++)
    {
    ptr->value[i]=variable[varn].value[i];
    }
    for(i=0; i<NUM_RAW; i++)
    {
    ptr->raw[i]=variable[varn].raw[i];
    }
    for(i=0; i<NUM_SCALING; i++)
    {
    ptr->scaling[i]=variable[varn].scaling[i];
    }
}

void showFreezePoint(MAPPOINT* ptr)
{
    int i;

    doDots("Freeze Point Information"); printf("\n");
    for(i=0; i<NUM_VALUES;i++)
    {
    doDots(&valueStrings[i][0]); printf(": %6.3g\n", ptr->value[i]);
    }
    for(i=0; i<NUM_RAW;i++)
    {
    doDots(&rawStrings[i][0]); printf(": %6.3g\n", ptr->raw[i]);
    }
    for(i=0; i<NUM_SCALING;i++)
    {
    doDots(&scalingStrings[i][0]); printf(": %6.3g\n", ptr->scaling[i]);
    }
}

void printFreezePoints(int start, int end, int valueindex)
{
  int i;
    
  if(start<end)printf("The Following Calibration Points Are Already Loaded:\n");
  i=start;
  while(i<end)
  {
  printf("Point #%d Current Y-Value (X-Value): %6.6f (%6.6f) Ok.\n", i+1, freezePoints[i].value[valueindex], freezePoints[i].raw[valueindex]);
  i++;   
  }   
}

int getImode(DWORD* locerror)
{
    return  readRamVariableAutoSize("imode", 0, 0, locerror);
}

int setWaitImode(int imode)
{
    DWORD locerror;
    int i, retries;
    
    i=getImode(&locerror);
    if((i==imode)||(locerror!=0))return locerror;
    writeRamVariable("rimode", (0x80 | imode), 0, SIZEBYTE, &locerror);
    i=imode + 1;
    retries=0;
    while((locerror==0)&&(i!=imode)&&(retries<RETRIES))
    {
     i=getImode(&locerror);
     DelayMs(IMODE_DELAY);
     retries++;
    }
    return locerror;
}

DWORD getFreezePoints(int varn, int valueindex, int start, int number, DWORD* error)
{
    // get freeze point on channel varn
    DWORD localerror, err;
    char buffer[2][MAX_STRING_SIZE];
    int i, j, k, d;
    char c;
    int pushing, cancel, vmode;
    double ftemp;
    int valuexerror;
    
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(valueindex<0)valueindex=0; else if(valueindex>=NUM_RAW)valueindex=NUM_RAW-1;
    if(number>=MAX_POLY)number=MAX_POLY-1; else if(number<0)number=1;
        
    i=writeRamVariable("pushVariable", varn+1, 0, SIZEBYTE, &localerror);
    if(localerror!=0){ *error=localerror; return 0; }

    i=writeRamVariable("pushCount", number, 0, SIZEBYTE, &localerror);
    if(localerror!=0)
    {
    *error=localerror; 
    return 0; 
    }

    i=writeRamVariable("pushIndex", valueindex, 0, SIZEBYTE, &localerror);
    if(localerror!=0)
    {
    *error=localerror; 
    return 0; 
    }

    i=writeRamVariable("pushing", 1, 0, SIZEBYTE, &localerror);
    if(localerror!=0)
    {
    *error=localerror; 
    return 0; 
    }

    i=writeRamVariable("pushStart", start, 0, SIZEBYTE, &localerror);
    if(localerror!=0)
    {
    *error=localerror; 
    return 0; 
    }
    DelayMs(MINOR_DELAY_MS);
    i=writeRamVariable("pushing", 2, 0, SIZEBYTE, &localerror);
    if(localerror!=0)
    {
    *error=localerror; 
    return 0; 
    }

    readVariable(varn, &localerror);
    err|=localerror;
    // save the current mode
    vmode=variable[varn].mode;
    // switch to direct view
    variable[varn].mode&=~0x01;
    variable[varn].mode|=MODE_NORMAL;
    // force direct mode to RAM only
    writeVariable(varn, &localerror);
    err|=localerror;
    // ok, so now the firmware will wait for the button press on that channel and collect
    // the freezepoint information
    cancel=0;
    printf("\nGathering Calibration Data...\n");
    printf("Press ESC to cancel, Any Other Key to Set the Calibration Value.\n");
    printFreezePoints(0, start, valueindex);
    j=start;
    number+=start;
    pushing=2;
    while((cancel==0)&&(j<number))
    {
    pushVariable=varn+1;
    err=0;
    while((err==0)&&(pushVariable!=0))
    {
//      pushing=readRamVariable("pushing",0, SIZEBYTE, &localerror);
        pushVariable=(BYTE)readRamVariable("pushVariable",0,SIZEBYTE,&localerror);
        err|=localerror;
        readVariable(varn, &localerror);
        err|=localerror;
        printf("\rPoint #%d Current Y-Value (X-Value): %+-12.6g (%+-8.6f)                 ", j+1, variable[varn].value[valueindex], variable[varn].raw[valueindex]);
        if(kbhit())
        {
            c=getch();
            if(c==0x1b)
            {
            // cancel!
            cancel=1;
            pushVariable=0;
            i=writeRamVariable("pushVariable", 0, 0, SIZEBYTE, &localerror);
            if(localerror!=0){ *error=localerror; return 0; }    
            printf(" ");
            } else
            {
            sprintf(&buffer[1][0],"\rPoint #%d Current Y-Value (X-Value): %+-12.6g (%+-8.6f) Enter New Y-Value>", j+1, variable[varn].value[valueindex], variable[varn].raw[valueindex]);
            sprintf(&buffer[0][0],"%lf", variable[varn].value[valueindex]);
            d=enterString(&buffer[0][0], &buffer[1][0], MAX_STRING_SIZE, STRING_DELIMITER, "Wait...");
            if(d!=0x1b)
            {
            sscanf(&buffer[0][0], "%lf", (double*)&ftemp);
            } else err=1;
            //printf("Value Entered was %lf\n", ftemp);
            pushVariable=0;
            i=writeRamVariable("pushVariable", 0, 0, SIZEBYTE, &localerror);
            if(localerror!=0){ *error=localerror; return 0; }        
            }
        }
        DelayMs(MINOR_DELAY_MS);
    }
    if(err==0)
    {
    } else
    {
        printf(" Error.\n");
        *error=err;
        return 0;
    }
    pushing=2;
    while(pushing!=3)
    {
    pushing=(BYTE)readRamVariable("pushing",0,SIZEBYTE,&localerror);
    err|=localerror;
    DelayMs(MINOR_DELAY_MS);
    }

    if(cancel==1)
    {
    i=writeRamVariable("pushing", 0, 0, SIZEBYTE, &localerror);
    j=0;
    }
    else
    {
    // collect the information now, copy to freezepoint!
    updateFreezePointInfo(&freezePoints[j], varn);
    freezePoints[j].value[valueindex]=(DOUBLE)ftemp;
    // printf("Begin.\n");
    // showFreezePoint(&freezePoints[j]);
    valuexerror=0;
    if(j>0)
    {
       // check for duplicate X values!
       for(k=0; k<=(j-1); k++)
       {
        if(freezePoints[j].raw[valueindex]==freezePoints[k].raw[valueindex])valuexerror=1;
       } 
    } else
    if(number==1)
    {
     // check for non zero denominator for scaling transformation.
     if(freezePoints[0].raw[valueindex]==0.0)
     valuexerror=1;
    }
        
    if(valuexerror==0)
    {
        pushing=3;
        j++;
        printf("Point Accepted.\n");
    } else
    {
        pushing=4;
        if(number>=2)
        printf("Duplicate X-Value Entered. Try Again.\n");
        else
        printf("Provide Non-Zero X-Value Point. Try Again.\n");
    }
    
    i=writeRamVariable("pushing", pushing, 0, SIZEBYTE, &localerror);
    if(localerror!=0){ *error=localerror; return 0; }
    }
        
    i=writeRamVariable("pushVariable", varn+1, 0, SIZEBYTE, &localerror);
    if(localerror!=0){ *error=localerror; return 0; }
    pushVariable=varn+1;
    }
    
    pushing=1;
    while(pushing!=5)
    {
    pushing=(BYTE)readRamVariable("pushing",0,SIZEBYTE,&localerror);
    err|=localerror;
    DelayMs(MINOR_DELAY_MS);
    }
    i=writeRamVariable("pushing", pushing+1, 0, SIZEBYTE, &localerror);
    err|=localerror;
    // restore the mode
    variable[varn].mode=vmode;
    // write to RAM only
    writeVariable(varn, &localerror);
    err|=localerror;
    return j;
}

DWORD getManualFreezePoints(int varn, int valueindex, int start, int number, DWORD* error)
{
    // get freeze point on channel varn
    DWORD localerror, err;
    char buffer[2][MAX_STRING_SIZE];
    int i, j, k, d;
    char c;
    int pushing, cancel, vmode;
    double ftemp, gtemp;
    int valuexerror;
    
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(valueindex<0)valueindex=0; else if(valueindex>=NUM_RAW)valueindex=NUM_RAW-1;
    if(number>=MAX_POLY)number=MAX_POLY-1; else if(number<0)number=1;
 
    cancel=0;
    printf("\nStarting Manual Calibration...\n");
    j=start;
    number+=start;
    //
    while((cancel==0)&&(j<number))
    {
        sprintf(buffer[1], "Point #%-3.3d Enter X-Value  >", j+1);
        sprintf(buffer[0], "%f", variable[varn].calibrationPoints[j][valueindex][0]);
        d=enterString(&buffer[0][0], &buffer[1][0], MAX_STRING_SIZE, STRING_DELIMITER, "\r");
        if(d!=0x1b)
        {
        sscanf(&buffer[0][0], "%lf", (double*)&ftemp);
        printf("Point #%-3.3d X-Value Entered: %lf\n", j+1, ftemp);
        } else 
        { 
            cancel=1; 
        }

        sprintf(buffer[1], "Point #%-3.3d Enter Y-Value  >", j+1);
        sprintf(buffer[0], "%f", variable[varn].calibrationPoints[j][valueindex][1]);
        d=enterString(&buffer[0][0], &buffer[1][0], MAX_STRING_SIZE, STRING_DELIMITER, "\r");
        if(d!=0x1b)
        {
        sscanf(&buffer[0][0], "%lf", (double*)&gtemp);
        printf("Point #%-3.3d Y-Value Entered: %lf\n", j+1, gtemp);
        } else 
        { 
            cancel=1; 
        }
        // collect the information now, copy to freezepoint!
        freezePoints[j].raw[valueindex]=(DOUBLE)ftemp;
        freezePoints[j].value[valueindex]=(DOUBLE)gtemp;
        valuexerror=0;
        if(j>0)
        {
        // check for duplicate X values!
        for(k=0; k<=(j-1); k++)
        {
         if(freezePoints[j].raw[valueindex]==freezePoints[k].raw[valueindex])valuexerror=1;
        } 
        }
        else
        if(number==1)
        {
        // check for non zero denominator for scaling transformation.
        if(freezePoints[0].raw[valueindex]==0.0)
        valuexerror=1;
        }
        
        if(valuexerror==0)
        {
        j++;
        } 
        else
        {
        if(number>=2)
        printf("Duplicate X-Value Entered. Try Again.\n");
        else
        printf("Provide Non-Zero X-Value Point. Try Again.\n");
        }
    }
    
    if(cancel==1)
    {
        printf("\nAction Cancelled.\n");
        *error=1;
        return 0;
    }
    variable[varn].calibrationPointIsDefault[valueindex]=0;
    return j;
}

int normalizeCalibrationPoints(int varn, int index)
{
    int i; 
    DOUBLE maximum;
    DOUBLE minimum;
    DOUBLE scale;
    DOUBLE result;
    // normalizes the x values of the entered data points
    i=1;
    maximum=variable[varn].calibrationPoints[0][index][0];
    minimum=variable[varn].calibrationPoints[0][index][0]-0.1;
    while(i<variable[varn].numCalibrationPoints[index])
    {
    if(maximum<variable[varn].calibrationPoints[i][index][0])
    {
        maximum=variable[varn].calibrationPoints[i][index][0];
    } 
    if(minimum>variable[varn].calibrationPoints[i][index][0])
    {
        minimum=variable[varn].calibrationPoints[i][index][0];
    }
    i++;
    }
    //printf("Minimum is: %6.6f Maximum is: %6.6f\n", minimum, maximum);
    scale=maximum-minimum;
    if(scale>0.0)
    {
         
     i=0;
     while(i<variable[varn].numCalibrationPoints[index])
     {
        result=(variable[varn].calibrationPoints[i][index][0]-minimum)/scale;
        variable[varn].calibrationPoints[i][index][0]=result;
        i++;
     }
    }
    return 0;
}

int importCalibrationPoints(char* filename, int varn, int index, int start, DWORD *error)
{
    // load calibration Points from file filename
    // into variable varn at index index 
    // return 0 error if ok and return number of calibration points loaded successfully...
    char linebuffer[MAX_STRING_SIZE];
    double farg;
    DWORD length;
    int i, j, line;
    char c;
    int lp;
    int maxnumber, runningdup;
    DWORD runningerr, locerror, locduplicate;
    MAPPOINT mappoint;
    char filename1[MAX_STRING_SIZE];
    ifstream icalFile;
    *error=0;
    runningerr=0;
    runningdup=0;
    maxnumber=2;        // 2 points per line
    //
    sprintf(filename1, "%s", filename);
    icalFile.open(filename1, ifstream::in);
    i=0;    // i tracks the number of calibration Points (x,y pairs)
    line=0;
    if(icalFile.good())
    {
        icalFile.seekg(0);
        icalFile.getline(linebuffer, MAX_STRING_SIZE);
        printf("\nFile Info: %-36.36s\n", linebuffer);
        variable[varn].numCalibrationPoints[index]=start;
        while((icalFile.eof())==0)
        {
            icalFile.getline(linebuffer, MAX_STRING_SIZE);
            line++;
            j=0;
            lp=0;
            while((j<maxnumber)&&(lp<MAX_STRING_SIZE)&&(linebuffer[lp]!='\0'))
            {
            while((linebuffer[lp]!=0)&&(isNumeric(linebuffer[lp])==0))lp++;
            if(isNumeric(linebuffer[lp])==1)
            { 
             if(j<maxnumber)
             {
                farg=atof(&linebuffer[lp]);
                //printf("farg: %6.6f\n", farg);
                if(j==0)
                {
                    mappoint.raw[index]=farg;
                }
                else mappoint.value[index]=farg;
                j++;
             } 
            }
             while((linebuffer[lp]!=0)&&(isNumeric(linebuffer[lp])==1))lp++;

            }
            // finished the line, so add the point!
            if(j>=maxnumber)
            {
            addCalibrationPoint(varn, index, &mappoint, &locerror, &locduplicate);
            runningerr|=locerror;
            runningdup+=locduplicate;

            if(locerror==0)
            {
                printf("Line %-3.3d Loading Point #%-3.0d (%+10.5f, %+-10.5f)........:", line, variable[varn].numCalibrationPoints[index], mappoint.raw[index], mappoint.value[index]);
                if(locduplicate==0)
                {
                printf(" Ok.\n");
                i++;
                } else
                {
                printf(" Duplicate X-Value!n");
                }
            } 
            else
            {
                if(locerror==1)
                {
                printf("Line %-3.3d Too Many Calibration Points........................: Ignored\n", line);
                }
                else
                if(locerror==2) 
                {
                printf("Line %-3.3d Zero X-Value.......................................: Ignored\n", line);
                }
                else
                printf("Line %-3.3d Error..............................................: Ignored\n", line);
            }
            
            } else 
            if(j>0)
            {
                printf("Line %-3.3d Insufficient Data..................................: Ignored\n", line);
            }
        }  
    } 
    else 
    { 
        *error=-1;
        i=-1;
    }
    *error=runningerr;
    icalFile.close();
    if(i>0)normalizeCalibrationPoints(varn,index);
    return i;
}

/*
int loadCalibrationPoints(void)
{
    streamsize length;
    char linebuffer[MAX_STRING_SIZE], ignoreline[MAX_STRING_SIZE];
    DWORD dwadr;
    char c;
    int i, j, h, k, l, m, b, already;
    int ii, jj, kk, mm;
    int varn, index;
    DOUBLE dataPoints[CAL_POINTS_PER_LINE];
    fstream calibrationfile;
    // Put default 0.0's
    varn=0;
    sprintf(linebuffer, "calibrationFile.csv");
    i=0;
    k=0;
    sprintf(printBuffer, "Loading Calibration Point File: %s", linebuffer);
    doDotsSys(printBuffer, ":");
    calibrationfile.open(linebuffer, fstream::in);
    calibrationfile.seekg(0, ios::end);
    length=calibrationfile.tellg();
    if(length>0)printf("Ok.\n"); else printf("Default File Created.\n");
    calibrationfile.seekg(0, ios::beg);
    if(length>0)
    {    
    while((!(calibrationfile.eof()))&&(i<(MAX_POLY+1)))
    {
    l=0;
    linebuffer[l]='\0';
    while((!calibrationfile.eof())&&(linebuffer[l]=='\0'))calibrationfile.getline(linebuffer,MAX_STRING_SIZE);
    
    if(linebuffer[l]!='\0')
    {
    j=0;
    h=0;
    for(m=0; m<CAL_POINTS_PER_LINE;m++)dataPoints[m]=0;
    
    while((linebuffer[l]!='\0')&&(j<CAL_POINTS_PER_LINE))
    {
    while((linebuffer[l]!=0)&&(isNumeric(linebuffer[l])==0))l++;
    if(isNumeric(linebuffer[l])==1)
    { 
        h++; 
        dataPoints[j]=atof(&linebuffer[l]);
//      printf("Got%d %6.6f ",j, dataPoints[j]);
    }
    while((linebuffer[l]!=0)&&(isNumeric(linebuffer[l])==1))l++;
    j++;
    }
    
    if(h>=CAL_HEADER_SIZE)
    {

        varn=(int)dataPoints[CAL_VARN_INDEX];
        index=(int)dataPoints[CAL_INDEX_INDEX];
        if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
        if(index<0)index=0; else if(index>=NUM_RAW)index=NUM_RAW-1;
        
        if((varn!=(int)dataPoints[CAL_VARN_INDEX])||(index!=(int)dataPoints[CAL_INDEX_INDEX]))
        {
           sprintf(printBuffer, "Line %d... Variable or Index Out of Range!", k+1);
           doDotsSys(printBuffer, ".");
           printf("\n");
        }
        else
        {
        //
        // before accepting this point, we must make sure there is no other point
        // already loaded with the same x coordinate...
        // we cannot accept two points with the same x coordinate!
        //
        already=0;
        b=0;
        while((b<variable[varn].numCalibrationPoints[index])&&(already==0))
        {
         // search the points already there, if equal then flag it!
         if(variable[varn].calibrationPoints[b][index][0]==dataPoints[CAL_HEADER_SIZE])already|=1;
         b++;
        }
        if(already==0)
        {
  //      printf("Line %d... Variable %d, Index %d, Accepting Data Point (%6.6f, %6.6f)\n", k+1, varn, index,  dataPoints[CAL_X_INDEX], dataPoints[CAL_Y_INDEX]);
        // now copy the points over to the variable data structure...
        b=0;
        while(b<CAL_DATA_SIZE)
        {
         variable[varn].calibrationPoints[(variable[varn].numCalibrationPoints[index])][index][b]=(DOUBLE)dataPoints[b+CAL_HEADER_SIZE];
         b++;                      
        }
        variable[varn].numCalibrationPoints[index]++;
        variable[varn].calibrationPointIsDefault[index]=(INT)dataPoints[CAL_IS_DEFAULT_INDEX];
        i++;
        }
        else
        {
        // a duplicate x value- so discard it!
        sprintf(printBuffer, "Line %d... Variable %d, Index %d, Ignoring Duplicate X Data Point (%6.6f)", k+1, varn, index,  dataPoints[CAL_X_INDEX], dataPoints[CAL_Y_INDEX]);
        doDotsSys(printBuffer,".");
        printf("\n");
        }
       }
    }
    k++;
    }
   }
   }
   calibrationfile.close();
   ii=0;
   jj=0;
   for(kk=0; kk<NUM_VARS; kk++)
   {
      for(mm=0; mm<NUM_RAW; mm++)
      {
        if(variable[kk].calibrationPointIsDefault[mm]==1)
        {

                variable[kk].calibrationPoints[0][mm][0]=1.0;
                variable[kk].calibrationPoints[0][mm][1]=1.0;// default scaling = 1.0/1.0=1.0
                variable[kk].numCalibrationPoints[mm]=1;
                variable[kk].interpolation[mm]=0;
                ii++;
        } else jj+=(variable[kk].numCalibrationPoints[mm]); 
      }
   }      
   
   if(k!=0)
   {
   sprintf(printBuffer, "Points Correctly Loaded: %d out of %d", i, k);
   doDotsSys(printBuffer,":");
   printf("%d%c\n", 100*i/(k), '%');
   }
   doDotsSys("Points Loaded with User Values", ":"); printf("%d%c\n", jj*100/(jj+ii), '%'); 
   doDotsSys("Points Loaded with Default Values", ":"); printf("%d%c\n",100-(jj*100/(jj+ii)), '%');
   doDotsSys("Total Points Loaded", ":"); printf("%d\n", ii+jj);
   calibrationfile.close();
   return 0;
}

int writeCalibrationPoints(void)
{
    streamsize length;
    char linebuffer[MAX_STRING_SIZE], filename[MAX_STRING_SIZE];
    int i, j;
    int varn, index, n;
    ofstream outcalibrationfile;
    
    sprintf(filename, "calibrationFileOut.csv");
    outcalibrationfile.open(filename, ios::trunc);
    n=0;
    for(varn=0; varn<NUM_VARS; varn++)
    {
                for(index=0; index<NUM_RAW; index++)
                {
                     
                     i=0;
                     while(i<variable[varn].numCalibrationPoints[index])
                     {
                     outcalibrationfile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
                     outcalibrationfile.precision(0);
                     outcalibrationfile << (DOUBLE)varn << ",";
                     outcalibrationfile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
                     outcalibrationfile.precision(0);
                     outcalibrationfile << (DOUBLE)index << ",";     
                     outcalibrationfile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
                     outcalibrationfile.precision(0);
                     outcalibrationfile << (DOUBLE)(variable[varn].calibrationPointIsDefault[index]) << ",";     
                    // printf("v:%d, i:%d, numpoints:%d \n", varn, index, variable[varn].numCalibrationPoints[index]);
                     j=0;
                     while(j<CAL_DATA_SIZE)
                     {
                     outcalibrationfile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
                     outcalibrationfile.precision(6);
                     outcalibrationfile << (DOUBLE)variable[varn].calibrationPoints[i][index][j];
                     if(j!=(CAL_DATA_SIZE-1))outcalibrationfile << ",";
                     //printf("%3.3f, ", (DOUBLE)variable[varn].calibrationPoints[i][index][j]);
                     n++;
                     j++;
                     }
                     outcalibrationfile << "\n";
                     i++;
                     }
                                                                                             
                                                                        
                     }                        
                }
    sprintf(printBuffer, "Writing To Calibration Point File: %s. Total Points Written", filename);
    doDotsSys(printBuffer, ":");
    printf("%d\n", n/2);
    outcalibrationfile.close();
    return 0;
}
*/

DWORD addCalibrationPoint(int varn, int index, MAPPOINT* indata, DWORD* error, DWORD* duplicate)
{
      //
      // attempt to add a calibration point to variable varn index index
      // returns 0 in error if success or 1 if error (eg. out of memory)
      // or if duplicate X value then it replaces the previous value rather than adds... 
      // etc.
      //
      int i, nn;
      int locerror;
      int already;
      int b;
      
      if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
      if(index<0)index=0; else if(index>=NUM_RAW)index=NUM_RAW-1;
      *duplicate=0;
      nn=variable[varn].numCalibrationPoints[index];
      // the number!
      if((polyMemoryUsed+1)>=MAX_POLY)
      {
      // out of memory
       *error=1;
      } else
      if(indata->raw[index]==0.0)
      {
       // reject a zero X point
       *error=2;
      }
      else
      {
        
        already=0;
        b=0;
        //printf("Begin Point Search.\n");     
        while((b<(variable[varn].numCalibrationPoints[index]))&&(already==0))
        {
        // search the points already there, if equal then flag it!
        //printf("b: %d and %6.6f vs %6.6f\n", b, variable[varn].calibrationPoints[b][index][0], indata->raw[index]);
        if(variable[varn].calibrationPoints[b][index][0]==indata->raw[index])already|=1;
        
        b++;
        }
        //printf("Already: %d\n", already);
        
        if((nn>1)||((variable[varn].calibrationPointIsDefault[index])==0))
        {
         if(already==0)
         {
         // not a duplicate X value so add it...
         variable[varn].calibrationPoints[nn][index][0]=indata->raw[index];   // X coordinate
         variable[varn].calibrationPoints[nn][index][1]=indata->value[index]; // Y coordinate
         nn++;
         }
         else
         {
         // a duplicate X value so replace the point previously there...
         variable[varn].calibrationPoints[b-1][index][0]=indata->raw[index];
         variable[varn].calibrationPoints[b-1][index][1]=indata->value[index];
         *duplicate=1;
         }
        //
        } else
        {
        // the point was a default scaling point so overwrite it first...
        variable[varn].calibrationPoints[0][index][0]=indata->raw[index];
        variable[varn].calibrationPoints[0][index][1]=indata->value[index];
        nn=1;
        variable[varn].calibrationPointIsDefault[index]=0;
        }
        variable[varn].numCalibrationPoints[index]=nn;
       *error=0;                               
       }
      return 0;
}

/*
int getStringsInternal(BYTE* ptr, int size, DWORD *err)
{
    DWORD locerr, runningerr;
    int i,ii, j, k;
    DWORD pA;
    DWORD nb;
    BYTE* locptr;

    j=STRINGPKSIZE;   
    k=size;
    i=0;
    runningerr=0;
    while((k>=j)&&(runningerr==0))
    {
    pA=(DWORD)addressStringFlash;
    pA+=i;
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=j;
    datapacket.dir=READ_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=0;
    ii=sendCommand(&datapacket, &nb, &locerr); 
    runningerr|=locerr;
    if(runningerr==0)
     {
     // now copy to ram from indatapacket
     locptr=ptr;
     locptr+=i;
     copyPtr((BYTE*)&indatapacket.data[0], locptr, j, READ_DIR);
     k-=j;
     i+=j;
     }
    }    

    if((runningerr!=0)||(k!=0))
    {
    // size must be a multiple of 32!
//    if(k!=0)printf("Bad Strings Size.\n"); 
    runningerr=1;
    *err=runningerr;
    return 0;
    } else *err=0;
  //  printf("Bytes Done: %d\n",i);
    // done!
    return 0;
}
*/

int getStrings(BYTE* ptr, BYTE* icmpptr, int size, DWORD *err)
{
    DWORD locerr, runningerr;
    int i,ii, j, k;
    DWORD pA;
    DWORD nb;
    BYTE* locptr;
    BYTE* loccmpptr;

    j=STRINGPKSIZE;   
    k=size;
    i=0;
    runningerr=0;
    while((k>=j)&&(runningerr==0))
    {
    pA=(DWORD)addressStringFlash;
    pA+=i;
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=j;
    datapacket.dir=READ_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=0;
    ii=sendCommand(&datapacket, &nb, &locerr); 
    runningerr|=locerr;
    if(runningerr==0)
     {
     // now copy to ram from indatapacket
     locptr=ptr;
     locptr+=i;
     loccmpptr=icmpptr;
     loccmpptr+=i;
     copyPtr((BYTE*)&indatapacket.data[0], locptr, j, READ_DIR);
     copyPtr((BYTE*)&indatapacket.data[0], loccmpptr, j, READ_DIR);
     k-=j;
     i+=j;
     }
    }    

    if((runningerr!=0)||(k!=0))
    {
    // size must be a multiple of 32!
//    if(k!=0)printf("Bad Strings Size.\n"); 
    runningerr=1;
    *err=runningerr;
    } else *err=0;
    // printf("Bytes Done: %d\n",i);
    // done!
    return 0;
}

/*
int putStringsInternal(BYTE* ptr, DWORD *err)
{
    DWORD locerr, runningerr;
    int i, ii, j, k;
    DWORD pA;
    DWORD nb;
    BYTE* locptr;

    j=STRINGPKSIZE; // must be multiple of 32
    k=size;
    i=0;
    runningerr=0;
    while((k>=j)&&(runningerr==0))
    {
    locptr=ptr;
    locptr+=i;
    copyPtr((BYTE*)&datapacket.data[0], locptr, j, WRITE_DIR);
    pA=(DWORD)addressStringFlash;
    pA+=i;
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=j;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=0;
    ii=sendCommand(&datapacket, &nb, &locerr); 
    runningerr|=locerr;
    if(runningerr==0)
     {
     k-=j;
     i+=j;
     }
    DelayMs(FLASHWR_DELAYMS);  // so as not to overwhelm the flash writer server on the device!
    }    

    if((runningerr!=0)||(k!=0))
    {
    // size must be a multiple of 32!
    if(k!=0)printf("Bad Strings Size.\n"); 
    runningerr=1;
    *err=runningerr;
    return 0;
    } else *err=0;
    //printf("Bytes Done: %d\n",i);
    // done!
    return 0;
}
*/

void eraseStringFlash(DWORD* err)
{
    int i, j, k;
    DWORD pA,locerr, runningerr, nb;
 
    (void)setWaitImode(FLASHWRITE_MODE);
    j=32;
    i=0;
    runningerr=0;
    while((runningerr==0)&&(i<stringsSize))
    {
    pA=(DWORD)addressStringFlash;
    pA+=i;
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=j;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=0;
    for(k=0; k<DATA_SIZE; k++)
    {
     datapacket.data[k]=0xFF;
    }
    (void)sendCommand(&datapacket, &nb, &locerr); 
    runningerr|=locerr;
    i+=j;
    DelayMs(FLASHWR_DELAYMS);  // so as not to overwhelm the flash writer server on the device!
    }
    if(i<stringsSize)*err=1; else *err=0;
  
}

int putStrings(BYTE* ptr, BYTE* icmpptr, int size, DWORD *err)
{
    DWORD locerr, runningerr;
    int i, ii, totalchanged, j, k;
    DWORD pA;
    DWORD nb;
    BYTE *locptr;
    BYTE *loccmpptr;

    // same as above but only writes to flash if the 32 byte blocks are different!
    // better for reducing wear on the flash memory.
    j=STRINGPKSIZE; // must be multiple of 32
    k=size;
    i=0;
    totalchanged=0;
    runningerr=0;
    while((k>=j)&&(runningerr==0))
    {
    locptr=ptr;
    locptr+=i;
    loccmpptr=icmpptr;
    loccmpptr+=i;
    ii=cmpPtr(locptr, loccmpptr, j);        // j byte blocks
    if(ii!=0)
    {
    // prepare packet
    (void)setWaitImode(FLASHWRITE_MODE);
    totalchanged+=ii;
    copyPtr((BYTE*)&datapacket.data[0], locptr, j, WRITE_DIR);
    pA=(DWORD)addressStringFlash;
    pA+=i;
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=j;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=0;
    ii=sendCommand(&datapacket, &nb, &locerr); 
    runningerr|=locerr;
    }
    if(runningerr==0)
    {
    k-=j;
    i+=j;
    }
    DelayMs(FLASHWR_DELAYMS);  // so as not to overwhelm the flash writer server on the device!
    }    
    if((runningerr!=0)||(k!=0))
    {
    // size must be a multiple of 32!
    //if(k!=0)printf("Bad Strings Size.\n"); 
    runningerr=1;
    *err=runningerr;
    } else *err=0;
    //printf("Bytes Done: %d\n",i);
    // done!
  
    return totalchanged;
}

/*
int copyCmpVariable(VARIABLE* source, VARIABLE* dest)
{
    int j, z;
    // returns the number of settings that are different too!
    j=0;
   
     for(z=0; z<NUM_VALUES; z++)
     {
     if((dest->min[z])!=(source->min[z]))
     {
         dest->min[z]=source->min[z];
         j++;
     }
     if((dest->max[z])!=(source->max[z]))
     {
         dest->max[z]=source->max[z];
         j++;
     }
     if((dest->name[z])!=(source->name[z]))
     {
         dest->name[z]=source->name[z];
         j++;
     }
     
     }
          
     for(z=0; z<NUM_SCALING; z++)
     {
     if((dest->scaling[z])!=(source->scaling[z]))
     {
         dest->scaling[z]=source->scaling[z];
         j++;
     }
     }  

     for(z=0; z<NUM_RAW; z++)
     {
     if((dest->decp[z])!=(source->decp[z]))
     {
         dest->decp[z]=source->decp[z];
         j++;
     }
     }  
    
     for(z=0; z<NUM_STRINGS_PER_VAR; z++)
     {
     if((dest->name[z])!=(source->name[z]))
     {
         dest->name[z]=source->name[z];
         j++;
     }
     }  
     
     if((dest->hysteresis)!=(source->hysteresis))
     {
         dest->hysteresis=source->hysteresis;
         j++;
     }
    return j;
}

int copyCmpVariables(VARIABLE* source, VARIABLE* dest, int start, int end)
{
    int i, tally;
    i=start;
    tally=0;
    while(i<end)
    {
    source->cmpTotal=copyCmpVariable(source, dest);
    tally+=source->cmpTotal;
    source++;
    dest++;
    i++;
    }
    return tally;
}
*/

int getAllVariableInfo(DWORD* err)
{
    DWORD locerr, runningerr;
    int i, j, k;
    
    runningerr=0;
    for(i=0; i<NUM_VARS;i++)
    {
//           printf("Reading Variable %d...", i);
             readVariable(i, &locerr);
//           if(locerr==0)printf("Ok.\n"); else printf("Error!\n");
             runningerr|=locerr;
    }

    if(runningerr==0)
    {
    // now we load the strings memory
    // we assume that the total size of the flash memory is as indicated
    // in the variable stringsSize (typically around 384 bytes) so we 
    // so now update the local copy here 
    // printf("Reading Strings: %d \n", stringsSize);
    i=getStrings((BYTE*)&Strings, (BYTE*)&StringsCmp, stringsSize, &locerr);
    runningerr|=locerr;
    if(runningerr==0)
     {
     // now compute the value of endindex, ie the number of strings loaded!
     //printf("End Index is %d\n", endIndex);
     endIndex=computeEndIndex((BYTE*)Strings, stringsSize, STRING_DELIMITER);
     computeRelativeStringAddresses(READ_DIR);
     }
    }
    *err=runningerr;
    return 0;
}

DWORD showPolyInfo(void)
{
    int i;
    doDots("Polynomial Information"); printf("\n");
    doDots("Polynomial Indexes"); printf("\n");
    for(i=0; i<MAX_POLY_INDEXES; i++)
    {
        printf("Polynomial Index %2.2d: %2.2d\n", i, polyTable[i]);
    }
    printf("\n");
    doDots("Polynomial Memory"); printf("\n");
    for(i=0; i<MAX_POLY; i++)
    {
        printf("Poly Memory %2.2d: %6.6f\n", i, polyMemory[i]);
    }
    showPolyMemoryInUse(0.0);
    return 0;
}

DWORD showAllPolynomials(void)
{
      
      int v, i;
      //
      for(v=0; v<NUM_VARS; v++)
      {
               for(i=0; i<NUM_RAW; i++)
               {
               printf("Polynomial Var: %d Index: %d Polynomial: ", v,i); 
               printPolynomial(v,i); 
               }
      }     
}

void loadCalibrationPointsWithPolynomialData(void)
{
    int h, k, a, i, j;
    double x, y;
    int deg;
    
    for(h=0; h<NUM_VARS; h++)
    {
     for(k=0; k<NUM_RAW; k++)
     {
      x=0.097;
      variable[h].numCalibrationPoints[k]=0;
      for(i=0; i<(variable[h].interpolation[k]+1); i++)
      { 
            deg=variable[h].interpolation[k];
            a=polyTable[getPolyTableAddress(h, k)];
            y=computePolynomialValue((DOUBLE*)&polyMemory[a], deg, x);
            //printf("x: %6.6f y:%6.6f \n", x,y);
            variable[h].calibrationPoints[i][k][0]=x;
            variable[h].calibrationPoints[i][k][1]=y;
            variable[h].numCalibrationPoints[k]++;
            variable[h].calibrationPointIsDefault[k]=1;
            x+=0.1;
      }  
     }
    }

}

DWORD getPolyInfo(DWORD* error)
{
    DWORD localerror, err;
    int i;
    
    clearPolyMemory();
    localerror=0;
    i=getPolyMemoryInfo(&err);
    localerror|=err;
    i=getPolyTableInfo(&err);
    localerror|=err;
    if(localerror==0)polyMemoryUsed=polyTable[MAX_POLY_INDEXES-1]; else polyMemoryUsed=0;
    polyMemoryUsedPercent=(100.0*polyMemoryUsed/(MAX_POLY-1));
    return localerror;
}

DWORD putPolyInfo(DWORD* error)
{
    DWORD localerror, err;
    int i;
    localerror=0;
    i=putPolyMemoryInfo(&err);
    localerror|=err;
    i=putPolyTableInfo(&err);
    localerror|=err;
    return localerror;
}

void updatePolyMemory(DWORD* err)
{
    int i;
    if(polyUpdate==0)
    {
    //doDotsSys("Polynomial Table and Indexes Unchanged. Polynomial Memory In Use", ":");
    *err=0;
    } else
    {
    i=putPolyInfo(err);
    if((*err)==0)polyUpdate=0;
    }
}

void updateVariable(int varn, DWORD* err)
{
    putVariableRamOnly(varn, err);
}

/*
DWORD writeStringFlash(int varn, int index, DWORD* error)
{
    DWORD localerror;
    DWORD pA;
    
    if(varn<0)varn=0; else if(varn>=NUM_VARS)varn=NUM_VARS-1;
    if(index<0)index=0; else if(index>=NUM_STRINGS_PER_VAR)index=NUM_STRINGS_PER_VAR-1;
    pA=getStringFlashAddress(varn, index);
    datapacket.cmd=CAR_DISPLAY_RW_ROM;
    datapacket.len=maxStringSize;
    datapacket.dir=WRITE_DIR;
    datapacket.pAdr.low=(pA);
    datapacket.pAdr.high=(pA>>8);
    datapacket.pAdr.upper=(pA>>16);
    *error=sendCommand(&datapacket, &nb, &localerror);
    return localerror;
}
*/

DWORD writeEEVariable(INT addressEE, DWORD value, int size, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;

    *error=0;
    pA=value;
    copyPtr(&datapacket.data[0], (BYTE *)&pA, size, WRITE_DIR);
    datapacket.cmd=CAR_DISPLAY_RW_EE;
    datapacket.len=size;
    datapacket.dir=WRITE_DIR;
    datapacket.iarg=addressEE;
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror; 
    return *error;
}

DWORD writeEEVariableAutoSize(char *symname, DWORD value, BYTE* mptr, INT eeAdr, DWORD* error)
{
    DWORD pA;
    int i, err;
    DWORD localerror;
    SYMBOL* ptr;
    //
    *error=0;
    ptr=lookUpSymbol(symname);
    if(ptr==NULL)
    {
        *error=1;
        return 0;
    }
    *error=0;
    pA=value;
    //printf("Here @ ptr->size: %d eeAdr %d value: %d \n", ptr->size, eeAdr, value);
    if(ptr->size<=SIZEDOUBLE)
    {
    copyPtr(&datapacket.data[0], (BYTE *)&pA, ptr->size, WRITE_DIR);
    }
    else
    {
    copyPtr(&datapacket.data[0], (BYTE *)mptr, ptr->size, WRITE_DIR);
    }
    pA=lookUpSymbolAdr(symname);
    if(pA==0)*error=1;
    datapacket.cmd=CAR_DISPLAY_RW_EE;
    datapacket.len=ptr->size;
    datapacket.dir=WRITE_DIR;
    datapacket.iarg=eeAdr;
    //printf("About to send the following packet");
    //showPacket((BYTE*)&datapacket, 128);
    err=sendCommand(&datapacket, &nb, &localerror); 
    if(localerror!=0)*error=localerror;
    //
    return *error;
}

DWORD writeEEAndRamVariable(char *symname, DWORD value, int size, INT addressEE, DWORD* error)
{
      DWORD locerror;
      int i;
            
   
      locerror=0;
      i=writeRamVariable(symname, value, 0, size, &locerror);
      if(locerror==0)
      {
       // success so write to EEPROM too!
       writeEEVariable(addressEE, value, size, &locerror);
       if(locerror==0)
       {
        *error=0;
       } else
       {
         *error=1;
       }
                             
      } else *error=1;
      return *error;
}

DWORD writeEEAndRamVariableAutoSize(char *symname, DWORD value, BYTE* mptr, INT addressEE, DWORD* error)
{
      DWORD locerror;
      int i;
      SYMBOL *ptr;
           
      //printf("Here \n");
      locerror=0;
      *error=0;
      ptr=lookUpSymbol(symname);
      if(ptr==NULL)
      {
        *error=1;
        return 0;
      }
      //printf("Begin 1\n");
      i=writeRamVariableAutoSize(symname, value, mptr, 0, &locerror);
      if(locerror==0)
      {
      //printf("Begin 2 EEADR: %d\n", addressEE);
      writeEEVariableAutoSize(symname, value, mptr, addressEE, &locerror);
      // success so write to EEPROM too!
      if(locerror==0)
      {
       *error=0;
      } else
      {
        *error=1;
      }
     } else *error=1;
      return *error;
}

DWORD writePolyEE(BYTE* ptr, DWORD* error)
{
    int i, n, total, adr;
    DWORD err, locerr;
    
    locerr=0;
    i=0;
    while((locerr==0)&&(i<MAX_POLY_INDEXES))
    {
    writeEEVariable(POLY_TABLE_ADR+i, (BYTE)polyTable[i], SIZEBYTE, &locerr);
    i++;
    }
    if(i<MAX_POLY_INDEXES){ *error=1; return 0; }
    total=MAX_POLY*SIZEDOUBLE;
    n=0;
    adr=POLY_MEMORY_ADR;
    while((locerr==0)&&(n<total))
    {
    copyPtr(&datapacket.data[0], ptr, 16, WRITE_DIR);
    datapacket.cmd=CAR_DISPLAY_RW_EE;
    datapacket.len=SIZEDOUBLE;
    ptr+=datapacket.len;
    datapacket.dir=WRITE_DIR;
    datapacket.iarg=adr;
    adr+=datapacket.len;
    err=sendCommand(&datapacket, &nb, &locerr);
    if(locerr==0)n+=datapacket.len;
    }
    if(n<total)*error=1;
    else
    *error=0;
    return *error;
}

void sprintFormat(char* tostr, BYTE* currentvalue, int format, int size)
{
     
     DOUBLE value;
     
     if(currentvalue!=NULL)
     {

     value=getDouble(currentvalue, size);
     switch(format)
     {
      
      case FORMAT_X2:
         sprintf(tostr, "0x%2.2x",(DWORD)value);
	 break;
    
      case FORMAT_X4:
         sprintf(tostr, "0x%4.4x",(DWORD)value);
    	 break;

     case FORMAT_D:
	      sprintf(tostr, "%d",(DWORD)value);
     	      break;

        case FORMAT_F1:
             sprintf(tostr, "%-0.1f",(DOUBLE)value);
             break;

        case FORMAT_F2:
             sprintf(tostr, "%-0.2f", (DOUBLE)value);
             break;

        case FORMAT_F3:
             sprintf(tostr, "%-0.3f",(DOUBLE)value);
             break;

        case FORMAT_F6:
             sprintf(tostr, "%-0.6f",(DOUBLE)value);
             break;

        case FORMAT_B:
              if(value!=0)sprintf(tostr, "Enabled"); else sprintf(tostr, "Disabled");
              break;

        case FORMAT_S:
             sprintf(tostr, "%s", (char *)currentvalue);
             break;

        default:
             sprintf(tostr, "N/A");
             break;
     } 
    } else
    {
        sprintf(tostr, "N/A");
    }
    
}

void printFormat(BYTE* currentvalue, int format, int size)
{
        char ib[MAX_STRING_SIZE];
        sprintFormat(ib, currentvalue, format, size);
        printf("%s", ib);
}

void sprintFDecimal(char *tostr, DOUBLE value, int numdec)
{
     int i;
     
     *tostr='\0';
     if(numdec<0)numdec=0; else if(numdec>=6)numdec=6;
     
     if(numdec==0)sprintf(tostr, "%0.0f", value);
     else
     if(numdec==1)sprintf(tostr, "%0.1f", value);
     else
     if(numdec==2)sprintf(tostr, "%0.2f", value);
     else
     if(numdec==3)sprintf(tostr, "%0.3f", value);
     else
     if(numdec==4)sprintf(tostr, "%0.4f", value);
     else
     if(numdec==5)sprintf(tostr, "%0.5f", value);
     else
     sprintf(tostr, "%0.6f", value);
}

void getFormat(DOUBLE* changevalue, int format, char* linebuffer)
{
     DWORD x;
     DOUBLE fx;
     
     switch(format)
        {

                case FORMAT_X2:
                case FORMAT_X4:
                     sscanf(linebuffer, "%x", &x);
                     *changevalue=(DOUBLE)x;
                        break;

                case FORMAT_D:
                case FORMAT_B:
                     sscanf(linebuffer, "%d",&x);
                     *changevalue=(DOUBLE)x;
                        break;

                case FORMAT_F1:
                case FORMAT_F2:
                case FORMAT_F3:
                case FORMAT_F6:
                default:
                     sscanf(linebuffer, "%f",&fx);
                     *changevalue=(DOUBLE)fx;
                     break;

                case FORMAT_S:
                     sscanf(linebuffer, "%s", linebuffer);
                        break;
     }
}

int getInput(char *title, char* unit, int format, DOUBLE* currentvalue, DOUBLE* changevalue, DOUBLE (*function)(DOUBLE), DOUBLE (*inverseFunction)(DOUBLE), DOUBLE min, DOUBLE max, DOUBLE* array, INT nvalues)
{
       char linebuffer[MAX_STRING_SIZE];
       char ibuffer[2][MAX_STRING_SIZE];
       DOUBLE ftemp, etemp, mtemp;
       int i, j, rval;
       DOUBLE* atemp;
       char ctemp;       

       rval=0;
	   i=0;
       while(i==0)
       {
             if(format==FORMAT_B)
              {
                   ftemp=function((DOUBLE)*currentvalue);
                   sprintFormat(ibuffer[0], (BYTE*)&ftemp, format, SIZEDOUBLE);
                   sprintf(printBuffer, "%s is %s %s", title, ibuffer[0], unit);
                   doDotsQuestion(printBuffer, FIRST_TAB);
                   doDotsQuestion("Press (E)nable/(D)isable", GI2_TAB);
                   printf("(ENTER Skips)> ");         // length of this is 14
                   ctemp=mygetch(&globalcontrolcode);
                   printf("%c",ctemp);
                   if((ctemp=='E')||(ctemp=='e'))
                   {
                   *changevalue=inverseFunction(1);
                   i=1;
		           rval=1;
                   } else
                   if((ctemp=='D')||(ctemp=='d'))
                   {
                   *changevalue=inverseFunction(0);
                   i=1;
                   rval=1;
                   } else
                   {
                   *changevalue=*currentvalue;
                   i=1;
                   }
                   printf("\n");
              } else
              if(format==FORMAT_S)
              {
                                  
              } else
              {
              ftemp=function((DOUBLE)*currentvalue);
              sprintFormat(ibuffer[0], (BYTE*)&ftemp, format, SIZEDOUBLE);
              sprintf(printBuffer, "%s is Set to: %s %s", title, ibuffer[0], unit);
              doDotsQuestion(printBuffer, FIRST_TAB);
              ftemp=0.0;
              if(nvalues<=2)
               {
                 sprintFormat(ibuffer[0], (BYTE*)&min, format, SIZEDOUBLE);
                 sprintFormat(ibuffer[1], (BYTE*)&max, format, SIZEDOUBLE);
                 if(min<max)sprintf(printBuffer, "Set New Value (%6.6s - %-6.6s)", ibuffer[0], ibuffer[1]);
                 else if(nvalues==0)sprintf(printBuffer, "Set New Value");
                 else if(nvalues==1)sprintf(printBuffer, "Set New Value (> %-6.6s)", ibuffer[0]);
                 else sprintf(printBuffer, "Set New Value (< %-6.6s)", ibuffer[1]);
                 doDotsQuestion(printBuffer, GI2_TAB);
                 printf("(ENTER Skips)> ");  // length of this is 14
               } else
               {
                  if(nvalues>=8)nvalues=8;
                  i=0;
                  atemp=array;
                  ibuffer[0][0]='\0';
                  while(i<nvalues)
                  {
                    sprintFormat(ibuffer[1], (BYTE*)atemp, format, SIZEDOUBLE);
                    if(i<(nvalues-2))sprintf(ibuffer[0], "%s%s, ", ibuffer[0], ibuffer[1]);
                    else
                    if(i<(nvalues-1))sprintf(ibuffer[0], "%s%s or ", ibuffer[0], ibuffer[1]);
                    else
                    sprintf(ibuffer[0], "%s%s", ibuffer[0], ibuffer[1]);
                    atemp++;
                    i++;
                  }
                  
                  sprintf(printBuffer, "Set New Value, Either: %s", ibuffer[0]);
                  doDotsQuestion(printBuffer, GI2_TAB);
                  printf("(ENTER Skips)> "); // length of this is 14
               }
              gets(&linebuffer[0]);
              if(linebuffer[0]=='\0')
              {
              // Old value kept.
              ftemp=function(*currentvalue);
              *changevalue=inverseFunction((DOUBLE)ftemp);
              i=1;
              } else
              {
              getFormat(&ftemp, format, &linebuffer[0]);
              // New value is ftemp
              if(nvalues<=2)
              {
                 if(min<max){ }
                 else if(nvalues==0){ min=ftemp; max=ftemp; }
                 else if(nvalues==1){ max=ftemp; }
                 else { min=ftemp; }
                 
                 if((ftemp>=min)&&(ftemp<=max))
                {
                  *changevalue=inverseFunction((DOUBLE)ftemp);
                  i=1;
		          rval=1;
                } else
                {
                   // value out of range
                   printf("Value Out of Range. Try again.\n");
                }
              } else
              {
               i=1;
               j=0;
               atemp=array;
               mtemp=(*atemp)-ftemp;
               mtemp*=mtemp;              // mtemp is the minimum squared error!
               atemp++;
               while(i<nvalues)
               {
                etemp=(*atemp)-ftemp;
                etemp*=etemp;
                if(etemp<mtemp)
                {
                  mtemp=etemp;
                  j=i;
                }                
                atemp++;
                i++;    
               }
               atemp=array;
               atemp+=j;
               *changevalue=inverseFunction((DOUBLE)*atemp);
               i=1;
	           rval=1;
              }
              }
              }
          }
       return rval;
}

int getInputVar(SYSTEMVAR* inptr, DOUBLE* changevalue)
{
       char linebuffer[MAX_STRING_SIZE];
       char ibuffer[4][MAX_STRING_SIZE];
       DOUBLE ftemp, etemp, mtemp;
       int i, j, rval;
       DOUBLE* atemp;
       char ctemp;       
       DOUBLE* currentvalue;
       DOUBLE f;

       f=getDouble(inptr->ptr, autoSize(inptr));
       currentvalue=&f;
       /*
    	The return value is 0 if no change to settings are required
	    and non zero otherwise
	   */
       rval=0;
	   i=0;
       while(i==0)
       {
             ftemp=inptr->function((DOUBLE)*currentvalue);
             inptr->showFunction(inptr, ibuffer[0], FIRST_TAB);
             if(inptr->format==FORMAT_B)
              {
                   sprintf(ibuffer[1], "%-70.70s Press (E)nable/(D)isable", ibuffer[0]);
                   sdoDots(ibuffer[1], ibuffer[1], SECOND_TAB, ' ');
                   sprintf(ibuffer[0], "%s     (ENTER Skips)> ", ibuffer[1]);
                   printf("%s", ibuffer[0]);
                   ctemp=mygetch(&globalcontrolcode);
                   printf("%c",ctemp);
                   if((ctemp=='E')||(ctemp=='e'))
                   {
                   putDouble(inptr->ptr, 1, autoSize(inptr));
                   *changevalue=inptr->inverseFunction(1);
                   i=1;
		           rval=1;
                   } else
                   if((ctemp=='D')||(ctemp=='d'))
                   {
                   putDouble(inptr->ptr, 0, autoSize(inptr));
                   *changevalue=inptr->inverseFunction(0);
                   i=1;
                   rval=1;
                   } else
                   {
                   *changevalue=*currentvalue;
                   i=1;
                   }
                   printf("\n");
              } else
              if(inptr->format==FORMAT_S)
              {
                                  
              } else
              {
              ftemp=0.0;
              if(inptr->nvalues<=2)
               {
               sprintFormat(ibuffer[1],(BYTE*)&inptr->minValue, inptr->format, SIZEDOUBLE);
               sprintFormat(ibuffer[2],(BYTE*)&inptr->maxValue, inptr->format, SIZEDOUBLE);
               if((inptr->minValue)<(inptr->maxValue))
               {
                    if(inptr->nvalues==0)sprintf(ibuffer[3], "%-70.70s Set New Value (%4.4s to %-4.4s)", ibuffer[0], ibuffer[1], ibuffer[2]);
                    else sprintf(ibuffer[3], "%-70.70s Set Value (< %-5.5s, 0 = Off)", ibuffer[0], ibuffer[2]);
               }
               else if(inptr->nvalues==0)sprintf(ibuffer[3], "%-70.70s Set New Value", ibuffer[0]);
               else if(inptr->nvalues==1)sprintf(ibuffer[3], "%-70.70s Set New Value (> %-4.4s)", ibuffer[0], ibuffer[1]);
               else if(inptr->nvalues==2)sprintf(ibuffer[3], "%-70.70s Set New Value (< %-4.4s)", ibuffer[0], ibuffer[2]);
               sdoDots(ibuffer[3], ibuffer[3], SECOND_TAB,' ');
               sprintf(ibuffer[0], "%s (ENTER Skips)> ", ibuffer[3]);
               printf("%s", ibuffer[0]);
    
               } else
               {
                  if(inptr->nvalues>=8)inptr->nvalues=8;
                  i=0;
                  atemp=inptr->array;
                  ibuffer[0][0]='\0';
                  while(i<inptr->nvalues)
                  {
                    sprintFormat(ibuffer[1], (BYTE*)atemp, inptr->format, SIZEDOUBLE);
                    if(i<(inptr->nvalues-2))sprintf(ibuffer[0], "%s%s, ", ibuffer[0], ibuffer[1]);
                    else
                    if(i<(inptr->nvalues-1))sprintf(ibuffer[0], "%s%s or ", ibuffer[0], ibuffer[1]);
                    else
                    sprintf(ibuffer[0], "%s%s", ibuffer[0], ibuffer[1]);
                    atemp++;
                    i++;
                  }
                  
               sprintf(ibuffer[0], "Set New Value, Either: %s", ibuffer[0]);
               sdoDots(ibuffer[0], ibuffer[0], SECOND_TAB,' ');
               sprintf(ibuffer[0], "%s (ENTER Skips)> ", ibuffer[0]);
               printf("%s", ibuffer[0]);
               }
              gets(&linebuffer[0]);
              if(linebuffer[0]=='\0')
              {
              // Old value kept.
              ftemp=inptr->function(*currentvalue);
              *changevalue=inptr->inverseFunction((DOUBLE)ftemp);
              i=1;
              } else
              {
              getFormat(&ftemp, inptr->format, &linebuffer[0]);
              // New value is ftemp
              if((inptr->minValue)<(inptr->maxValue))
              {
                if((ftemp>=inptr->minValue)&&(ftemp<=inptr->maxValue))
                {
                  putDouble(inptr->ptr, ftemp, autoSize(inptr));
                  *changevalue=inptr->inverseFunction((DOUBLE)ftemp);
                  i=1;
		          rval=1;
                } else
                {
                   // value out of range
                   printf("Value Out of Range. Try again.\n");
                }
              } else
              {
               i=1;
               j=0;
               atemp=inptr->array;
               mtemp=(*atemp)-ftemp;
               mtemp*=mtemp;              // mtemp is the minimum squared error!
               atemp++;
               while(i<inptr->nvalues)
               {
                etemp=(*atemp)-ftemp;
                etemp*=etemp;
                if(etemp<mtemp)
                {
                  mtemp=etemp;
                  j=i;
                }                
                atemp++;
                i++;    
               }
               atemp=inptr->array;
               atemp+=j;
               putDouble(inptr->ptr, *atemp, autoSize(inptr));
               *changevalue=inptr->inverseFunction((DOUBLE)*atemp);
               i=1;
	           rval=1;
              }
              }
              }
          }
       return rval;
}

DOUBLE idF(DOUBLE x)
{
       return x;
}

DOUBLE idSetFVarName(char *name, DOUBLE value, BYTE* mptr, INT eeAdr, DWORD* totalerror)
{
    // generic write routine Name
    DWORD pA;
    DWORD error;
    
    error=0;
    pA=(DWORD)value;
    if(eeAdr==0)
    {
    printf("EE Address Error.\n");
    *totalerror=1;
    } else
    if(autoSizeName(name)>=MAXEEVARSIZE)
    {
    printf("Write Variable %s Size Error: %d.\n", name, autoSizeName(name));
    *totalerror=1;
    } else
    {
    writeEEAndRamVariableAutoSize(name, pA, mptr, eeAdr, &error);
    *totalerror=error;
    }
	return 0;
}

DOUBLE idSetF(SYSTEMVAR* inptr, DWORD* totalerror)
{
    // this is the default set function for simple non dependent variables
    DWORD error;
    idSetFVarName(inptr->name, inptr->inputValue, inptr->ptr, inptr->eeAdr, &error);
    *totalerror=error;
    return 0;
}

DOUBLE setBattRef(SYSTEMVAR* inptr, DWORD* totalerror)
{
    DWORD error;
    idSetFVarName("battScaling", inptr->inputValue, inptr->ptr, BATTSCALINGL_ADR, &error);
    *totalerror=error;
    return 0;  
}

DOUBLE setBattMax(SYSTEMVAR* inptr, DWORD* totalerror)
{
    DWORD error;
    idSetFVarName("battMax", inptr->inputValue, inptr->ptr, BATTMAX_ADR, &error);
    *totalerror=error;
    return 0;
}

DOUBLE setBattMin(SYSTEMVAR* inptr, DWORD* totalerror)
{
    DWORD error;
    idSetFVarName("battMin", inptr->inputValue, inptr->ptr, BATTMIN_ADR, &error);
    *totalerror=error;
    return 0;
}

DOUBLE idShowF(SYSTEMVAR* inptr, char* tostr, int tabwidth)
{
       // this is the default show function
       char ibuffer[2][MAX_STRING_SIZE];
       DOUBLE f;
       SYMBOL* psym;

       if(inptr->title[0]!='\0')       
       sprintf(ibuffer[0], "%s", inptr->title);
       else
       sprintf(ibuffer[0], "%s", inptr->name);
       sdoDots(ibuffer[0], ibuffer[0], tabwidth,'.');
       sprintFormat(ibuffer[1], (BYTE*)inptr->ptr, inptr->format, autoSize(inptr));
       sprintf(tostr, "%s: %s %s", ibuffer[0], ibuffer[1], inptr->unit);
        return 0;
}

DOUBLE showQueueObjF(SYSTEMVAR* inptr, char* tostr, int tabwidth)
{
       int i;
       char ibuffer[2][MAX_STRING_SIZE];
       BYTE* ptr;
       
       if(inptr->title[0]!='\0')       
       sprintf(ibuffer[0], "%s", inptr->title);
       else
       sprintf(ibuffer[0], "%s", inptr->name);
       sdoDots(ibuffer[0], ibuffer[0], tabwidth,'.');
       ibuffer[1][0]='\0';
       ptr=inptr->ptr;
       for(i=0; i<autoSizeName(inptr->name); i++)
       {
       sprintf(ibuffer[1], "%s0x%2.2x.", ibuffer[1], *ptr++);         
       }
       sprintf(tostr, "%s: %s %s", ibuffer[0], ibuffer[1], inptr->unit);
       return 0;
}

void getChannelString(char *tostr, int varn)
{

    BYTE vartype;

    vartype=variable[varn].type & 3;
    if(varn<NUM_VARS)
    {
        if(vartype==ANALOG_VAR)
        sprintf(tostr, "AN%d", variable[varn].index & 3);
        else
        if(vartype==FREQUENCY_VAR)
        sprintf(tostr, "FQ%d", variable[varn].index & 1);
        else
        sprintf(tostr, "N/A");

    } else
    {
        sprintf(tostr, "N/A");

    }
}

void getVarTypeString(char* tostr, int varn)
{
     char buffer[MAX_STRING_SIZE];
     int i;
     BYTE vartype;
     //
     vartype=(variable[varn].type & 3);
     //
     if(varn<NUM_VARS)
     {
     if(vartype==ANALOG_VAR)
     {
     sprintf(tostr, "Variable #%d Monitoring Voltage/Resistance Channel AN%d (Pin %d of CON3)", varn, (variable[varn].index & 3), 5-(variable[varn].index & 3));
     } else
     if(vartype==FREQUENCY_VAR)
     { 
     sprintf(tostr, "Variable #%d Monitoring Frequency/Duty Cycle Channel FQ%d (Pin %d of CON2)", varn, (variable[varn].index & 1), 2+(variable[varn].index & 1));
     } else
     if(vartype==DEPENDENT_VAR)
     {
     i=variable[varn].index & 7;
     if(i!=varn)
     {
            getVarTypeString(buffer, i);
            sprintf(tostr, "Variable #%d Dependent On: %s", varn, buffer);
        } else
        {
         sprintf(tostr, "Variable #%d Circularly Dependent", varn);
        }          
     } else
     {
     sprintf(tostr, "Variable #%d Silent Variable", varn);
     }
    } else
    if((varn==VAR_BATT)||(VAR_LDR))
    {
  	varn-=NUM_VARS;
	if((systemName>=0)&&(systemName<stringsSize))
                                                 {
                                                 sprintString(tostr, systemName+addressStringFlash, (varn<<1), STRING_DELIMITER, MAX_STRING_SIZE);
                                                 } else
                                                 {
                                                 copyString(tostr, getStringSubIndexGeneral(&systemString[0], (varn<<1), STRING_DELIMITER), STRING_DELIMITER, MAX_STRING_SIZE);
                                                 }
    } else
    {
     sprintf(tostr, "Unknown Variable");   
    }
}


void showVariables(void)
{
    int i;
    char buffer[MAX_STRING_SIZE];
    printf("Current Variables:\n");
    for(i=0; i<NUM_UPDATE_VARS; i++)
    {
    getVarTypeString(buffer, i);
    printf("(*) %s\n", buffer);
    }
}

void getTypeString(char *tostr, int i)
{
    int type;

    type=i & 3;

    switch(type)
    {
        default:
        case ANALOG_VAR:
            sprintf(tostr, "Voltage/Resistance Sensor");
            break;

        case FREQUENCY_VAR:
            sprintf(tostr, "Frequency/Duty Cycle Sensor");
            break;

        case DEPENDENT_VAR:
            sprintf(tostr, "Dependent");
            break;        
        case SILENT_VAR:   
            sprintf(tostr, "Silent");
            break;
    }
}

int chooseTypeOfVariable(int num)
{
    int i, j;
    char c;
    char buffer[MAX_STRING_SIZE];
    
    j=0;
    for(i=0; i<4; i++)
    {
    j++;
    getTypeString(buffer, i);
    printf("(%c) %s\n", j+0x60, buffer);
    }
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<=(j+0x60)))
    return (c-0x61);
    else
    return -1;
}

int chooseVariable(int num)
{
    int i, j;
    char c;
    char buffer[MAX_STRING_SIZE];
    //
    printf("\nChoose the Variable:\n");
    j=0;
    for(i=0; i<num; i++)
    {
    j++;
    getVarTypeString(buffer, i);
    printf("(%c) %s\n", j+0x60, buffer);
    }
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<=(j+0x60)))
    return (c-0x61);
    else
    return -1;
}

DOUBLE idActionF(int x, int xx, int xxx)
{
       printf("Doing Action %d, %d, %d\n", x, xx, xxx);
       return x;
}

int getNameAndUnit(char* name, char* unit, int varn, int index, int maxsize)
{
    sprintStringVar(name, &variable[varn], varn, index, VALUE_INDEX, STRING_DELIMITER, maxsize);
    sprintStringVar(unit, &variable[varn], varn, index, UNIT_INDEX, STRING_DELIMITER, maxsize);    
    return 0;
}

void getValueIndexString(char *tostr, int varn, int valueindex)
{
    char valueindexString[MAX_STRING_SIZE];
    int i;
    BYTE vartype;
    char buffer[MAX_STRING_SIZE];
    //
    sprintf(tostr, "N/A");
    vartype=variable[varn].type & 3;
    //
    if(varn<NUM_VARS)
    {
     if(vartype==ANALOG_VAR)
     {
        if(valueindex==0)
        {
        sprintf(tostr, "Voltage");
        } else
        if(valueindex==1)
        {
        sprintf(tostr, "Resistance");
        } else
        if(valueindex==2)
        {
        sprintf(tostr, "Delta");
        } else
        if(valueindex==3)
        {
        sprintf(tostr, "Integral");
        }
     } else
     if(vartype==FREQUENCY_VAR)
     { 
        if(valueindex==0)
        {
        sprintf(tostr, "Frequency");
        } else
        if(valueindex==1)
        {
        sprintf(tostr, "Duty");
        } else
        if(valueindex==2)
        {
        sprintf(tostr, "Delta");
        } else
        if(valueindex==3)
        {
        sprintf(tostr, "Integral");
        }
     } else
     if(vartype==DEPENDENT_VAR)
     {
      i=variable[varn].index & 7;
      if(i!=varn)
      {
         //
         if(valueindex<NUM_RAW)
            {
             if(valueindex==0)
             {
                sprintStringVar(buffer, &variable[i], i, (variable[varn].type>>4)&3, 0, STRING_DELIMITER, STRING_TAB);
             } else
             {
                sprintStringVar(buffer, &variable[i], i, (variable[varn].type>>6)&3, 0, STRING_DELIMITER, STRING_TAB);
             }
             sprintf(tostr, "Depends On %-20.20s", buffer);
            }
         else
         if(valueindex==2)sprintf(tostr, "Delta (Dependent)");
         else
         if(valueindex==3)sprintf(tostr, "Integral (Dependent)");
         //
      } else
      {
      
         sprintf(tostr, "Circularly Dependent");
      }          
     } else
     if(vartype==SILENT_VAR)
     { 
        sprintf(tostr, "Message String #%d", valueindex);
     }
    } else
    {
        if(varn==VAR_BATT)
        sprintf(tostr, "Battery Level");
        else
        if(varn==VAR_LDR)
        sprintf(tostr, "Light Level");
    }
}

void getOrderString(char* tostr, int order)
{
    
    sprintf(tostr, "%d", order);
    if(order==0)
    {
        sprintf(tostr, "N/A ");        
    } else
    if(order==1)
    { 
        sprintf(tostr, "%sst ", tostr);
    } else
    if(order==2)
    { 
        sprintf(tostr, "%snd ", tostr);
    } else
    if(order==3)
    { 
        sprintf(tostr, "%srd ", tostr);
    } else
    { 
        if(order<10)sprintf(tostr, "%sth ", tostr);
        else sprintf(tostr, "%sth", tostr);
    }
}

int insertChar(char *tostr, int cursor, char c, int maxsize)
{
    int ptr;
    ptr=cursor+1;
    while((ptr<(maxsize-1))&&(*(tostr+ptr)!=0))ptr++;    // go to the end of the string!
     // now shift everything one!
    while(ptr>=cursor)
    {
    *(tostr+ptr+1)=*(tostr+ptr);
    ptr--;   
    }
    *(tostr+cursor)=c; cursor++;
    return cursor;
}

int deleteChar(char *tostr, int cursor)
{
     // delete a character!
     int ptr;
     
     ptr=cursor;
     while(*(tostr+ptr)!=0)
     {
     *(tostr+ptr)=*(tostr+ptr+1);       
     ptr++;   
     }
     *(tostr+ptr-1)=0;
     return cursor;
}

int enterString(char *tostr, char* question, int maxsize, int delimiter, char* endchar)
{
    int cursor, ptr;
    char c, d;
    int controlcode;
  /*
    c=1;
    while(c!=0x1b)
    {
        c=mygetch(&controlcode);
        printf("%4.4x: %4.4x \n", c, controlcode);
    }
  */
  
    cursor=stringLength(tostr)-1;
    c=1;
    while(1)
    {
    if(cursor<0)cursor=0; else if(cursor>(maxsize-1))cursor=maxsize-1;
    while(!kbhit())
    {    
    c=*(tostr+cursor);
    *(tostr+cursor)='_';
    if(c==0)*(tostr+cursor+1)=0;
    printf("%s %s  \r", question, tostr);   
    DelayMs(12);
    *(tostr+cursor)=c;
    printf("%s %s  \r", question, tostr);
    DelayMs(12);
    }
    c=mygetch(&controlcode);
    if(c==0x0D)break;
    else
    if(c=='\r')break;
    else
    if(c==0x1B)break;
    else
    if((controlcode==1)&&(c==0x4d))
            {
                // right arrow
                d=*(tostr+cursor);
                if(d!=0)cursor++; 
            }
    else
    if((controlcode==1)&&(c==0x4b))
        {
            // left arrow
            cursor--;
        }
    else
    if((controlcode==1)&&(c==0x47))
    {
        // HOME key
     cursor=0;   
    } else
    if((controlcode==1)&&(c==0x53))
    {
        // delete key
        d=*(tostr+cursor);
        if(d!=0){
        cursor=deleteChar(tostr, cursor);
        }
    } else
    if((controlcode==0)&&(c>=BIG_FONT_MIN)&&(c<=BIG_FONT_MAX)&&(c!=delimiter))
                    { 
                        d=(*(tostr+cursor));
                        if((d==0)&&(cursor<(maxsize-2))){ *(tostr+cursor)=c; cursor++; *(tostr+cursor)=0;  } else
                            { 
                            // insert a new character!
                            if(stringLength(tostr)<maxsize)cursor=insertChar(tostr, cursor, c, maxsize);
                            }
                        }
    else
    if(c=='\b')
        { 
            d=*(tostr+cursor); 
            cursor--;
            if(d==0)*(tostr+cursor)=0; else
            {
            cursor=deleteChar(tostr, cursor);
            }
        }
    }
    if(c!=0x1B)printf("%s %s %s", question, tostr, endchar);
    else
    printf("%s %s", question, tostr);
    return c;
}

int chooseMenu(MENU* mnptr)
{
   int i, j;
   int c;
   MENU* menuptr;
   
   menuptr=mnptr;
   j=0x60;
   while(menuptr->question[0]!='\0')
   {
       j++;
       printf("(%c) %s\n", (char)j, &menuptr->question[0]);                         
       menuptr++;
   }
   printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
   c=(int)mygetch(&globalcontrolcode);
   printf("%c\n", c);
   if((c>='a')&&(c<=j))return c-'a';
   else
   return -1;
}

void hideDisplayObject(int objnum)
{
    // internal operation on data structure...
    int i, n;
    
    // n is the size of the queue in the firmware
    n=autoSizeName("displayObj");
    // now shift!
    i=objnum;
    while((i+1)<n)
    {
    displayObj[i]=displayObj[i+1];
    i++;
    }
    displayObj[i]=0;
}

int firstFreeDisplayObject(void)
{
    // return the index of the first free object
    int i, n;
    // n is the size of the queue in the firmware
    n=autoSizeName("displayObj");
    // now scan...
    i=1;
    while(i<n)
    {
    if((displayObj[i] & 0x80)==0)break;
    else i++;
    }
    return i;
}

int addDisplayObject(int objnum, int value)
{
    // internal operation on data structure...
    // returns 0 if added ok or non zero if error (eg. out of memory)
    int n, end;
    // n is the size of the queue in the firmware
    n=autoSizeName("displayObj");
    end=firstFreeDisplayObject();
    if(end<n)
    {
        // now shift to make room
        while(end>objnum)
        {
         displayObj[end]=displayObj[end-1];
         end--;
        }
        displayObj[objnum]= 0x80 | (value);
        return 0;
    } 
    return -1;
}

int addDisplayObjectAtEnd(int value)
{
    // internal operation on data structure...
    // adds to the end of the display queue...
    // returns 0 if ok or other value if error (eg. out of memory)
    int n, end;
    n=autoSizeName("displayObj");
    end=firstFreeDisplayObject();
    if(end<n)
    {
        displayObj[end]=0x80 | (value);
        return 0;
    } 
    return -1;
}

void hideAllMarked(void)
{
    int i, n;
    n=autoSizeName("displayObj");
    i=1;
    while(i<n)
    {
    if((displayObj[i] & 0x80)==0)hideDisplayObject(i);
    i++;
    }   
}

void getOutputName(char *tostr, int i)
{
    sprintf(tostr, "%s", outputStrings[i & 1]);
}

int getOutputStateMask(int i)
{
    if(i==1)return OUTPUT2;
    else
    return OUTPUT1;
}

void getOutputState(char *tostr, int i)
{
    DWORD localerror;
    BYTE portstate;
    
    sprintf(tostr, "OFF");
    portstate=readRamVariableAutoSize("PORTE", 0, &portstate, &localerror);
    if(localerror==0)
    {
        if((portstate & (getOutputStateMask(i)))!=0)sprintf(tostr, "ON");
    }
}

void getOutputString(char *tostr, int outputvalue)
{
    int mode, varn, maxminmode, valueindex;
    //
    mode=(outputvalue>>6) & 3;
    varn=(outputvalue & 7);
    maxminmode=(outputvalue>>3)&1;
    valueindex=(outputvalue>>4)& 3;
    switch(mode)
    {
        default:
        case 0:
        sprintf(tostr, "Disabled");
        break;
        
        case 1:
        sprintf(tostr, "Buzzer Mode (Static Display Mode Only)");
        break;
        
        case 2:
        sprintf(tostr, "Relay Mode");
        break;
        
        case 3:
        sprintf(tostr, "Relay Mode (Inverted)");
        break;
    }
}

void getOutputFunctionString(char *tostr, int outputvalue)
{
    int mode, varn, minmode, valueindex;
    char buffer[4][MAX_STRING_SIZE];
    DOUBLE max, min;
    int decp;
    //
    mode=(outputvalue>>6) & 3;
    varn=(outputvalue & 7);
    minmode=(outputvalue>>3)&1;
    valueindex=(outputvalue>>4)& 3;
    (void)getNameAndUnit(buffer[0], buffer[1], varn, valueindex, NAME_TRUNCATION_OUTPUTS);
    if(varn>=NUM_VARS)
    {
    if(varn==VAR_BATT)
    {
    min=(DOUBLE)battMin*BATTSCALE;
    max=(DOUBLE)battMax*BATTSCALE;
    }
    decp=systemDecp;                    
    } else
    {
    min=(DOUBLE)variable[varn].min[valueindex];
    max=(DOUBLE)variable[varn].max[valueindex];
    if(valueindex<NUM_RAW)decp=variable[varn].decp[valueindex]; else decp=systemDecp;
    }
    sprintFDecimal(buffer[2], min, decp);
    sprintFDecimal(buffer[3], max, decp);
    //
    switch(mode)
    {
        default:
        case 0:
        sprintf(tostr, "Output is Always OFF");
        break;
        
        case 1:
        sprintf(tostr, "One Beep When %s Rises Above %s %s, Two Beeps When %s Drops Below %s %s", buffer[0], buffer[3], buffer[1], buffer[0], buffer[2], buffer[1]);
        break;
        
        case 2:
        if(minmode==0)
        {
            // max mode
            sprintf(tostr, "Relay Switches ON When %s Rises Above %s %s", buffer[0], buffer[3], buffer[1]);
        } else
        {
            // min mode
            sprintf(tostr, "Relay Switches ON When %s Drops Below %s %s", buffer[0], buffer[2], buffer[1]);
        }
        break;
        
        case 3:
        if(minmode==0)
        {
            // max mode
            sprintf(tostr, "Relay Switches OFF When %s Rises Above %s %s", buffer[0], buffer[3], buffer[1]);
        } else
        {
            // min mode
            sprintf(tostr, "Relay Switches OFF When %s Drops Below %s %s", buffer[0], buffer[2], buffer[1]);
        }
        break;
    }
}

int showOutputs(int selected)
{
    int i, n, j;
    char buffer[4][MAX_STRING_SIZE];
    
    n=autoSizeName("output");
    i=0;
    j=0x60;
    while(i<n)
    {
    (void)getOutputName(buffer[0], i);
    (void)getOutputState(buffer[1], i);
    (void)getOutputString(buffer[2], output[i]);
    (void)getOutputFunctionString(buffer[3], output[i]);
    j++;
    printf("(%c) %s Current State: %-16.16s Mode: %s\n    Function: %s\n", j, buffer[0], buffer[1], buffer[2], buffer[3]);
    i++;   
    }
    return 0;
}

int showDisplayObjects(int selected, int mode)
{
     int i, j;
     int n;
     char ibuffer[5][MAX_STRING_SIZE];
     int varn;
     int index, decp;
     DOUBLE f;
     
     hideAllMarked();
     n=autoSizeName("displayObj");
     if((n>0)&&(n<MAX_NUM_DISPLAY_OBJECTS))
     {     i=0;
           j=0x60;
           while(i<n)
           {
                     varn=(displayObj[i] & 0x0F);
                     index=(displayObj[i]>>4) & 0x03;
                     if((i==0)||((displayObj[i] & 0x80)!=0))
                     {
                     sprintStringVar(ibuffer[0], &variable[varn], varn, index, VALUE_INDEX, STRING_DELIMITER, NAME_TRUNCATION);
                     sprintStringVar(ibuffer[1], &variable[varn], varn, index, UNIT_INDEX, STRING_DELIMITER, NAME_TRUNCATION);
                     if(varn>=NUM_VARS)
                     {
                     if(varn==VAR_BATT)
                     f=(DOUBLE)battVoltage;
                     else
                     if(varn==VAR_LDR)
                     f=(DOUBLE)ldrPercent;
                     else
                     f=90.0;          
                     decp=systemDecp;                    
                     } else
                     {
                      if((displayObj[i] & 0x40)==0)
                      {
                      f=(DOUBLE)variable[varn].value[index];
                      } else
                      {
                      f=(DOUBLE)variable[varn].acc;  
                      index=(variable[varn].index>>4) & 3;
                      sprintStringVar(printBuffer, &variable[varn], varn, index, VALUE_INDEX, STRING_DELIMITER, NAME_TRUNCATION);
                      sprintStringVar(ibuffer[1], &variable[varn], varn, index, UNIT_INDEX, STRING_DELIMITER, NAME_TRUNCATION);
                      sprintf(ibuffer[0], "Acc(%s)", printBuffer);
                      }
                      if(index<NUM_RAW)decp=variable[varn].decp[index]; else decp=systemDecp;
                     }
                     sdoDots(ibuffer[0],ibuffer[0], VALUE_TAB, '.');
                     j++;
                     sprintFDecimal(ibuffer[2], f, decp);
                     sprintf(ibuffer[4], "%s %s", ibuffer[2], ibuffer[1]);
                     getOrderString(ibuffer[1], j-0x60);
                     if(selected<=0)
                        {
                        if(mode==0)sprintf(printBuffer, "(%c) %4.4s %s: %s\n", j, ibuffer[1], ibuffer[0], ibuffer[4]);
                        else sprintf(printBuffer, "%-4.4s %-32.32s: %s\n", ibuffer[1], ibuffer[0], ibuffer[4]);
                        }
                     else
                     {
                      if(selected==(int)(j-0x60))
                      sprintf(printBuffer, "(*) %4.4s %s: %s\n", ibuffer[1], ibuffer[0], ibuffer[4]);
                      else
                      sprintf(printBuffer, "( ) %4.4s %s: %s\n", ibuffer[1], ibuffer[0], ibuffer[4]);
                     }
                     printf("%s", printBuffer);
                     }
                     i++;
                   }
           }         
           return j;
}

int changeOrderDisplayObject(int objn)
{
    int i, n, value, xvalue, exit;
    char ctemp;
    int objnum, redraw;
    
    objnum=objn;
    redraw=1;
    exit=0;
    while(exit==0)
    { 
    if(redraw==1)
    { printf("\nChanging the Order of a Display Object. The Following are Currently Displayed Readings (In Order):\n");
      i=showDisplayObjects(objnum+1, 0);
      redraw=0;
    }
    value=displayObj[objnum];
    printf("Press Arrow Keys To Move the Object Up and Down. Press Enter to Exit> ");
    ctemp=mygetch(&globalcontrolcode);
    printf("%c\r", ctemp);
    if(ctemp==0x0D)exit=1;
    else
    if((globalcontrolcode==1)&&(ctemp==0x48))
    {
       // move up
       if(objnum>0)
       {
        objnum--;
        xvalue=displayObj[objnum];
        displayObj[objnum]=0x80 | value;
        displayObj[objnum+1]=0x80 | xvalue;        
        redraw=1;
        printf("\n");
       }
    } else
    if((globalcontrolcode==1)&&(ctemp=0x50))
    { 
       // move down
       n=autoSizeName("displayObj");
       if(((objnum+1)<n)&&((displayObj[objnum+1] & 0x80)!=0))
       {
          objnum++;
          xvalue=displayObj[objnum];
          displayObj[objnum]=0x80 | value;
          displayObj[objnum-1]=0x80 | xvalue;
          redraw=1;
          printf("\n");
       }
     }
    }
    return 0;
}

int printDisplayObject(char c, int varn, int index)
{
    char buffer[4][MAX_STRING_SIZE];
    //
    if(varn<NUM_VARS)
    {
    (void)getNameAndUnit(buffer[0], buffer[1], varn, index, NAME_TRUNCATION);
    getOrderString(buffer[2], variable[varn].displayed[index]);
    getValueIndexString(buffer[3], varn, index);
    sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-16.16s \n    Measures: %-32.32s Display Order: %s", c, buffer[0], buffer[1], buffer[3], buffer[2]);
    printf("%s\n", printBuffer);
    }
    else
    {
    (void)getNameAndUnit(buffer[0], buffer[1], varn, 0, NAME_TRUNCATION);
    getOrderString(buffer[2], variable[varn].displayed[0]);
    getValueIndexString(buffer[3], varn, 0);
    sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-16.16s \n    Measures: %-32.32s Display Order: %s", c, buffer[0], buffer[1], buffer[3], buffer[2]);
    printf("%s\n", printBuffer);
    }
}

int printLogObject(char c, int varn, int index)
{
    char buffer[4][MAX_STRING_SIZE];
    int logmask;
    //
    if(varn<NUM_VARS)
    {
    (void)getNameAndUnit(buffer[0], buffer[1], varn, index, NAME_TRUNCATION);
    logmask=(variable[varn].mode & MODE_LOGMASK)>>4;
    if((logmask & (1<<index))==0) 
    {
        sprintf(buffer[2], "Not Currently Logged");
    } else
    {
        if(((variable[varn].mode & MODE_LOGACC)==0)&&((variable[varn].mode & MODE_LOGMINMAX)==0))
        {
        sprintf(buffer[2], "Value Only Logged");
        } else
        if(((variable[varn].mode & MODE_LOGACC)!=0)&&((variable[varn].mode & MODE_LOGMINMAX)==0))
        {
        sprintf(buffer[2], "Value & Acc. Logged");
        } else
        if(((variable[varn].mode & MODE_LOGACC)==0)&&((variable[varn].mode & MODE_LOGMINMAX)!=0))
        {
        sprintf(buffer[2], "Value & Min-Max Logged");
        } else
        {
        sprintf(buffer[2], "Value, Min-Max & Acc. Logged");
        }
    }
    getValueIndexString(buffer[3], varn, index);
    sprintf(printBuffer, "(%c) Name: %-60.60s \n    Measures: %-32.32s Log Status: %-20.20s ", c, buffer[0], buffer[3], buffer[2]);
    printf("%s\n", printBuffer);
    }
    else
    {
    (void)getNameAndUnit(buffer[0], buffer[1], varn, 0, NAME_TRUNCATION);
    sprintf(buffer[2], "Value Only Logged           ");
    getValueIndexString(buffer[3], varn, 0);
    sprintf(printBuffer, "(%c) Name: %-32.32s \n    Measures: %-32.32s Log Status: %-20.20s ", c, buffer[0], buffer[3], buffer[2]);
    printf("%s\n", printBuffer);
    }
}

int chooseLogObject(int varn)
{
       // returns the log object code >=0!
       // or -1 if aborted...
       int i, j, totalindex, value;
       int c;
       //
       if(varn<NUM_VARS)
       {
       printf("\nChoose the Measurement To Toggle Logging On:\n");
       j=0x60;
       for(i=0; i<NUM_VALUES; i++)
       {
       j++;
       printLogObject(j, varn, i);
       }
       j++;
       printf("(%c) None\n", j);
       printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
       c=mygetch(&globalcontrolcode);
       printf("%c\n", c);
       if((c>='a')&&(c<=j))
       {
         value= c-'a';
         return value;
       } else return -1;
       }
    return -1;
}

int chooseDisplayObject(void)
{
       // returns the display object code >=0!
       // or -1 if aborted...
       int i, j, varn, totalindex, value;
       int c;
       //
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))
       {
          if(varn<NUM_VARS)
          {
          printf("\nChoose the Measurement:\n");
          j=0x60;
          for(i=0; i<NUM_VALUES; i++)
          {
          j++;
          printDisplayObject(j, varn, i);
          }
          printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
          c=mygetch(&globalcontrolcode);
          printf("%c\n", c);
             if((c>='a')&&(c<=j))
             {
                   totalindex=c-'a';
                   value= ((totalindex << 4) & 0x30) + (varn & 0x0F);
                   return value;
             } else return -1;
            } else
            {
            return (0x0F & varn);
            }
        }
        return -1;
}

int chooseDisplayObjectFull(void)
{
       // includes accumulator selection
       // returns the display object code >=0!
       // or -1 if aborted...
       int i, j, varn, totalindex, value;
       int c, x;
        
       //
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))
       {
            if(varn<NUM_VARS)
            {
             printf("\nChoose the Measurement:\n");
             j=0x60;
             for(i=0; i<NUM_VALUES; i++)
             {
             j++;
             printDisplayObject(j, varn, i);
             }
             j++;
             printf("(%c) Accumulator\n", j);
             printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
             c=mygetch(&globalcontrolcode);
             printf("%c\n", c);
             if((c>='a')&&(c<=j))
             {
                   totalindex=c-'a';
                   if(totalindex<NUM_VALUES)
                   {
                   value= ((totalindex << 4) & 0x30) + (varn & 0x0F);
                   return value;
                   } else
                   {
                   printf("\n");       
                   printf("The Accumulator Currently Adds the Measurement:\n");
                   printDisplayObject('+', varn, ((variable[varn].index >> 4) & 3));
                   printf("\n");
                   printf("Change the Variable's Type & Acquisition Parameters    \n");
                   printf("to Change the Value that is Applied to the Accumulator.\n");
                   printf("eg: use -v Option to Access the Variable Menu. \n");
                   value=0x40 + (varn & 0x0F);
                   return value;
                   }

             } else return -1;
            } else
            {
            return (0x0F & varn);
            }
        }
        return -1;
}

int chooseDeltaChannel(int varn)
{
       // or -1 if aborted...
       int i, j, totalindex, value;
       int c, currentdeltachannel;
       //
       if((varn>=0)&&(varn<NUM_VARS))
       {
            if(varn<NUM_VARS)
            {
             currentdeltachannel=(variable[varn].index >> 7 ) & 1;
             printf("Delta/Integral Values Currently Apply To the Measurement:\n");
             printDisplayObject('*', varn, currentdeltachannel);
             printf("\nChoose the New Measurement on Which the Delta/Integral is to Apply:\n");
             j=0x60;
             for(i=0; i<NUM_RAW; i++)
             {
             j++;
             printDisplayObject(j, varn, i);
             }
             printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
             c=mygetch(&globalcontrolcode);
             printf("%c\n", c);
             if((c>='a')&&(c<=j))
             {
                   totalindex=c-'a';
                   return totalindex;
             } else return -1;
            } else
            {
            return (0x0F & varn);
            }
        }
        return -1;
}

int chooseAccChannel(int varn)
{
        // or -1 if aborted...
       int i, j, totalindex, value;
       int c, currentaccchannel;
       //
       if((varn>=0)&&(varn<NUM_VARS))
       {
            if(varn<NUM_VARS)
            {
             currentaccchannel=(variable[varn].index >> 4) & 3;
             printf("The Accumulator Currently Adds the Measurement:\n");
             printDisplayObject('*', varn, currentaccchannel);
             printf("\nChoose the New Measurement to Accumulate On:\n");
             j=0x60;
             for(i=0; i<NUM_VALUES; i++)
             {
             j++;
             printDisplayObject(j, varn, i);
             }
             printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
             c=mygetch(&globalcontrolcode);
             printf("%c\n", c);
             if((c>='a')&&(c<=j))
             {
                   totalindex=c-'a';
                   return totalindex;
             } else return -1;
            } else
            {
            return (0x0F & varn);
            }
        }    
        return -1;
}

DOUBLE hideDisplayObj(int objnum, int index, int subindex)
{
    int i;
    char ctemp;
    
    printf("\nHiding Display Object. The Following are Currently Displayed Readings (In Order):\n");
    i=showDisplayObjects(0, 0);
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", i);
    ctemp=mygetch(&globalcontrolcode);
    printf("%c\n", ctemp);
    if((ctemp>='a')&&(ctemp<=(i)))
    {
    objnum=ctemp - 'a';
    if(objnum!=0)
    {
    hideDisplayObject(objnum);
    displayObject=0;
    finalSystemWrite++;
    //printf("\nDisplay Object Hidden. The Following are Currently Displayed Variables (In Order):\n");
    //(void)showDisplayObjects(0, 1);
    printf("\nDisplay Object Hidden.\n");
    return 0;
    } else { printf("The First Display Object Cannot Be Hidden.\n"); return 0; }
    } else return -1;
    return 0;
}

DOUBLE clearDisplayObj(int objnum, int index, int subindex)
{
    int i, n;
    char ctemp;
    
    printf("\nClearing Display Objects. The Following are Currently Displayed Readings (In Order):\n");
    i=showDisplayObjects(0, 0);
    printf("Do You Wish to Clear the Display Object Queue. Press (Y)es/(N)o. (Any Other Key to Cancel)> ");
    ctemp=mygetch(&globalcontrolcode);
    printf("%c\n", ctemp);
    if((ctemp=='y')||(ctemp=='Y'))
    {
    i=1;
    n=autoSizeName("displayObj");
    while(i<n)
    {
    displayObj[i]=0;
    i++;
    }
    displayObject=0;
    finalSystemWrite++;
    printf("Display Objects Cleared.\n");
    return 0;
    } 
    return 0;
}

DOUBLE changeOrderDisplayObj(int objnum, int index, int subindex)
{
    int i;
    char ctemp;
    printf("\nChanging the Order of a Display Object. The Following are Currently Displayed Readings (In Order):\n");
    i=showDisplayObjects(0, 0);
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", i);
    ctemp=mygetch(&globalcontrolcode);
    printf("%c\n", ctemp);
    if((ctemp>='a')&&(ctemp<=(i)))
    {
    objnum=ctemp - 'a';
    changeOrderDisplayObject(objnum);
    displayObject=0;
    finalSystemWrite++;
    return 0;
    } else return -1;
    return 0;
}

DOUBLE addDisplayObj(int objnum, int index, int subindex)
{
    int i, res;
    // add a display object
    printf("\nAdding a Display Object.\n");
    i=chooseDisplayObjectFull();
    if(i>=0)
    {
            res=addDisplayObjectAtEnd(i);
            if(res==0)
            {
              displayObject=0;
              finalSystemWrite++;  
              printf("Display Object Added.\n");
              return 0;
            } else
            {
              printf("Cannot Add Display Object (Out of Memory Error). Try Hiding a Display Object First.\n");
              return 0;
            }
    } else 
    { 
        //printf("Action Cancelled.\n"); 
        return -1; 
    }
    return 0;
}

DOUBLE exitSave(int objnum, int index, int subindex)
{
    return 1;
}

MENU displayObjMenu[]={  
    {"Add Display Object", &addDisplayObj },
    {"Hide Display Object", &hideDisplayObj },
    {"Change Order of Display Object", &changeOrderDisplayObj },
    {"Clear Display Object Queue", &clearDisplayObj },
	{"Change Display Settings", &changeDisplaySettings },
    {"Exit & Save", &exitSave },
    {"", &idActionF } };

int doDisplayObjectMenu(int objnum)
{
    int zz;
    printf("\nDisplay Object Menu:\n");
    zz=chooseMenu(displayObjMenu);
    if(zz>=0)
    {
    (void)computeDisplayed(0);
    return (displayObjMenu[zz].actionF(objnum, 0, 0));                      
    } 
    return -1;
}

DOUBLE notImplemented(int varn, int index, int subindex)
{
    printf("\nFeature Not Yet Implemented.\n");
    return 0;
}

int chooseOutput(void)
{
    int i, n, j;
    char c;
    int negpin, pospin;
    //    
    n=autoSizeName("output");
    i=0;
    j=0x60;
    while(i<n)
    {
    j++;
    if(i==0)
    {
    negpin=1; 
    pospin=2;
    } else
    {
    pospin=3;
    negpin=4;
    }
    printf("(%c) %s Across Pin %d (-) and Pin %d (+) of CON4\n", j, outputStrings[i], negpin, pospin);
    i++;
    }   
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ",j);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<=j))
    return (c-0x61);
    else
    return -1;
}

MENU relayMenu[]={  
    {"Relay Switches ON on a Maximum Condition", 0 },
    {"Relay Switches OFF on a Maximum Condition", 0 },
    {"Relay Switches ON on a Minimum Condition", 0 },
    {"Relay Switches OFF on a Minimum Condition", 0 },
    {"", &idActionF } };

int chooseRelayFunction(void)
{
    int zz, value;
    // returns the code for output
    // bit 3= invert bit and bits 7,6 are the relay mode ie 0xC0=relay inverted and 0x80 = relay normal modes
    // returns -1 if aborted...
    printf("\nChoose the Output Configuration\n");
    zz=chooseMenu((MENU*)&relayMenu[0]);
    if(zz>=0)
    {
        value=0;
        switch(zz)
        {
            case 0:
                // relay on on a maximum
                value=0x80;
                break;
            case 1:
                // relay off on a maximum
                value=0xC0;
                break;
            case 2:
                // relay on on a minimum
                value=0x88;
                break;
            case 3:
                // relay off on a minimum
                value=0xC8;
                break;
            default:
                value=0;
        }
        return value;
    } else
    return -1;
}

DOUBLE disableAllOutputs(int varn, int index, int subindex)
{
    int n, i;
    printf("Disabling All Outputs.\n");
    n=autoSizeName("output");
    i=0;
    while(i<n)
    {
        output[i]=0;
        i++;
    }
    displayObject=0;
    finalSystemWrite++;
    return 0;
}

DOUBLE setUpBeep(int v, int index, int subindex)
{
    int zz, yy, varn;
    printf("\nChoose Which Output To Enable a Buzzer On:\n");
    zz=chooseOutput();
    if(zz>=0)
    {
        yy=chooseDisplayObject();
        if(yy>=0)
        {
         varn=yy & 0x0F;
         if((varn<NUM_VARS)||(varn==VAR_BATT))
         {
         output[zz]=0x40 | (yy & 0x37);
         displayObject=0;
         finalSystemWrite++;
         printf("Output Configured.\n");
         return 0;
         }
         printf("Cannot Monitor That Variable.\n");
         }
    } 
    return -1;
}

DOUBLE setUpRelay(int v, int index, int subindex)
{
    int zz, yy, varn, xx;
    printf("\nChoose Which Output To Enable A Relay On:\n");
    zz=chooseOutput();
    if(zz>=0)
    {
        xx=chooseRelayFunction();
        if(xx>=0)
        {
        yy=chooseDisplayObject();
        if(yy>=0)
        {
         varn=yy & 0x0F;
         if((varn<NUM_VARS)||(varn==VAR_BATT))
         {
         output[zz]=xx | (yy & 0x37);
         displayObject=0;
         finalSystemWrite++;
         printf("Output Configured.\n");
         return 0;
         }
         printf("Cannot Monitor That Variable.\n");
         }
        }
    } 
    return -1;
}

MENU outputMenu[]={  
    {"Set Up a Buzzer Output", &setUpBeep },
    {"Set Up a Relay Output", &setUpRelay },
   // {"Change Beep Frequency", &notImplemented },
    {"Disable All Outputs", &disableAllOutputs },
    {"Exit & Save", &exitSave },
    {"", &idActionF } };
    
MENU variableMenu[]=
{
    {"Change the Name and Unit of the Variable", &changeNameAndUnit },
    {"Change the Minimum and Maximum Values & Hysteresis", &changeMinAndMax },
    {"Change the Variable Display Parameters", &changeDisplayParametersVar },
    {"Change the Variable Type & Acquisition Parameters", &changeAcquisitionParametersVar },
    {"Set the Logging Parameters For the Variable", &changeLoggingParameters },
    {"Change the Welcome Message", &changeWelcomeString },
    {"Exit & Save", &exitSave },
    {"", &idActionF }
};

MENU calibrationMenu[]=
{
    //{"Calibrate the ADC System Automatically", &calibrateSupplyRefAuto },
    {"Calibrate the ADC System", &calibrateSupplyRefManual },
    {"Perform Calibration on a Variable", &calibrateVariableMainMenu },
    {"Exit & Save", &exitSave },
    {"", &idActionF }
};

int doOutputMenuSmall(int objnum)
{
    int zz;
    printf("\n");
    printf("Output Menu:\n");
    zz=chooseMenu(outputMenu);
    if(zz>=0)
    {
    return (outputMenu[zz].actionF(objnum, 0, 0));
    } 
    return -1;
}

int doCalibrationMenuSmall(int objnum)
{
    int zz;
    printf("\n");
    printf("Calibration Menu:\n");
    zz=chooseMenu(calibrationMenu);
    if(zz>=0)
    {
    return (calibrationMenu[zz].actionF(objnum, 0, 0));
    } 
    return -1;
}

int doVariableMenuSmall(int objnum)
{
    int zz, varn;
    //
    printf("\n");
    showVariables();
    printf("\n");
    printf("Variable Menu:\n");
    zz=chooseMenu(variableMenu);
    if(zz>=0)
    {
    return (variableMenu[zz].actionF(varn, 0, 0));
    } 
    return -1;
}

void showConfirmExitMenu(void)
{
    printf("Press Enter  to Exit and Save Changes    \n");
    printf("      ESC    to Cancel and Ignore Changes\n");
    printf("      Any Other Key to Return to The Menu> ");
}

int displayMenu(void)
{
    int i, res;
    char ctemp;
    res=0;
    while(res!=1)
    {
            ctemp=0x0D;
            printf("\nThe Following are Currently Displayed Readings (In Order):\n");
            i=showDisplayObjects(0, 1);
            res=doDisplayObjectMenu(0);
            if(res<0)
            {
            showConfirmExitMenu();
            ctemp=mygetch(&globalcontrolcode);
            printf("%c\n", ctemp);
            if((ctemp==0x1b)||(ctemp==0x0D))res=1;    
            }
    }
    if(ctemp!=0x0D){ finalSystemWrite=0; return -1; }
    return 0;
}

/*
int doVariableMenu(void)
{
    int i, redo;
    char ctemp;
    int yy, zz;
    //
    printf("Setting Up A Variable. Choose From the Following:\n");
    zz=chooseVariable(NUM_UPDATE_VARS);
    if((zz>=0)&&(zz<NUM_UPDATE_VARS))
    {
    redo=0;
    while(redo==0)
    {
            ctemp=0x0D;
            printf("Select From the following:\n");
            yy=chooseMenu(&variableMenu[0]);
            if(yy>=0)
            {
            redo=variableMenu[yy].actionF(zz, 0, 0);
            } else redo=-1;
     if(redo<0)
     {
     printf("Press Enter to Exit and Save Changes, ESC to Cancel. Any Other Key to Return to The Menu> ");
     ctemp=mygetch(&globalcontrolcode);
     printf("%c\n", ctemp);
     if(ctemp==0x1b)redo=-1;
     else if(ctemp==0x0d)redo=1;
     else redo=0;
     }
    }
    if(redo<0)
    { 
        return -1;    
    }
    } else
    {
        printf("You Cannot Perform Calibration On that Variable.\n");
        return 1;
    }
    return 0;        
}
*/

int doVariableMenu(void)
{
    int i, res;
    char ctemp;
    res=0;
    while(res!=1)
    {
            ctemp=0x0D;
            res=doVariableMenuSmall(0);
            if(res<0)
            {
            showConfirmExitMenu();
            ctemp=mygetch(&globalcontrolcode);
            printf("%c\n", ctemp);
            if((ctemp==0x1b)||(ctemp==0x0D))res=1;    
            }
    }
    if(ctemp!=0x0D)
    { 
        return -1; 
    }
    return 0;
}
                 
int doCalibrationMenu(void)
{
    int i, res;
    char ctemp;
    res=0;
    while(res!=1)
    {
            ctemp=0x0D;
            res=doCalibrationMenuSmall(0);
            if(res<0)
            {
            showConfirmExitMenu();
            ctemp=mygetch(&globalcontrolcode);
            printf("%c\n", ctemp);
            if((ctemp==0x1b)||(ctemp==0x0D))res=1;    
            }
    }
    if(ctemp!=0x0D)
    { 
        return -1; 
    }
    return 0;
}

int doOutputMenu(void)
{
    int i, res;
    char ctemp;
    res=0;
    while(res!=1)
    {
            ctemp=0x0D;
            printf("\nThe Following are the Output Settings:\n");
            i=showOutputs(0);
            res=doOutputMenuSmall(0);
            if(res<0)
            {
            showConfirmExitMenu();
            ctemp=mygetch(&globalcontrolcode);
            printf("%c\n", ctemp);
            if((ctemp==0x1b)||(ctemp==0x0D))res=1;    
            }
    }
    if(ctemp!=0x0D){ finalSystemWrite=0; return -1; }
    return 0;
}

DOUBLE showFirmwareVersionF(SYSTEMVAR* inptr, char* tostr, int tabwidth)
{
      sprintf(tostr, "%s", inptr->title);
      sdoDots(tostr, tostr, tabwidth, '.');
      sprintf(tostr, "%s: %0.2d.%0.2d", tostr, verhigh, verlow);
      return 0;
}

DOUBLE computeFosc4(DOUBLE x)
{
   return (DOUBLE)(fosc4div1000*1000.0);       
}

DOUBLE computeFosc4MHz(DOUBLE x)
{
   return (DOUBLE)(fosc4div1000/1000.0);
}

DOUBLE computeTmr0Period(DOUBLE x)
{
    return 65535.0-(double)tmr0HPeriod*256.0;
}

DOUBLE inverseTmr0Period(DOUBLE x)
{
    return (65535.0-x)/256.0;
}

VALUEPAIR computeT0CONAndTmr0Period(DOUBLE targetfreq)
{
         VALUEPAIR v;
         DOUBLE f;
         int j;
         // returns x=T0CON value and y=Tmr0Period Ticks value corresponding to the frequency required
         if(targetfreq<0.01)targetfreq=0.01;             // clip negatives and avoid div by zero!
         f=fosc4/(targetfreq*NUM_UPDATE_VARS*2.0);
         // f is now the timer 0 period required for the target frequency with 1:1 prescaler
         j=0;
         while((j<6)&&(f>65535.0))
         {
         f/=2.0;
         j++;
         }
         if(f>65535.0)f=65535.0;  // this is an error!
         else
         if(f<1)f=1;
         v.x=j;
         v.y=f;
         return v;
}

DOUBLE setLogUpdateFreq(SYSTEMVAR* inptr, DWORD* totalerror)
{
    DWORD error;
    VALUEPAIR v;
    BYTE reqT0CON, reqTmr0HPeriod;
    // so now the input value is the required log update frequency...
    v=computeT0CONAndTmr0Period(inptr->inputValue);
    reqT0CON=(0x80 | ((BYTE)(v.x) & 7));
    reqTmr0HPeriod=inverseTmr0Period(v.y);
    idSetFVarName("tmr0ConLog", reqT0CON, 0, TMR0CONLOG_ADR, &error);
    *totalerror=error;
    idSetFVarName("tmr0HPeriod", reqTmr0HPeriod, 0, TMR0HPERIOD_ADR, &error);
    *totalerror|=error;
    idSetFVarName("tmr0Con", reqT0CON+1, 0, TMR0CON_ADR, &error);
    *totalerror|=error;
    writeRamVariable("T0CON", reqT0CON+1, 0 , SIZEBYTE, &error);
    *totalerror|=error;
    return 0;  
}

DOUBLE computeVarUpdateFreq(DOUBLE x)
{ 
    int i;    
    DOUBLE f;
    
    i=(1<< ((tmr0con & 7)+1));
    if((i*tmr0Period)!=0)f=fosc4/(i*NUM_UPDATE_VARS*tmr0Period); else f=0.1;
    return f;
}

DOUBLE computeLogUpdateFreq(DOUBLE x)
{
    int i;
    
    i=(1<< ((tmr0conlog & 7)+1));
    if((i*tmr0Period)!=0)logUpdateFreq=fosc4/(i*NUM_UPDATE_VARS*tmr0Period); else logUpdateFreq=0.1;
    x=logUpdateFreq;
    return x;
}    

/*DOUBLE computeIBattScaling(DOUBLE x)
{
    return ((DOUBLE)(battScaling+SCALE_OFFSET)*((DOUBLE)VOLTAGE_SCALE_STEP));
}
*/

DOUBLE computeStringMemInUse(DOUBLE x)
{
       return getStringsSubIndex(0, computeEndIndex((BYTE*)&Strings, stringsSize, STRING_DELIMITER), STRING_DELIMITER);     
}

DOUBLE computeDisplayed(DOUBLE x)
{
       int i, j, n, varn, index;
       // computes which variables & value indexes are currently being displayed!
       // put defaults!
       for(i=0; i<NUM_VARS; i++)
       {
                for(j=0;j<NUM_VALUES;j++)variable[i].displayed[j]=0;
                variable[i].displayedTotal=0;
       }
       // size the objects
       n=autoSizeName("displayObj");
       if((n>0)&&(n<MAX_NUM_DISPLAY_OBJECTS))
       {
                i=0;
                while(i<n)
                {
                          if((i==0)||((displayObj[i] & 0x80)!=0))
                          {
                                    varn=(displayObj[i] & 0x0F);
                                    index=(displayObj[i]>>4) & 3;
                                    if(varn<NUM_VARS)
                                    { 
                                    if(variable[varn].displayed[index]==0)variable[varn].displayed[index]=i+1;
                                    variable[varn].displayedTotal|=(1<<index);
                                    } else
                                    if(varn<NUM_UPDATE_VARS)
                                    {
                                      if(variable[varn].displayed[0]==0)variable[varn].displayed[0]=i+1;
                                        variable[varn].displayedTotal|=1;
                                    }
                          }
                          i++;
                          }                                                       
       }
       return 0;
}

DOUBLE showBattVoltage(SYSTEMVAR* inptr, char* tostr, int tabwidth)
{
    char buffer[MAX_STRING_SIZE];
    //sprintf(tostr, "%s", inptr->title);
    sprintStringVar(buffer, &variable[VAR_BATT], VAR_BATT, 0, UNIT_INDEX, STRING_DELIMITER, tabwidth); 
    sprintStringVar(tostr, &variable[VAR_BATT], VAR_BATT, 0, VALUE_INDEX, STRING_DELIMITER, tabwidth);
    sdoDots(tostr, tostr, tabwidth, '.');
    sprintf(tostr, "%s: %-3.1f %s (Min: %-3.1f %s Max: %-3.1f %s)", tostr, battVoltage, buffer, battMin*BATTSCALE, buffer, battMax*BATTSCALE, buffer);
    return 0;
}

DOUBLE computeBattRef(DOUBLE x)
{
    return ((DOUBLE)VOLTAGEREF*((DOUBLE)(battScaling+SCALE_OFFSET)/FIXED_POINT_SCALE));
}

DOUBLE inverseBattRef(DOUBLE x)
{
    return (((DOUBLE)x/(DOUBLE)VOLTAGEREF)*(DOUBLE)FIXED_POINT_SCALE)-SCALE_OFFSET;
}

DOUBLE computeBattMax(DOUBLE x)
{
    return (battMax*BATTSCALE);
}

DOUBLE inverseBattMax(DOUBLE x)
{
    return (x/BATTSCALE);
}

DOUBLE computeBattMin(DOUBLE x)
{
    return (battMin*BATTSCALE);
}

DOUBLE inverseBattMin(DOUBLE x)
{
    return (x/BATTSCALE);
}

DOUBLE showBattSleepDelay(SYSTEMVAR* inptr, char* tostr, int tabwidth)
{
       char ibuffer[2][MAX_STRING_SIZE];
       DOUBLE f;
       SYMBOL* psym;

       if(inptr->title[0]!='\0')       
       sprintf(ibuffer[0], "%s", inptr->title);
       else
       sprintf(ibuffer[0], "%s", inptr->name);
       sdoDots(ibuffer[0], ibuffer[0], tabwidth,'.');
       sprintFormat(ibuffer[1], (BYTE*)inptr->ptr, inptr->format, autoSize(inptr));
       if(battSleepDelay>0.0)sprintf(tostr, "%s: %s %s", ibuffer[0], ibuffer[1], inptr->unit);
       else sprintf(tostr, "%s: Off", ibuffer[0]);
       return 0;
}

DOUBLE computeBattSleepDelay(DOUBLE x)
{
    return ((DOUBLE)battSleepMode*2.0/(DOUBLE)logUpdateFreq);
}

DOUBLE setBattSleepDelay(SYSTEMVAR* inptr, DWORD* totalerror)
{
    DWORD error;
    idSetFVarName("battSleepMode", inptr->inputValue, inptr->ptr, BATTSLEEPMODE_ADR, &error);
    *totalerror=error;
    return 0;  
}

DOUBLE inverseBattSleepDelay(DOUBLE x)
{
    
    return (DOUBLE)x*(DOUBLE)logUpdateFreq/2.0;
}

DOUBLE computeBattRefCorrection(DOUBLE x)
{
    return 100.0*((battRef/(VOLTAGEREF))-1.0);
}

DOUBLE showNumberOfSymbols(DOUBLE x)
{
     printf("%d", mapTable.mapTableSize);
     return x;
}

void showInfoDirect(SYSTEMVAR* sysptr, INT prioritymin, INT prioritymax)
{
    int i;
    char ibuffer[MAX_STRING_SIZE];
    //
    while(sysptr->type!=END_TYPE)
    {
      if((sysptr->type & SETTING_TYPE)!=0)
      {               
       sysptr->showFunction(sysptr, ibuffer, VAR_TAB);
       printf("%s\n", ibuffer);
       }
       sysptr++;
    }
}

SYSTEMVAR* systemVarLookUp(char *name, SYSTEMVAR* inptr)
{
    int notfound;
    notfound=1;
    inptr--;
    while((notfound!=0)&&(inptr->type!=END_TYPE))
    {
    inptr++;
    notfound=strcmp(inptr->name, name);
    }
    return inptr;    
}

SYSTEMVAR* systemVarLookUpTitle(char *title, SYSTEMVAR* inptr)
{
    int notfound;
    notfound=1;
    inptr--;
    while((notfound!=0)&&(inptr->type!=END_TYPE))
    {
    inptr++;
    notfound=strcmp(inptr->title, title);
    }
    return inptr;    
}

int getInfoSystemVar(SYSTEMVAR* inptr, DWORD* err)
{
    DWORD error, totalerror;
    DWORD pA;
     
     totalerror=0;
     if((inptr->type & RD_TYPE)!=0)
     {
          // a straight read only variable type so just read it in!
          pA=readRamVariableAutoSize(inptr->name, 0, inptr->ptr, &error);
          //printf("Reading the variable %s: %4.4x\n", inptr->name, pA);
          copyPtr((BYTE*)&indatapacket.data[0], inptr->ptr, autoSize(inptr), READ_DIR);
          inptr->inputValue=getDouble(inptr->ptr, autoSize(inptr));
          totalerror|=error;
     }
//    printf("Processing System Var: %s ", inptr->name);
     if((inptr->type & COMPUTE_TYPE)!=0)
     {
          // a computation is required ...
          inptr->inputValue=inptr->function(0);
          putDouble(inptr->ptr, inptr->inputValue, autoSize(inptr));
     }
     
     if((inptr->type & UPDATE_TYPE)!=0)
     {
          // a computation to update some other variables is required ...
          inptr->inputValue=inptr->function(0);
     }
    
    *err=totalerror;
    return 0;
}

int getInfoSystemVarName(char* name, SYSTEMVAR* inptr, DWORD* err)
{
    getInfoSystemVar(systemVarLookUp(name, inptr), err);
    return 0;
}

int getInfoSystemVarTitle(char* title, SYSTEMVAR* inptr, DWORD* err)
{
    getInfoSystemVar(systemVarLookUpTitle(title, inptr), err);
    return 0;
}

int getInfo(SYSTEMVAR* inptr, DWORD* err)
{
    int i;
    short int        x;
    DWORD            error;
    DWORD            totalerror;
    DWORD            pA;
    int exit;
    SYMBOL* symp;
    // start reading or computing the system information here
    totalerror=0;
    exit=0;
    while((exit==0)&&(totalerror==0))
    {
    if(inptr->type==END_TYPE)exit=1;
    else
    {
    getInfoSystemVar(inptr, &error);
    totalerror|=error;
    }
    inptr++;
   }      
   *err=totalerror;
   return totalerror;  
}

int putInfoSystemVar(SYSTEMVAR* inptr, DWORD* err)
{
    DWORD localerr;
    DOUBLE ftemp;
    int rval;
    
    localerr=0;
    // these are writeable variables!
    //itemp=getDouble(inptr->ptr, autoSize(inptr));
    rval=getInputVar(inptr, &ftemp);
    if(rval!=0)
	{
    inptr->inputValue=ftemp;
    ftemp=inptr->setFunction(inptr, &localerr);
    }
    *err=localerr;
    return 0;
}

int putInfoSystemVarTitleDouble(char* title, SYSTEMVAR* inptr, DOUBLE ftemp, DWORD* err)
{
    DWORD localerr;
    SYSTEMVAR* ptr;
    localerr=0;
    ptr=systemVarLookUpTitle(title, inptr);
    ptr->inputValue=ptr->inverseFunction(ftemp);
    ftemp=ptr->setFunction(ptr, &localerr);
    *err=localerr;
    return 0;
}

int putInfoSystemVarName(char *name, SYSTEMVAR* inptr, DWORD* err)
{
    putInfoSystemVar(systemVarLookUp(name, inptr), err);
    return 0;
}


int putInfoSystemVarTitle(char *title, SYSTEMVAR* inptr, DWORD* err)
{
    putInfoSystemVar(systemVarLookUpTitle(title, inptr), err);
    return 0;
}

SYSTEMVAR systemSystem[]=
{
  {RO,   0, "verhigh", 	           "High Version",                       "",       FORMAT_D,     (BYTE*)&verhigh,               SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RO,   0, "verlow",              "Low Version",                        "",       FORMAT_D,     (BYTE*)&verlow,                SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {SO,   0, "",                    "Firmware Version",                   "",       NO_FORMAT,     0,                            1,           0, 0,          0, 0,    0,                   &showFirmwareVersionF,&idF,             &idF, &idSetF, 0 }, 
  {SO,   0, "",                    "Number of Symbols",                  "",       FORMAT_D,     (BYTE*)&(mapTable.mapTableSize),sizeof(mapTable.mapTableSize), 0, 0, 0, 0, 0,            &idShowF,            &idF,              &idF, &idSetF, 0 },
  {SO,   0, "",                    "Polynomial Memory In Use",           "%",      FORMAT_D,     (BYTE*)&polyMemoryUsedPercent, sizeof(polyMemoryUsedPercent),   0, 0, 0, 0, 0,           &idShowF,            &idF,              &idF, &idSetF, 0 },
  {SO,   0, "",                    "Number of Loaded Strings",           "String(s)",FORMAT_D,     (BYTE*)&endIndex,              sizeof(endIndex),   0, 0, 0, 0, 0,                      &idShowF,            &idF,              &idF, &idSetF, 0 },  
  {RS,   0, "szVariable",          "Size of Variable Data Structure",    "Bytes",  FORMAT_D,     (BYTE*)&szVariable,             SIZEAUTO,    0, 0,          0, 0,    0,                  &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "addressStringFlash",  "Address String Flash",               "",       FORMAT_X4,    (BYTE*)&addressStringFlash,    SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "addressVariableFlash","Address Variable Flash",             "",       FORMAT_X4,    (BYTE*)&addressVariableFlash,  SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RO,   0, "maxStringSize",       "Maximum String Size",                "Bytes",  FORMAT_D,     (BYTE*)&maxStringSize,          SIZEAUTO,    0, 0,          0, 0,    0,                  &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "stringsSize",         "String Memory",                      "Bytes",  FORMAT_D,     (BYTE*)&stringsSize,            SIZEAUTO,    0, 0,          0, 0,    0,                  &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "T0CON",               "",                                   "",       FORMAT_X2,    (BYTE*)&t0con,                 SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
 // {RS,   0, "CCP1CON",             "",                                   "",       FORMAT_X2,    (BYTE*)&ccp1con,                 SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
 // {RS,   0, "PIE1",                "",                                   "",       FORMAT_X2,    (BYTE*)&pie1,                 SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
 // {RS,   0, "PIR1",                "",                                   "",       FORMAT_X2,    (BYTE*)&pir1,                 SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "tmr0ConLog",          "",                                   "",       FORMAT_X2,    (BYTE*)&tmr0conlog,            SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "tmr0Con",             "",                                   "",       FORMAT_X2,    (BYTE*)&tmr0con,               SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 4, "checkPeriod",         "",                                   "",       FORMAT_X2,    (BYTE*)&checkPeriod,           SIZEAUTO,    0, 0,          0, 0,    CHECKPERIOD_ADR,     &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 4, "beepPeriod",          "",                                   "",       FORMAT_X2,    (BYTE*)&beepPeriod,            SIZEAUTO,    0, 0,          0, 0,    BEEPPERIOD_ADR,      &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 4, "limitPeriod",         "",                                   "",       FORMAT_X2,    (BYTE*)&limitPeriod,           SIZEAUTO,    0, 0,          0, 0,    LIMITPERIOD_ADR,     &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "limitCounter",        "",                                   "",       FORMAT_X2,    (BYTE*)&limitCounter,          SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "limitObj",            "",                                   "",       FORMAT_X2,    (BYTE*)&limitObj,              SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 0, "displayMode",         "Current Display Mode",               "",       FORMAT_D,     (BYTE*)&displayMode,           SIZEAUTO,    0, 2,          0, 0,    DISPLAYMODE_ADR,     &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 0, "displayObject",       "Current Display Object",             "",       FORMAT_D,     (BYTE*)&displayObject,         SIZEAUTO,    0, 0,          0, 0,    DISPLAYOBJECT_ADR,   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 1, "minorDelay",          "Minor Delay",                        "x16ms",  FORMAT_D,     (BYTE*)&minorDelay,            SIZEAUTO,    12,250,        0, 0,    MINORDELAY_ADR,      &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 1, "majorDelay",          "Major Delay",                        "x16ms",  FORMAT_D,     (BYTE*)&majorDelay,            SIZEAUTO,    20,250,        0, 0,    MAJORDELAY_ADR,      &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "tmr0HPeriod",         "",                                   "",       FORMAT_X2,    (BYTE*)&tmr0HPeriod,           SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RO,   1, "ldrLevel",            "LDR Level",                          "",       FORMAT_D,     (BYTE*)&ldrLevel,              SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RO,   0, "ldrPercent10",        "",                                   "",       FORMAT_D,     (BYTE*)&ldrPercent10,          SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battLevel",           "Battery Level",                      "",       FORMAT_D,     (BYTE*)&battLevel,             SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {CS,   1, "ldrPercent",          "Ambient Light",                      "%",      FORMAT_F1,    (BYTE*)&ldrPercent,            sizeof(ldrPercent),         0, 0,    0, 0,    0,          &idShowF,            &computeLdrPercent,&idF, &idSetF, 0 },
  {RWSF, 0, "systemName",          "System Name String Index",           "",       FORMAT_X4,    (BYTE*)&systemName,            SIZEAUTO,    0, 0,          0, 0,    SYSTEMNAMEL_ADR,     &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 0, "systemDecp",          "No. of Digits After Decimal Point",  "Digit(s)",FORMAT_D,    (BYTE*)&systemDecp,            SIZEAUTO,    0, 3,          0, 0,    SYSTEMDECP_ADR,      &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 2, "minBrightness",       "Min Brightness",                     "",       FORMAT_D,     (BYTE*)&minBrightness,         SIZEAUTO,    5, 250,        0, 0,    MINBRIGHTNESS_ADR,   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 2, "maxBrightness",       "Max Brightness",                     "",       FORMAT_D,     (BYTE*)&maxBrightness,         SIZEAUTO,    5, 250,        0, 0,    MAXBRIGHTNESS_ADR,   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   2, "screenOnPeriod",      "Current Brightness",                 "",       FORMAT_D,     (BYTE*)&screenOnPeriod,        SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 1, "roundingMode",        "Readings Rounding-Off",              "",       FORMAT_B,     (BYTE*)&roundingMode,          SIZEAUTO,    0, 0,          0, 0,    ROUNDINGMODE_ADR,    &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 1, "zeroAcc",             "Zero Accumulators at Power On",      "",       FORMAT_B,     (BYTE*)&zeroAcc,               SIZEAUTO,    0, 0,          0, 0,    ZEROACC_ADR,         &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 1, "battWakeUpMode",      "Automatic Wake Up On Battery Sense", "",       FORMAT_B,     (BYTE*)&battWakeUpMode,        SIZEAUTO,    0, 0,          0, 0,    BATTWAKEUPMODE_ADR,  &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battLow",             "Battery Protection TimeOut",         "Tick(s)",FORMAT_D,     (BYTE*)&battLow,               SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battSleepMode",       "Battery Protection (Sleep Mode)",    "",       FORMAT_D,     (BYTE*)&battSleepMode,         SIZEAUTO,    16, 250,       0, 0,    BATTSLEEPMODE_ADR,   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 3, "invertMask",          "Visible Cues Mask",                  "",       FORMAT_X2,    (BYTE*)&invertMask,            SIZEAUTO,    0x00, 0xFF,    0, 0,    INVERTMASK_ADR,      &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWSF, 2, "scrollSpeed",         "Scroll Delay",                       "ms",     FORMAT_D,     (BYTE*)&scrollSpeed,           SIZEAUTO,    5, 200,        0, 0,    SCROLLSPEED_ADR,     &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battScaling",         "",                                   "",       FORMAT_X2,    (BYTE*)&battScaling,           SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RO,   0, "fosc4div1000",        "",                                   "kHz",    FORMAT_D,     (BYTE*)&fosc4div1000,          SIZEAUTO,    0, 20000,          0, 0,    0,               &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battMin",             "",                                   "",       FORMAT_X2,    (BYTE*)&battMin,               SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RS,   0, "battMax",             "",                                   "",       FORMAT_X2,    (BYTE*)&battMax,               SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {CO,   0, "fosc4",               "",                                   "Hz",     FORMAT_D,     (BYTE*)&fosc4,                 sizeof(fosc4),   0, 20000000.0, 0, 0,    0,               &idShowF,            &computeFosc4,     &idF, &idSetF, 0 },
  {CS,   0, "",                    "System Clock Frequency",             "MHz",    FORMAT_F3,    (BYTE*)&fosc4MHz,              sizeof(fosc4MHz),0, 20.0,       0, 0,    0,               &idShowF,            &computeFosc4MHz,  &idF, &idSetF, 0 },
  {CS,   0, "",                    "Tmr0 Period",                        "Tick(s)",FORMAT_D,     (BYTE*)&tmr0Period,            sizeof(tmr0Period),    0,       65535.0,        0, 0, 0,  &idShowF,            &computeTmr0Period,   &idF, &idSetF, 0 }, 
  {CS,   1, "",                    "Readings Update Frequency (Normal)", "Hz",     FORMAT_F1,    (BYTE*)&varUpdateFreq,         sizeof(varUpdateFreq), MINUFQ,  MAXUFQ,         0, 0, 0,  &idShowF,            &computeVarUpdateFreq,&idF, &idSetF, 0 }, 
  {CWSF, 1, "",                    "Readings Update Frequency (Logged)", "Hz",     FORMAT_F1,    (BYTE*)&logUpdateFreq,         sizeof(logUpdateFreq), MINUFQ,  MAXUFQ,         0, 0, 0,  &idShowF,            &computeLogUpdateFreq,&idF, &setLogUpdateFreq, 0 }, 
  {CS,   1, "",                    "Battery Voltage",                    "V",      FORMAT_F1,    (BYTE*)&battVoltage,           sizeof(battVoltage),   0,       VOLTAGE_RANGE,  0, 0, 0,  &showBattVoltage,    &computeBattVoltage,  &idF, &idSetF, 0 }, 
  {CWSF, 1, "",                    "Battery Protection Delay",           "sec.",   FORMAT_F1,    (BYTE*)&battSleepDelay,        sizeof(battSleepDelay),0.0,     120.0,          0, 1, 0,  &showBattSleepDelay, &computeBattSleepDelay,  &inverseBattSleepDelay, &setBattSleepDelay, 0 },   
  {CWSF, 1, "",                    "Battery Maximum Voltage",            "V",      FORMAT_F2,    (BYTE*)&battMaxVoltage,        sizeof(battMaxVoltage),       0, 100.0,        0, 0, 0,  &idShowF,            &computeBattMax,  &inverseBattMax, &setBattMax, 0 },   
  {CWSF, 1, "",                    "Battery Minimum Voltage",            "V",      FORMAT_F2,    (BYTE*)&battMinVoltage,        sizeof(battMinVoltage),       0, 100.0,        0, 0, 0,  &idShowF,            &computeBattMin,  &inverseBattMin, &setBattMin, 0 },   
  {CWSF, 1, "",                    "Supply Reference",                   "V",      FORMAT_F2,    (BYTE*)&battRef,               sizeof(battRef),       MINREFV, MAXREFV,        0, 0, 0,  &idShowF,            &computeBattRef,  &inverseBattRef, &setBattRef, 0 },   
  {CS,   1, "",                    "Supply Reference Correction",        "%",      FORMAT_F2,    (BYTE*)&battRefCorrection,     sizeof(battRefCorrection),-50.0,50.0,           0, 0, 0,  &idShowF,            &computeBattRefCorrection,   &idF, &idSetF, 0 },   
  {CS,   0, "",                    "String Memory In Use",               "Bytes",  FORMAT_D,     (BYTE*)&stringMemInUse,        sizeof(stringMemInUse),         0, 0,    0, 0,    0,      &idShowF,            &computeStringMemInUse,&idF, &idSetF, 0 },
  {RS,   0, "PORTE",               "",                                   "",       FORMAT_X2,    (BYTE*)&porte,                 SIZEAUTO,    0, 0,          0, 0,    0,                   &idShowF,            &idF,              &idF, &idSetF, 0 },
  {RWUSF,0, "displayObj",          "Display Queue",                      "",       FORMAT_X2,    (BYTE*)&displayObj[0],         SIZEAUTO,    0, 0,     0, 0,    DISPLAY_OBJS_ADR,         &showQueueObjF,      &computeDisplayed,   &idF, &idSetF, 0 },
  {RWSF, 0, "output",              "Outputs",                            "",       FORMAT_X2,    (BYTE*)&output[0],             SIZEAUTO,    0, 0,     0, 0,    OUTPUT1_ADR,              &showQueueObjF,      &idF,                &idF, &idSetF, 0 },
  {END_TYPE, 0, "", "", "", 								                       NO_FORMAT, 	 (BYTE*)0, 		  0,   0, 	0, 0, 0, 0, &idShowF, &idF, &idF, &idSetF, 0 }
};


DOUBLE changeDisplaySettings(int varn, int index, int subindex)
{
    DWORD localerror;
	doDotsCommand("Changing Display Settings", ": Ok");
	printf("\n");
	putInfo((SYSTEMVAR*)&systemSystem[0], 2, 2, &localerror);
	return 0;
}

int getSystemInfo(DWORD* err)
{
    getInfo(&systemSystem[0], err);
    return 0;   
}

BYTE* processSystemSettings(SYSTEMVAR* sysptr, BYTE* ptr, int dir)
{
    BYTE* iptr;
    int i;

    iptr=ptr;
    while(sysptr->type!=END_TYPE)
    {
        if((sysptr->type & SETTING_TYPE)!=0)
        {
            if(sysptr->ptr!=NULL)
            {
                    i=autoSize(sysptr);
                    if(i<=0)i=1;
                    
        /*
        if(sysptr->title[0]!='\0')printf("Processing Var: %s Auto Sized: %d\n", sysptr->title, i);
        else printf("Processing VAR: %s Auto Sized: %d\n", sysptr->name, i);
        */
        iptr+=copyPtr(iptr, (BYTE*)sysptr->ptr, i, dir);
            }
        }
    sysptr++;
    }
    return iptr;
}

BYTE* processSettings(BYTE* ptr, int number, int dir)
{
    // process all settings!
    int i, localcmptotal;
    BYTE* iptr;
    iptr=ptr;
    for(i=0; i<NUM_VARS;i++)
    {
    localcmptotal=0;
    iptr=updateVariableInfo(iptr, i, dir, &localcmptotal);
    //printf("Loading Variable Data. Cmptotal: %d\n", localcmptotal);
    if(dir==READ_DIR)variable[i].cmptotal+=localcmptotal;
    }
    iptr=processSystemSettings((SYSTEMVAR*)&systemSystem[0], iptr, dir);
    iptr=updatePolyTableInfo(iptr, MAX_POLY_INDEXES, dir);
    iptr=updatePolyMemoryInfo(iptr, 0, MAX_POLY+2, dir);
    for(i=0; i<MAXSTRINGSSIZE; i++)
    {
    if(dir==READ_DIR)Strings[i]=*iptr++; else *iptr++=Strings[i];
    }
    if(dir==READ_DIR)polyUpdate++;
    return iptr;
}

int sendSystemSettings(SYSTEMVAR* sysptr, DWORD* totalerror)
{
    // this function sends all system settings to the device!
    // ie. commits them to (non volatile) memory.
    BYTE* iptr;
    int i;
    DOUBLE ftemp;
    DWORD localerror;
    
    i=0;
    *totalerror=0;
    while(sysptr->type!=END_TYPE)
    {
        if(((sysptr->type & SETTING_TYPE)!=0)&&((sysptr->type & WR_TYPE)!=0))
        {
            if(sysptr->ptr!=NULL)
            {
             // these are writeable variables!
             ftemp=getDouble(sysptr->ptr, autoSize(sysptr));
             // ftemp is now the value of the variable...
             //printf("Loading %s Value: %6.6f\n", sysptr->title, ftemp);
             sysptr->inputValue=sysptr->inverseFunction(ftemp);
             localerror=0;
             ftemp=sysptr->setFunction(sysptr, &localerror);
             (*totalerror)=(*totalerror)|localerror;
             if(localerror==0)i++;
             //printf("Localerror: %4.4x\n", localerror);
             }      
        }
    sysptr++;
    }
    return i;
}

int sendSettings(SYSTEMVAR* sysptr, DWORD* totalerror)
{
    // this function sends all system settings to the device as well as variable data and string data!
    // ie. commits them to (non volatile) memory.
    DWORD localerror;
    int i, j, k;
    
    j=sendSystemSettings(sysptr, &localerror);
    *totalerror=localerror;
    i=0;
    while(((*totalerror)==0)&&(i<NUM_VARS))
    {
    //   printf("Committing variable %d\n", i);
       localerror=0;
       k=variable[i].cmptotal;
       putVariable(i, &localerror);
       (*totalerror)=(*totalerror) | localerror;
       if(localerror==0)j+=k;
      // printf("totalerror: %4.4x\n", *totalerror);
    i++;
    }
    return j;
}

int readSettingsFile(char *filename, BYTE* inptr, int maxnumber)
{
    // load all settings
    char ifilename[MAX_STRING_SIZE];
    char linebuffer[MAX_STRING_SIZE];
    DWORD length;
    INT i;
    long int farg;
    char c;
    int lp;
    BYTE* optr;
    ifstream isettingsFile;

    sprintf(ifilename, "%s", filename);
    isettingsFile.open(filename, ifstream::in);
    isettingsFile.getline(linebuffer, MAX_STRING_SIZE);
    i=0;
    optr=inptr;
    if(isettingsFile.good())
    {
        while(!isettingsFile.eof())
        {
            isettingsFile.getline(linebuffer, MAX_STRING_SIZE);
            lp=0;
            while((lp<MAX_STRING_SIZE)&&(linebuffer[lp]!='\0'))
            {
            while((linebuffer[lp]!=0)&&(isNumericHex(linebuffer[lp])==0))lp++;
            if(isNumeric(linebuffer[lp])==1)
            { 
            i++; 
            farg=strtol(&linebuffer[lp], NULL, 16);
            //printf("FARG: 0x%4.4x ", (BYTE)farg);
            if(i<=maxnumber){ *optr=(BYTE)farg; optr++; }
            }
            while((linebuffer[lp]!=0)&&(isNumericHex(linebuffer[lp])==1))lp++;
            }
        }  
    } 
    (void)processSettings(inptr, i, READ_DIR);
    isettingsFile.close();
    return i;
}

int writeSettingsFile(char *filename, BYTE* inptr, int maxnumber)
{
    // save all settings
    char ifilename[MAX_STRING_SIZE];
    DWORD length;
    INT i;
    BYTE* optr;
    int total;
    ofstream osettingsFile;
    //
    optr=processSettings(inptr, maxnumber, WRITE_DIR);
    total=optr-inptr;
    if(total<maxnumber)maxnumber=total;
    sprintf(ifilename, "%s", filename);
    osettingsFile.open(filename, ofstream::trunc);
    osettingsFile << "Settings Saved On: ";
    updateTime();
    osettingsFile << asctime(&theLocalTime);
    i=0;
    optr=inptr;
    while(i<maxnumber)
    {
    //osettingsFile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixed
    //osettingsFile.precision(0);
    osettingsFile.setf(ios::hex, ios::basefield);       // set hex as the basefield
    osettingsFile.setf(ios::showbase);                  // activate showbase
    osettingsFile.width(4);
    (void)osettingsFile.fill(' ');
    osettingsFile << (int)(*optr);
    osettingsFile << ", ";
    i++;
    optr++;
    if((i % SETTINGS_LINE_LENGTH)==0)osettingsFile << "\n";
    }
    osettingsFile << "EOF\n";
    osettingsFile.close();
    return i;
}

DOUBLE changeWelcomeString(int vn, int index, int subindex)
{
   int d;
   char buffer[6][MAX_STRING_SIZE];
   DWORD localerror;
   //
   printf("\nChanging the Welcome Message:\n");
   sprintStringWelcome(buffer[0], STRING_DELIMITER, STRING_TAB);
   d=enterString(buffer[0], "Enter New Welcome Message>", STRING_TAB, STRING_DELIMITER, "\n");
   if(d!=0x1b)
   {      
   sprintStringVar(buffer[1], 0, VAR_BATT,0, 0, STRING_DELIMITER, STRING_TAB);
   sprintStringVar(buffer[2], 0, VAR_LDR, 0, 0, STRING_DELIMITER, STRING_TAB);
   sprintStringVar(buffer[3], 0, VAR_BATT,0, 1, STRING_DELIMITER, STRING_TAB);
   sprintStringVar(buffer[4], 0, VAR_LDR, 0, 1, STRING_DELIMITER, STRING_TAB);
   sprintf(buffer[5], "%s:%s:%s:%s:%s:", buffer[1], buffer[3], buffer[2], buffer[4], buffer[0]);
   //printf("buffer5= %s\n", buffer[5]);
   doDotsCommand("Entering New Welcome String", ":");
   putSystemString(buffer[5], STRING_DELIMITER, &localerror);
   //showPacketASCII(&Strings[0], 128);
   if(localerror==0)
   {
   printf("Ok.\n");
   finalSystemWrite++;
   } else printf("Error.\n");
   } else
   {
   printf("\n");
   }
   return 0;
}

DOUBLE changeNameAndUnit(int vn, int index, int subindex)
{
       int valueshow;
       char buffer[4][NUM_VALUES][MAX_STRING_SIZE*5];
       int i, j;
       int c;
       int d;
       int varn;
       DWORD localerror;

       printf("\n");
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))
       {
       getVarTypeString(buffer[0][0], varn);
       printf("\nChanging the Name and Unit Strings for %s.\n", buffer[0][0]);
       if(varn<NUM_VARS)
       { 
       if(variable[varn].displayedTotal==0)
       {
       printf("This Variable Is Not Currently Being Displayed\n");
       printf("Go To the Display Menu to Add this to the Display Queue\n");
       printf("Type cardisplay -d to Enter the Display Menu.\n");
       printf("\n");
       }
       else
       {
        printf("\nChanging the Names and Units of the Displayed Values of the Variable. Displayed Values Are:\n");
        j=0;
        for(i=0; i<NUM_VALUES; i++)
        {
        (void)getNameAndUnit(buffer[0][j], buffer[1][j], varn, i, NAME_TRUNCATION);
        getOrderString(buffer[2][j], variable[varn].displayed[i]);
        getValueIndexString(buffer[3][j], varn, i);
        sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-16.16s \n    Measures: %-32.32s Display Order: %s", j+0x61, buffer[0][j], buffer[1][j], buffer[3][j], buffer[2][j]);
        printf("%s\n", printBuffer);
        j++;
        } 
        printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
        c=mygetch(&globalcontrolcode);
        printf("%c\n", c);
        if((c>='a')&&(c<=(0x60+j)))
        {
         c-='a';
         d=enterString(buffer[0][c], "Enter New Name>", STRING_TAB, STRING_DELIMITER, "\n");
         if(d!=0x1b)
         {
          d=enterString(buffer[1][c], "Enter New Unit>", STRING_TAB, STRING_DELIMITER, "\n");  
          if(d!=0x1b)
          {
            sprintf(printBuffer, "%s:%s", buffer[0][c], buffer[1][c]);
            doDotsCommand("Entering Strings", ":");
            d=putVarString(printBuffer, varn, c, STRING_DELIMITER, &localerror);
            if(localerror==0)
                { 
                //printf("Here variable %d name %d index %d \n", varn, variable[varn].name[c], c);
                printf("Ok.\n");
                }
                else
                printf("Error.\n");
            
          } else 
          { 
                //printf("\nAction Cancelled.\n");
                printf("\n");
            }
         } else 
         {
                //printf("\nAction Cancelled.\n");
                printf("\n");
            }
        } else 
        {
            //printf("Action Cancelled.\n");
        }
       }
    } else
    if((varn==VAR_BATT)||(varn==VAR_LDR))
    {
        // rename a builtin variable
         sprintStringVar(buffer[1][1], 0, varn, 0, 0, STRING_DELIMITER, STRING_TAB);
         d=enterString(buffer[1][1], "Enter New Name>", STRING_TAB, STRING_DELIMITER, "\n");
         if(d!=0x1b)
         {
         sprintStringVar(buffer[1][2], 0, varn, 0, 1, STRING_DELIMITER, STRING_TAB);
         d=enterString(buffer[1][2], "Enter New Unit>", STRING_TAB, STRING_DELIMITER, "\n");
         if(d!=0x1b)
         {       
         sprintStringVar(buffer[0][1], 0, VAR_BATT+VAR_LDR-varn, 0, 0, STRING_DELIMITER, STRING_TAB);
         sprintStringVar(buffer[0][2], 0, VAR_BATT+VAR_LDR-varn, 0, 1, STRING_DELIMITER, STRING_TAB);
         sprintStringWelcome(buffer[2][0], STRING_DELIMITER, STRING_TAB);
         if(varn==VAR_BATT)
         {
         sprintf(buffer[0][3], "%s:%s:%s:%s:%s:", buffer[1][1], buffer[1][2], buffer[0][1], buffer[0][2], buffer[2][0]);
         } else sprintf(buffer[0][3], "%s:%s:%s:%s:%s:", buffer[0][1], buffer[0][2], buffer[1][1], buffer[1][2], buffer[2][0]);
            doDotsCommand("Entering Strings", ":");
            putSystemString(buffer[0][3], STRING_DELIMITER, &localerror);
             if(localerror==0)
             {
                printf("Ok.\n");
                finalSystemWrite++;
             } else printf("Error.\n");
         } else 
         {
                //printf("Action Cancelled.\n");   
            }
        } else { 
            //printf("\nAction Cancelled.\n");
            printf("\n");
        }
    } else
    {
        printf("No Parameters Can be Changed For this Variable.\n");   
    }
    }
    return 0;
}

DOUBLE changeMinAndMax(int vn, int index, int subindex)
{
       int valueshow;
       char buffer[6][NUM_VALUES][MAX_STRING_SIZE];
       int i, j;
       int c;
       int d;
       DOUBLE ftemp, gtemp;
       DWORD localerror;
       int varn;
       
       printf("\n");
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))
       { 
        getVarTypeString(buffer[0][0], varn);
        printf("Changing the Minimum, Maximum & Hysteresis Values for %s.\n", buffer[0][0]);
        if(varn<NUM_VARS)
        {
        j=0;
        for(i=0; i<NUM_VALUES; i++)
        {
        (void)getNameAndUnit(buffer[0][i], buffer[1][i], varn, i, NAME_TRUNCATION);
        sprintFDecimal(buffer[3][i], variable[varn].min[i], 3);
        sprintFDecimal(buffer[4][i], variable[varn].max[i], 3);
        sprintFDecimal(buffer[6][i], getHysteresisPercent(variable[varn].hysteresis), 2);
        getValueIndexString(buffer[5][i], varn, i);
        getOrderString(buffer[2][i], variable[varn].displayed[i]);
        sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-10.10s \n    Measures: %-32.32s Min: %-6.6s Max: %-6.6s Hysteresis: %-4.4s%c", j+0x61, buffer[0][i], buffer[1][i], buffer[5][i], buffer[3][i], buffer[4][i], buffer[6][i], '%');
        printf("%s\n", printBuffer);
        j++;
        }
        printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
        c=mygetch(&globalcontrolcode);
        printf("%c\n", c);
        if((c>='a')&&(c<=(0x60+j)))
        {
          c-='a';
         (void)getInput("The Minimum Value", buffer[1][c], FORMAT_F3, &variable[varn].min[c], &ftemp, &idF, &idF, 0, 0, 0, 0);
          if(variable[varn].min[c]!=ftemp)
          {
                variable[varn].min[c]=ftemp;
                variable[varn].cmptotal++;
            }
         (void)getInput("The Maximum Value", buffer[1][c], FORMAT_F3, &variable[varn].max[c], &ftemp, &idF, &idF, 0, 0, 0, 0);
         if(variable[varn].max[c]!=ftemp)
          {
                variable[varn].max[c]=ftemp;
                variable[varn].cmptotal++;
          }
          
          gtemp=getHysteresisPercent(variable[varn].hysteresis);
          (void)getInput("The Hysteresis Value", "%", FORMAT_F3, &gtemp, &ftemp, &idF, &idF, 0.0, (100.0*HYST_FULLSCALE), 0, 0);
          d=(int)inverseHysteresisPercent(ftemp);
          if(variable[varn].hysteresis!=d)
          {
                variable[varn].hysteresis=d;
                variable[varn].cmptotal++;
          }
          doDotsCommand("Entering New Values", ":");
          printf("Ok.\n");
        } else 
        {
            //printf("Action Cancelled.\n");
        }
    } 
    else if(varn==VAR_BATT)
    {
        
        
        
    } else printf("No Parameters Can be Changed For this Variable.\n");
    }
    return 0;
}

DOUBLE changeAcquisitionParametersVar(int vn, int index, int subindex)
{
       int valueshow;
       char buffer[MAX_STRING_SIZE];
       //
       int i, j, c, d, max, varn, cancel;
       BYTE channel, vartype, avgmode, valueindex;
       BYTE deltachannel, deltaavg, accchannel;
       DOUBLE ftemp, gtemp;
       DWORD localerror;
       BYTE targetindex, targetmode, targettype;
       //       
       cancel=0;
       // some fallback defaults
       vartype=variable[varn].type & 3;
       avgmode=variable[varn].mode & 1;
       channel=variable[varn].index & 7;
       valueindex=(variable[varn].type>>4) & 0x0f;
       deltachannel=(variable[varn].index>>7 ) & 1;
       deltaavg=(variable[varn].index>> 6 ) & 1;
       accchannel=(variable[varn].index>>4) & 3;
       //
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))  
       {
       getVarTypeString(buffer, varn);
       printf("\nChanging the Acquistion Parameters for %s.\n", buffer);
       if(varn<NUM_VARS)
       {    
        printf("\nChoose the New Type of the Variable:\n");
        vartype=chooseTypeOfVariable(4);
        if(vartype>=0)
        {
            if(vartype==ANALOG_VAR)
            {
             // analog var chosen
             max=3;
             channel=variable[varn].index & max;
             gtemp=(DOUBLE)channel;
             (void)getInput("The Physical Monitoring Channel", "", FORMAT_D, &gtemp, &ftemp, &idF, &idF, 0, max, 0, 0);
             channel=((int)ftemp) & max;

            } else
            if(vartype==FREQUENCY_VAR)
            {
             // frequency var chosen
             max=1;
             channel=variable[varn].index & max;
             gtemp=(DOUBLE)channel;
             (void)getInput("The Physical Monitoring Channel", "", FORMAT_D, &gtemp, &ftemp, &idF, &idF, 0, max, 0, 0);
             channel=((int)ftemp) & max;

            } else
            if(vartype==DEPENDENT_VAR)
            {
            // dependent var chosen
             printf("\nChoose which Variable This Variable Should Depend On:\n");
             channel=chooseVariable(NUM_UPDATE_VARS);
             if(channel>=0)
             {
             sprintStringVar(buffer, &variable[varn], varn, 0, VALUE_INDEX, STRING_DELIMITER, STRING_TAB);
             printf("\nChoose which Measurement %s Should Depend On:\n", buffer);
             j=0x60;
             for(i=0; i<NUM_VALUES; i++)
             {
             j++;
             printDisplayObject(j, channel, i);
             }
             printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
             c=mygetch(&globalcontrolcode);
             printf("%c\n", c);
             if((c>='a')&&(c<=j))
             {
                valueindex=c-'a';
                sprintStringVar(buffer, &variable[varn], varn, 1, VALUE_INDEX, STRING_DELIMITER, STRING_TAB);
                printf("\nChoose which Measurement %s Should Depend On:\n", buffer);
                j=0x60;
                for(i=0; i<NUM_VALUES; i++)
                {
                j++;
                printDisplayObject(j, channel, i);
                }
                printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", j);
                c=mygetch(&globalcontrolcode);
                printf("%c\n", c);
                if((c>='a')&&(c<=j))
                {
        
                  valueindex=((c-'a')<<2)&0x0C+(valueindex & 3);
                  targetindex=((accchannel<<4)& 0x30)+((deltachannel<<7)& 0x80)+((deltaavg<<6)& 0x40)+(channel & 0x0F);
                  // we need to update the channel here for later (only for dependent vars
                  // because of different semantics for the channel subfield in the index sub variable
                  if(variable[varn].index!=targetindex)
                  {
                  variable[varn].index=targetindex;
                  variable[varn].cmptotal++;
                  }
                } else cancel=1;
               } else cancel=1;
              } else cancel=1;
             } else
            {
            // silent var chosen
            }
        } else cancel=1;
     // the following are common settings to all variable types
     if(cancel==0)
     {
        printf("\n");
        if(vartype!=SILENT_VAR)
        {
         avgmode= variable[varn].mode & 1;
         gtemp=(DOUBLE)avgmode;
         (void)getInput("Acquisition Averaging Mode", "", FORMAT_B, &gtemp, &ftemp, &idF, &idF, 0, 2, 0, 0);
         avgmode=((int)ftemp) & 1;
         deltaavg=(variable[varn].index>>6) & 1;
         gtemp=(DOUBLE)deltaavg;
         (void)getInput("Averaging Mode on Delta/Integral Values", "", FORMAT_B, &gtemp, &ftemp, &idF, &idF, 0, 2, 0, 0);
         deltaavg=((int)ftemp) & 1;
         deltachannel=(variable[varn].index >> 7) & 1;
         d=chooseDeltaChannel(varn);
         if(d>=0)
         {
            deltachannel=d;
         } else cancel=1;
         accchannel=(variable[varn].index >> 4) & 3;
         d=chooseAccChannel(varn);
         if(d>=0)
         {
            accchannel=d;
         } else cancel=1;

        }
        else
        {
        // for silent var type use defaults!       

        }
     } 
     // now make the changes!
     if(cancel==0)
     {
        //
        targetindex=((accchannel<<4)& 0x30)+((deltachannel<<7)& 0x80)+((deltaavg<<6)& 0x40)+(channel & 0x0F);
        targetmode=(variable[varn].mode & 0xFE)+avgmode;
        targettype=((valueindex<<4)&0xF0)+(vartype & 3);
        // these are the targets!
        if(variable[varn].index!=targetindex)
        {
        variable[varn].index=targetindex;
        variable[varn].cmptotal++;
        }

        if(variable[varn].type!=targettype)
        {
        variable[varn].type=targettype;
        variable[varn].cmptotal++;
        }

        if(variable[varn].mode!=targetmode)
        {
        variable[varn].mode=targetmode;
        variable[varn].cmptotal++;
        }
     }
    // done!
    } else
    {
        printf("No Parameters Can be Changed For this Variable.\n");
        cancel=1;
    }
    }
    return 0;
}

DOUBLE changeDisplayParametersVar(int vn, int index, int subindex)
{
       int valueshow;
       DWORD error;
       char buffer[5][NUM_VALUES][MAX_STRING_SIZE];
       int i, j;
       int c;
       int d;
       DOUBLE ftemp, gtemp;
       DWORD localerror;
       int varn;
    
       varn=chooseVariable(NUM_UPDATE_VARS);
       if((varn>=0)&&(varn<NUM_UPDATE_VARS))
       {
       getVarTypeString(buffer[0][0], varn);
       printf("\nChanging the Display Parameters for %s.\n", buffer[0][0]);
              
       if(varn<NUM_VARS)
       {
        j=0;
        for(i=0; i<NUM_RAW; i++)
        {
        (void)getNameAndUnit(buffer[0][i], buffer[1][i], varn, i, NAME_TRUNCATION);
        getOrderString(buffer[2][i], variable[varn].displayed[i]);
        sprintf(printBuffer, "(%c) Name: %-32.32s Display Order: %s Number of Digits After Decimal Point: %d", j+0x61, buffer[0][i], buffer[2][i], variable[varn].decp[i]);
        printf("%s\n", printBuffer);
        j++;
        }
        printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
        c=mygetch(&globalcontrolcode);
        printf("%c\n", c);
        if((c>='a')&&(c<=(0x60+j)))
        {
          c-='a';
          gtemp=(DOUBLE)variable[varn].decp[c];
         (void)getInput("The Number of Digits After Decimal Point", " digits", FORMAT_D, &gtemp, &ftemp, &idF, &idF, 0, 3, 0, 0);
          if(variable[varn].decp[c]!=(int)ftemp)
          {
                variable[varn].decp[c]=(int)ftemp;
                variable[varn].cmptotal++;
          }
          doDotsCommand("Entering New Values", ":");
          printf("Ok.\n");
        } else {
            //printf("Action Cancelled.\n");
        }
    } else
    if((varn==VAR_BATT)||(VAR_LDR))
    {
        //putIn
        //  {RS,  0, "systemDecp",          "No. of Digits After Decimal Point",  "",       FORMAT_D,     (BYTE*)&systemDecp,            SIZEAUTO,    0, 6,          0, 0,    SYSTEMDECP_ADR,      &idShowF,             &idF,              &idF, &idSetF, 0 },
        putInfoSystemVarName("systemDecp", (SYSTEMVAR*)systemSystem, &error);
    } else printf("No Parameters Can be Changed For this Variable.\n");
    }
    return 0;
}

int chooseSensorType(int varn)
{
    // for variable varn, choose the sensor type
    int j, i;
    char buffer[3][NUM_VALUES][MAX_STRING_SIZE];
    char c;
    
    j=0;
    for(i=0; i<NUM_RAW; i++)
    {
    (void)getNameAndUnit(buffer[0][i], buffer[1][i], varn, i, NAME_TRUNCATION);
    getValueIndexString(buffer[2][j], varn, i);
    sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-16.16s \n    Measures: %-32.32s", j+0x61, buffer[0][i], buffer[1][i], buffer[2][i]);
    printf("%s\n", printBuffer);
    j++;
    }
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<=(0x60+j)))
    {
        return c-'a';
    } else {
        //printf("Action Cancelled.\n");
    }
    return -1;
}

int chooseValueIndex(int varn, int min, int max)
{
    // for variable varn, choose the value index sub menu...
    int j, i;
    char buffer[5][NUM_VALUES][MAX_STRING_SIZE];
    char c;
    
    j=0;
    for(i=min; i<max; i++)
    {
    (void)getNameAndUnit(buffer[0][i], buffer[1][i], varn, i, NAME_TRUNCATION);
    sprintFDecimal(buffer[3][i], variable[varn].min[i], 3);
    sprintFDecimal(buffer[4][i], variable[varn].max[i], 3);
    getOrderString(buffer[2][i], variable[varn].displayed[i]);
    getValueIndexString(buffer[5][i], varn, i);
    sprintf(printBuffer, "(%c) Name: %-36.36s Unit: %-16.16s \n    Measures: %-32.32s Display Order: %-6.6s Minimum: %-10.10s Maximum: %-10.10s", j+0x61, buffer[0][i], buffer[1][i], buffer[5][i], buffer[2][i], buffer[3][i], buffer[4][i]);
    printf("%s\n", printBuffer);
    j++;
    }
    printf("Press (a)-(%c) to Select One of the Above. (Any Other Key to Cancel)> ", 0x60+j);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<=(0x60+j)))
    {
        return c-'a';
    } else 
    { 
        //printf("Action Cancelled.\n"); 
    }
    
    return -1;
}

int chooseInterpolationDegree(int defaultdeg)
{
    char c;
    int result;
    char buffer[2][MAX_STRING_SIZE];
    int temp;
    
    result=-1;
    printf("Can the Sensor Function be best approximated by:\n");
    printf("(a) A Linear Function Through the Origin (A Scaling Transformation)\n");
    printf("(b) A Linear Function Not Passing Through the Origin\n");
    printf("(c) A Quadratic or Higher Degree Polynomial\n");
    printf("Press (a)-(c) to Select One of the Above. (Any Other Key to Cancel)> ");
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c>='a')&&(c<='c'))
    {
     if(c=='a')
     {
        result=0;
        } else
        if(c=='b')
        {
        result=1;
        } else
        if(c=='c')
        {
        sprintf(&buffer[1][0],"Enter the Required Degree (>=2)>");
        sprintf(&buffer[0][0],"%d", defaultdeg);
        enterString(&buffer[0][0], &buffer[1][0], MAX_STRING_SIZE, STRING_DELIMITER, "\n");
        sscanf(&buffer[0][0], "%d", (int*)&temp);
        if(temp<2)temp=2; else if(temp>(MAX_POLY-1))temp=MAX_POLY-2;
        result=temp;
        }
    } else 
    {
        result=-1;
    }
    return result;
}

int chooseCommit(char *instr)
{
    // returns 1 if yes or 0 if no or -1 if cancel
    char c;
        
    sprintf(printBuffer, "%s (Y)es/(N)o", instr);
    sdoDots(printBuffer, printBuffer, COMMAND_TAB, '.');
    sprintf(printBuffer, "%s> ", printBuffer);
    printf("%s", printBuffer);
    c=mygetch(&globalcontrolcode);
    printf("%c\n", c);
    if((c=='Y')||(c=='y'))
    {
        return 1;
    } else
    if((c==0x0D)||(c=='N'))
    {
        return 0;
    } else
    return -1;
}

void copyFreezePoints(int varn, int index, int start, int end)
{
    int i, k;
    k=0; 
    for(i=start; i<end; i++)
    {
        freezePoints[i].raw[index]=variable[varn].calibrationPoints[i][index][0];
        freezePoints[i].value[index]=variable[varn].calibrationPoints[i][index][1];
    k++;
    }
}

void putFreezePoints(int varn, int index, int start, int end)
{
    int i, k;
        
    k=0; 
    for(i=start; i<end; i++)
    {
        variable[varn].calibrationPoints[i][index][0]=freezePoints[i].raw[index];
        variable[varn].calibrationPoints[i][index][1]=freezePoints[i].value[index];
    k++;
    }
    variable[varn].numCalibrationPoints[index]=k;    
}

DOUBLE manualCalibration(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;

    loadCalibrationPointsWithPolynomialData();
    variable[varn].numCalibrationPoints[ind]=0; 
    printf("\nChoose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
    printf("\nStarting Calibration Sequence...\n");
    nn=chooseInterpolationDegree(2);
    if((nn>=0)&&(nn<(MAX_POLY-1)))
    {    
        mm=nn+1;
        j=getManualFreezePoints(varn, zz, 0, mm, &localerror);
        if(j>0)
        {
        // j is now the number of calibration points captured...
        // now copy the freezepoint information to the variable, calibration points, etc
        putFreezePoints(varn, zz, 0, j);
        // now compute the polynomial
        deg=computePolynomial(varn, zz, nn);
        doDotsCommand("No. of Calibration Points Accepted.", ":");
        printf("%d\n", j);
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
        handleInsertPolynomialError(localerror);
        if(localerror==0)
        { 
            polyUpdate++;
            updatePolyMemory(&localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
             }
            }
         }
        } 
        else
        {
            printf("Polynomial Discarded.\n");
        }          
        } else 
        {
            //printf("Action Cancelled.\n"); 
        }
    } else 
    {
        //printf("Action Cancelled.\n");
    }
    } else printf("Bad Interpolation Degree.\n"); 
    return 0;
}

DOUBLE calibrateNewSensor(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;

    loadCalibrationPointsWithPolynomialData();
    variable[varn].numCalibrationPoints[ind]=0; 
    printf("\nChoose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
    printf("\nStarting Calibration Sequence...\n");
    nn=chooseInterpolationDegree(2);
    if((nn>=0)&&(nn<(MAX_POLY-1)))
    {    
        mm=nn+1;
        j=getFreezePoints(varn, zz, 0, mm, &localerror);
        if(j>0)
        {
        // j is now the number of calibration points captured...
        // now copy the freezepoint information to the variable, calibration points, etc
        putFreezePoints(varn, zz, 0, j);
        // now compute the polynomial
        deg=computePolynomial(varn, zz, nn);
        doDotsCommand("No. of Calibration Points Accepted.", ":");
        printf("%d\n", j);
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
        handleInsertPolynomialError(localerror);
        if(localerror==0)
        { 
            polyUpdate++;
            updatePolyMemory(&localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
             }
            }
         }
        } 
        else
        {
            printf("Polynomial Discarded.\n");
        }          
        } else 
        {
            //printf("Action Cancelled.\n"); 
        }
    } else 
    {
        //printf("Action Cancelled.\n");
    }
    } else printf("Bad Interpolation Degree.\n"); 
    return 0;
}

DOUBLE calibrateImportNewSensor(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;
    char filename[MAX_STRING_SIZE];
    int d;
    //
    loadCalibrationPointsWithPolynomialData();
    variable[varn].numCalibrationPoints[ind]=0;
    //
    printf("\nStarting Calibration Sequence from Imported File.\n");
    printf("Choose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
    printf("\n");
    sprintf(filename, "default.csv");
    d=enterString(filename, "Enter Filename>", STRING_TAB, STRING_DELIMITER, "\n");
    if(d==0x1b)return 1;
    printf("Importing Calibration Points File: %s. Begin:\n", filename);
    j=importCalibrationPoints(filename, varn, zz, 0, &localerror);
    printf("\n");
    if(j>0)
    {
        // j is now the number of calibration points captured...
        // now compute the polynomial, ask for degree, default
        printf("Number of Calibration Points Loaded from File: %d\n\n", j);
        nn=chooseInterpolationDegree(variable[varn].numCalibrationPoints[zz]-1);
        deg=computePolynomial(varn, zz, nn);
        printf("\n");
        doDotsCommand("No. of Calibration Points Accepted.", ":");
        printf("%d\n", deg+1);
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        //printf("polytemp[0] pointer is: %d\n", (int)&polyTemp[0]);
        insertPolynomial(varn, zz, (deg+1), (DOUBLE*)&polyTemp[0], &localerror);
        //printf("Reached Here Two.\n");
        handleInsertPolynomialError(localerror);
          if(localerror==0)
          { 
            polyUpdate++;
            updatePolyMemory(&localerror);
            //printf("Updated Localerror: 0x%x\n", localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
             } else localerror=0; 
             //printf("Going to Update at interpolation: %d.\n", variable[varn].interpolation[zz]);
             updateVariable(varn, &localerror);
             // showVariableInfoNice(varn);
             // showVariableInfo(varn, 0x0F, 0x0F, 0xFF);
             renormalizeSensorInternal(varn, zz, 0);
            }
          }
         } 
         else
         {
            printf("Polynomial Discarded.\n");
         }          
        } else 
        if(j<0)
        {
            printf("File Not Found. No Points Loaded.\n");
        } else
        {
            printf("No Points Loaded.\n");
        }
      } else 
      { 
            printf("Action cancelled.\n");
      }
    return 0;
}

DOUBLE calibrateImportAddSensor(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;
    char filename[MAX_STRING_SIZE];
    int d;
    int start;
    //
    loadCalibrationPointsWithPolynomialData();
    printf("\nAdding Calibration Points from Imported File.\n");
    printf("Choose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
    printf("\n");
    sprintf(filename, "default.cal");
    d=enterString(filename, "Enter Filename>", STRING_TAB, STRING_DELIMITER, "\n");
    if(d==0x1b)return 1;
    printf("Importing Calibration Points File: %s. Begin:\n", filename);
    start=variable[varn].numCalibrationPoints[zz];
    j=importCalibrationPoints(filename, varn, zz, start, &localerror);
    printf("\n");
    if(j>0)
    {
        // j is now the number of calibration points captured...
        // now compute the polynomial, ask for degree, default
        printf("Number of Calibration Points Loaded from File: %d\n\n", j);
        nn=chooseInterpolationDegree((variable[varn].numCalibrationPoints[zz]-1));
        deg=computePolynomial(varn, zz, nn);
        printf("\n");
        doDotsCommand("No. of Calibration Points Accepted.", ":");
        printf("%d\n", deg+1);
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
        handleInsertPolynomialError(localerror);
          if(localerror==0)
          { 
            polyUpdate++;
            updatePolyMemory(&localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
             }
            }  
          }
         } 
         else
         {
            printf("Polynomial Discarded.\n");
         }          
        } else 
        if(j<0)
        {
            printf("File Not Found. No Points Loaded.\n");
        } else
        {
            printf("No Points Loaded.\n");
        }
      } else 
      { 
            printf("Action cancelled.\n");
      }
    return 0;
}

DOUBLE enterPolynomialManual(int varn, int ind, int subindex)
{
    int zz, mm, aa, i, j, deg;
    DWORD localerror;
    char buffer[MAX_STRING_SIZE];
    int syntaxptr;
    int errptr;

    printf("\nChoose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
        sprintPolynomialInternal((char*)&buffer[0], varn, zz);
        mm=enterString((char*)&buffer[0], "Enter New Polynomial>", MAX_STRING_SIZE, STRING_DELIMITER, "\n");
        if(mm!=0x1b)
        {
        localerror=getPolynomialPtr((char*)&buffer[0], (DOUBLE*)&polyTemp[0], MAX_POLY, &deg, &syntaxptr);        
        if(localerror==0)
        {
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
        handleInsertPolynomialError(localerror);
        if(localerror==0)
        { 
            polyUpdate++;
            updatePolyMemory(&localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
              }
            }
        }
        }
        else
        {
            printf("Polynomial Discarded.\n");
        }  
        } else 
        {
        printf("Entered String : %s\n", buffer);
        printf("Syntax Error At: ");
        errptr=syntaxptr;
        //printf("Syntaxptr: %d Adr: %d Errptr: %d\n", (int)syntaxptr, (int)&buffer[0], errptr);
        while(errptr>0)
        {
            printf(" ");
            errptr--;
        }
        printf("^\n");
    }
    } else 
    {
        //printf("\nAction Cancelled.\n"); 
        printf("\n");
    }
    } else
    {
        // printf("Action Cancelled.\n");
    }
    return 0;
}

DOUBLE enterScalingFactorsDeltaIntegral(int varn, int ind, int subindex)
{
    int i, j;
    char buffer[8][MAX_STRING_SIZE];
    DOUBLE gtemp, ftemp;
    int d;
    int deltachannel;
    //
    deltachannel=(variable[varn].index >> 7 ) & 1;
    sprintStringVar(buffer[2], &variable[varn], varn, deltachannel , VALUE_INDEX, STRING_DELIMITER, VALUE_TAB );
    sprintStringVar(buffer[3], &variable[varn], varn, deltachannel, UNIT_INDEX, STRING_DELIMITER, VALUE_TAB);
    //      
    (void)getVarTypeString(buffer[0], varn);
    printf("\nChanging the Scaling Factors for Delta/Integral Values of %s.\n", buffer[0]);
    printf("Delta/Integral Values Currently Apply To:\nName: %36.36s ", buffer[2]);
    printf("(Unit: %-10.10s)\n", buffer[3]);
    printf("Change the Variable's Type & Acquisition Parameters    \n");
    printf("to Change the Value that the Delta/Integral Applies to.\n");
    printf("eg: use -v Option to Access the Variable Menu. \n\n");
    //                   
    i=0;
    d=0;
    while((d!=0x1b)&&(i<NUM_RAW))
    {
    sprintFDecimal(buffer[0], variable[varn].scaling[i], 3);
    (void)getNameAndUnit(buffer[4], buffer[5], varn, DELTA_INDEX+i, NAME_TRUNCATION);
    getValueIndexString(buffer[6], varn, DELTA_INDEX+i);
    sprintf(printBuffer, "Name: %36.36s Unit: %-16.16s \nMeasures: %-32.32s", buffer[4], buffer[5], buffer[6]);
    printf("%s\n", printBuffer);
    gtemp=(DOUBLE)variable[varn].scaling[i];
    d=getInput("Scaling Factor", "", FORMAT_F6, &gtemp, &ftemp, &idF, &idF, 0, 0, 0, 0);
    if((d!=0x1b)&&(ftemp!=variable[varn].scaling[i]))
    {
        variable[varn].scaling[i]=ftemp;
        variable[varn].cmptotal++;
    }
    i++;
    }
    printf("\n");
    return 0;
}

int writePolynomialToFile(char* filename1, char *polynomialString, DOUBLE min, DOUBLE max, DOUBLE samples, DOUBLE* polynomial, int deg)
{
    ofstream myfile;
    int i,j;
    DOUBLE x, y;
    DOUBLE step;

    step=((max-min)/samples);   
    myfile.open(filename1, ios::trunc);
    myfile << "Dumping Polynomial: " << polynomialString << ", Samples: " << samples << "\n";
    myfile << "X-Value, Y-Value\n";
    x=min;
    for(j=0; j<=samples; j++)
    {
    myfile.setf(ios::fixed,ios::floatfield);   // floatfield set to fixe
    myfile.precision(3);
    y=computePolynomialValue(polynomial, deg, x);
    myfile << x << "," << y << "\n";
    x+=step;
    }
    myfile.close();
    return (samples+1);
}

DOUBLE dumpPolynomial(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;
    char buffer[MAX_STRING_SIZE];
    char filename[MAX_STRING_SIZE];
    int syntaxptr;
    int errptr;
    //
    printf("\nChoose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
        sprintPolynomialInternal((char*)&buffer[0], varn, zz);
        printf("The Current Polynomial Is: %s\n", buffer);
        sprintf(filename, "polynomialDump%d(%d)", varn, zz);
        (void)enterString((char*)&filename[0], "Enter Filename>", MAX_STRING_SIZE, STRING_DELIMITER, "\n");
        if(filename[0]!=0)
        { 
        sprintf(filename, "%s.csv", filename);
        deg=copyVarPolynomial((DOUBLE*)&polyTemp[0], varn, zz);
        // 10 bit ADC so output 1024 samples!
        aa=writePolynomialToFile(filename, buffer, 0.0, (battRef/VOLTAGEREF), 1023.0, &polyTemp[0], deg);
        sprintf(printBuffer, "Dumping Polynomial To File: %s. Total Written", filename);
        doDotsSys(printBuffer, ":");
        printf("%d Samples\n", aa);
        } else printf("Bad File Name.\n");
    } else
    {
        // printf("Action Cancelled.\n"); 
    }
    return 0;
}

int chooseNumber(char* question, int defaultnum, int min, int max)
{
    char buffer[2][MAX_STRING_SIZE];
    int temp, result;
    
    sprintf(&buffer[1][0],"%s", question);
    sprintf(&buffer[0][0],"%d", defaultnum);
    enterString(&buffer[0][0], &buffer[1][0], MAX_STRING_SIZE, STRING_DELIMITER, "\n");
    sscanf(&buffer[0][0], "%d", (int*)&temp);
    if(temp<min)temp=min; else if(temp>max)temp=max-1;
    result=temp;
    return result;
}

DOUBLE calibrateAddSensor(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;

    loadCalibrationPointsWithPolynomialData();
    printf("\nChoose the Sensor Type:\n");
    zz=chooseSensorType(varn);
    if(zz>=0)
    {
    printf("Starting Calibration Sequence...\n");
    nn=chooseNumber("Enter Number of Additional Points Required>", 1, 1, MAX_POLY-1);
    if((nn>=1)&&(nn<(MAX_POLY-1)))
    {    
        mm=nn;
        printf("Number of Calibration Points: %d\n", variable[varn].numCalibrationPoints[zz]);
        copyFreezePoints(varn, zz, 0, variable[varn].numCalibrationPoints[zz]);
        j=getFreezePoints(varn, zz, variable[varn].numCalibrationPoints[zz], mm, &localerror);
        if(j>0)
        {
        // j is now the number of calibration points captured...
        // now copy the freezepoint information to the variable, calibration points, etc
        putFreezePoints(varn, zz, 0, j);
        // now compute the polynomial
        deg=computePolynomial(varn, zz, nn);
        doDotsCommand("No. of Calibration Points Accepted.", ":");
        printf("%d\n", variable[varn].numCalibrationPoints[zz]);
        doDotsCommand("The New Polynomial Is", ":");
        //showPolyTemp(deg);
        printPolynomialPtr(&polyTemp[0], deg);
        printf("\n");    
        aa=chooseCommit("Do you Wish to Commit This Polynomial?");
        if(aa==1)
        {
        doDotsCommand("Attempting to Insert Polynomial",":");
        insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
        handleInsertPolynomialError(localerror);
        if(localerror==0)
        {
            polyUpdate++;
            updatePolyMemory(&localerror);
            if(localerror==0)
            {
             if(variable[varn].interpolation[zz]!=deg)
             {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
              }
            }
        }
        
        } 
        else
        {
            printf("Polynomial Discarded.\n");
        }          
        } else 
        {
         //   printf("Action Cancelled.\n"); 
        }
    } else
    {
        // printf("Action Cancelled.\n");
    }
    } else printf("Bad Interpolation Degree.\n"); 
    return 0;
}

DOUBLE renormalizeSensor(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;
    double alpha, x0, q0;
    int result;

    // this menu allows you to adjust a previously stored (computed)
    // polynomial on a variable for a new horizontal scale (ie X scale)
    // for eg. you may want to do this if you changed the input resistors
    // on an analog channel (the divider resistors) or if you tweaked the
    // the supply reference value since last calibrating the sensor on that
    // channel. This needs to be done only for analog or resistance type
    // variables.
    // what happens is that an alpha value is found such that
    // p(x) the previously computed polynomial becomes q(x) such that
    // q(x)=p(x.alpha) where alpha is a constant and the user must input
    // one calibration point (x0, q0) so that
    // q(x0)=q0=p(alpha.x0).
    // then recomputes the polynomial so that if the existing polynomial was
    // p(x)=a_n x^n + ... + a_0 then the new polynomial will be:
    // p'(x)= a_n*alpha^n x^n + ... + a_0 so that it is the case that:
    // p'(x0)=p(alpha.x_0)=q0 !
    //
    if(varn<ANALOG_VARS)
    {

        printf("\nChoose the Sensor Type:\n");
        zz=chooseSensorType(varn);
        if(zz>=0)
        {
        printf("Starting Horizontal Scale Adjustment. One Calibration Point Is Required..\n");
        j=getFreezePoints(varn, zz, 0, 1, &localerror);
         if(j>0)
         {
             // copy the variable's polynomial to polytemp
             deg=copyVarPolynomial((DOUBLE*)&polyTemp[0], varn, zz);
             if(deg>0)
             {
             // now find the corresponding alpha!
             x0=freezePoints[0].raw[zz];
             q0=freezePoints[0].value[zz];
             alpha=findAlpha((DOUBLE*)&polyTemp[0], deg, x0, q0, 0.00000001, 100.0, &result);
             if(result==0)
             {
             printf("Operation Did Not Converge but Timed Out. \n");
             printf("Try Again with Different X-Value as the Calibration Point.\n");
             } else
             {
             printf("\nAlpha Value Found: %6.6f Corresponding to a Horizontal Scale Adjustment of: %2.2f %c\n", alpha, 100.0*(alpha-1.0), '%');
             printf("\nThe Original Polynomial Was: ");
             printPolynomial(varn, zz);
             printf("\n");
             computeAlphaPolynomial((DOUBLE*)&polyTemp[0], deg, alpha);
             printf("\nThe Adjusted Polynomial Is : ");
             printPolynomialPtr(&polyTemp[0], deg);
             printf("\n");
             aa=chooseCommit("\nDo you Wish to Commit This Polynomial?");
             if(aa==1)
             { 
             doDotsCommand("Attempting to Insert Polynomial",":");
             insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
             handleInsertPolynomialError(localerror);
             if(localerror==0)
             {
              polyUpdate++;
              updatePolyMemory(&localerror);
              if(localerror==0)
              {
               if(variable[varn].interpolation[zz]!=deg)
               {
               variable[varn].interpolation[zz]=deg;
               variable[varn].cmptotal++;
               }
              }
             }
            } 
            else
            {
            printf("Polynomial Discarded.\n");
            }          
             }
             } else 
             {
             printf("This Action Cannot Be Performed on a Scaling Transformation.\n");
             printf("You Should Calibrate This Variable for a New Sensor Instead.\n");
             }
         } else
         {
                // printf("Action Cancelled.\n");     
            }
        } else
        {
            // printf("Action Cancelled.\n");    
        }
    } else printf("This Action Only Applies to Voltage/Resistance Variables.\n"); 
    return 0;
}

DOUBLE renormalizeSensorInternal(int varn, int ind, int subindex)
{
    int zz, nn, mm, aa, i, j, deg;
    DWORD localerror;
    double alpha, x0, q0;
    int result;

    // this menu allows you to adjust a previously stored (computed)
    // polynomial on a variable for a new horizontal scale (ie X scale)
    // for eg. you may want to do this if you changed the input resistors
    // on an analog channel (the divider resistors) or if you tweaked the
    // the supply reference value since last calibrating the sensor on that
    // channel. This needs to be done only for analog or resistance type
    // variables.
    // what happens is that an alpha value is found such that
    // p(x) the previously computed polynomial becomes q(x) such that
    // q(x)=p(x.alpha) where alpha is a constant and the user must input
    // one calibration point (x0, q0) so that
    // q(x0)=q0=p(alpha.x0).
    // then recomputes the polynomial so that if the existing polynomial was
    // p(x)=a_n x^n + ... + a_0 then the new polynomial will be:
    // p'(x)= a_n*alpha^n x^n + ... + a_0 so that it is the case that:
    // p'(x0)=p(alpha.x_0)=q0 !
    //
    if(varn<ANALOG_VARS)
    {
        zz=ind;
        if(zz>=0)
        {
        printf("Starting Horizontal Scale Adjustment. One Calibration Point Is Required..\n");
        j=getFreezePoints(varn, zz, 0, 1, &localerror);
         if(j>0)
         {
             // copy the variable's polynomial to polytemp
             deg=copyVarPolynomial((DOUBLE*)&polyTemp[0], varn, zz);
             if(deg>0)
             {
             // now find the corresponding alpha!
             x0=freezePoints[0].raw[zz];
             q0=freezePoints[0].value[zz];
             alpha=findAlpha((DOUBLE*)&polyTemp[0], deg, x0, q0, 0.00000001, 100.0, &result);
             if(result==0)
             {
             printf("Operation Did Not Converge but Timed Out. \n");
             printf("Try Again with Different X-Value as the Calibration Point.\n");
             } else
             {
             printf("\nAlpha Value Found: %6.6f Corresponding to a Horizontal Scale Adjustment of: %2.2f %c\n", alpha, 100.0*(alpha-1.0), '%');
             printf("\nThe Original Polynomial Was: ");
             printPolynomial(varn, zz);
             printf("\n");
             computeAlphaPolynomial((DOUBLE*)&polyTemp[0], deg, alpha);
             printf("\nThe Adjusted Polynomial Is : ");
             printPolynomialPtr(&polyTemp[0], deg);
             printf("\n");
             aa=chooseCommit("\nDo you Wish to Commit This Polynomial?");
             if(aa==1)
             { 
             doDotsCommand("Attempting to Insert Polynomial",":");
             insertPolynomial(varn, zz, deg+1, (DOUBLE*)&polyTemp[0], &localerror);
             handleInsertPolynomialError(localerror);
             if(localerror==0)
             {
              polyUpdate++;
              updatePolyMemory(&localerror);
              if(localerror==0)
              {
              if(variable[varn].interpolation[zz]!=deg)
              {
              variable[varn].interpolation[zz]=deg;
              variable[varn].cmptotal++;
              }
              }
             }
            } 
            else
            {
            printf("Polynomial Discarded.\n");
            }          
             }
             } else 
             {
             printf("This Action Cannot Be Performed on a Scaling Transformation.\n");
             printf("You Should Calibrate This Variable for a New Sensor Instead.\n");
             }
         } else
         {
                // printf("Action Cancelled.\n");     
            }
        } else
        {
            // printf("Action Cancelled.\n");    
        }
    } else printf("This Action Only Applies to Voltage/Resistance Variables.\n"); 
    return 0;
}

MENU calibrateVariableSubMenu[]=
{
    {"Calibrate the Variable for a New Sensor", &calibrateNewSensor },
    {"Add Calibration Points to Existing Variable",&calibrateAddSensor },
    {"Adjust Variable For New Horizontal Scale (X-scale)", &renormalizeSensor },
    {"Perform a Manual Calibration", &manualCalibration },
    {"Enter a Polynomial Manually", &enterPolynomialManual },
    {"Adjust Scaling For Delta/Integral Unit Conversion", &enterScalingFactorsDeltaIntegral },
    {"Dump Polynomial To SpreadSheet", &dumpPolynomial },
    {"Import Calibration Points for New Sensor From File", &calibrateImportNewSensor },
    {"Import Additional Calibration Points to Existing Variable From File", &calibrateImportAddSensor },
   // {"Export Sensor Calibration Points to File", &notImplemented },
    {"", &idActionF }
};

DOUBLE calibrateVariableMainMenu(int varn, int index, int subindex)
{
       int valueshow;
       DWORD error;
       char buffer[5][NUM_VALUES][MAX_STRING_SIZE];
       int i, j;
       int c;
       int d;
       int zz, yy;
       DOUBLE ftemp, gtemp;
       DWORD localerror;
    
       printf("\nPerforming Calibration on a Variable.\n");
       zz=chooseVariable(NUM_VARS);
       if((zz>=0)&&(zz<NUM_VARS))
       {
        getVarTypeString(buffer[0][0], zz);
        printf("\nPerforming Calibration for %s.\n", buffer[0][0]);     
        printf("Select From the Following:\n");
        yy=chooseMenu(&calibrateVariableSubMenu[0]);
        if(yy>=0)
        {
        calibrateVariableSubMenu[yy].actionF(zz, 0, 0);                      
        } else
        {
            // printf("Action Cancelled.\n");
        }
       } else
       {
             //printf("Action Cancelled.\n");
		}
       return 0;
}

DOUBLE calibrateSupplyRefManual(int varn, int index, int subindex)
{
       DWORD error;
       //    
       printf("\n");
       printf("Calibrating the ADC System Manually.\n");
       printf("Note: This will Require Re-Adjusting All Polynomials For Voltage/Resistance Variables\n");
       printf("      For a New Horizontal Scale (X-scale). Type cardisplay -c to Enter the\n");
       printf("      Calibration Menu. Choose to Perform Calibration on a Variable, then\n");
       printf("      Choose the Variable and Then the:\n");
       printf("      Adjust For a New Horizontal Scale (X-scale) option.\n");
       printf("\n");
       printf("Measure the +5V Rail At Pin 1 of CON3 and Enter the Measured Reading.\n");
       putInfoSystemVarTitle("Supply Reference", (SYSTEMVAR*)systemSystem, &error);
       showSystemVar("Supply Reference");
       return 0;
}

/*
DOUBLE calibrateSupplyRefAuto(int varn, int index, int subindex)
{
       DWORD error, totalerror;
       int aa, abort;
       DOUBLE value, abortvalue;
       //       
       abort=0;
       printf("\n");      
       printf("Calibrating the ADC System Automatically.\n");
       printf("Note: This will Require Re-Adjusting All Polynomials For Voltage/Resistance Variables\n");
       printf("      For a New Horizontal Scale (X-scale). Type cardisplay -c to Enter the\n");
       printf("      Calibration Menu. Choose to Perform Calibration on a Variable, then\n");
       printf("      Choose the Variable and Then the:\n");
       printf("      Adjust For a New Horizontal Scale (X-scale) option.\n");
       printf("\n");
       printf("Connect the +5V Rail At Pin 1 of CON3 to the Battery Sense Input At Pin 4 of CON1 using a Resistor R.\n");
       aa=chooseCommit("Have You Connected the +5V Rail to the Battery Sense Input via R?");
       if(aa==1)
       {
            aa=chooseCommit("Do You Want to Automatically Adjust the Supply Reference?  ");
            if(aa==1)
            {
              abortvalue=battRef;
              abort=1;
              putInfoSystemVarTitleDouble("Supply Reference", (SYSTEMVAR*)systemSystem, VOLTAGEREF, &error);
              doDotsCommand("Reading +5V Rail Voltage",":\r");
              startt=clock();
              timeElapsed=0;
              while((!kbhit())&&(timeElapsed<AUTO_DELAY))
              {
              endt=clock();
              timeElapsed=(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
              doDotsCommand("Reading +5V Rail Voltage", ":");
              printf("%-3.1f sec.\r", AUTO_DELAY+0.1-timeElapsed);
              DelayMs(100);
              }
              getInfoSystemVarName("battLevel", (SYSTEMVAR*)systemSystem, &error);
              totalerror=error;
              if(totalerror==0)
              {
              printf("BattLevel is %d \n", battLevel);
              getInfoSystemVarTitle("Battery Voltage", (SYSTEMVAR*)systemSystem, &error);
              doDotsCommand("Reading +5V Rail Voltage At Battery Sense Input", ":");
              printf("%-3.1f V             \n", battVoltage);
              if((battVoltage>=MINREFV)&&(battVoltage<=MAXREFV))
              {
              doDotsCommand("Correcting the Supply Reference",":");
              putInfoSystemVarTitleDouble("Supply Reference", (SYSTEMVAR*)systemSystem, battVoltage, &error);
              if(error==0)
              {
                printf("Ok.\n");
                abort=0;
                } else printf("Error.\n");
                
                } else
                {
                printf("Measured Voltage Out Of Range. Aborting Calibration.\n");
                }
              } else printf("Error.\n");
            } else
            {
                // printf("Action Cancelled.\n");
            }
       } else 
       {
            //printf("Action Cancelled.\n");
        }
       
       printf("You Can Now Disconnect the +5V Rail Voltage At the Battery Sense Input.\n");
       if(abort==1)putInfoSystemVarTitleDouble("Supply Reference", (SYSTEMVAR*)systemSystem, abortvalue, &error);
       return 0;
}
*/

DOUBLE changeLoggingParameters(int varn, int index, int subindex)
{
       int valueshow;
       char buffer[MAX_STRING_SIZE];
       int i, j;
       int c;
       int d;
       int type;
       int channel;
       DOUBLE ftemp, gtemp;
       DWORD localerror;
       int max;
       int logmask;
       int logminmax, logacc;
       BYTE vartype;
       //
       printf("\n");
       varn=chooseVariable(NUM_UPDATE_VARS);
       getVarTypeString(buffer, varn);
       printf("\nChanging the Logging Parameters For %s.\n", buffer);
       vartype=variable[varn].type & 3;
       //
       if(varn<NUM_VARS)
       {
       if((vartype==DEPENDENT_VAR)||(vartype==ANALOG_VAR)||(vartype==FREQUENCY_VAR))       
       {
         i=chooseLogObject(varn);
         if(i>=0)
         {
            if(i<NUM_VALUES)
            {
            logmask=(0x10<<i);
            variable[varn].mode^=(BYTE)logmask;
            variable[varn].cmptotal++;
            }
            printf("The New Settings Are:\n");
            for(j=0; j<NUM_VALUES;j++)
            {
            printLogObject('*', varn, j);
            }
            if((variable[varn].mode & MODE_LOGMASK)!=0)
            {
            // if at least one is enabled...
            logacc=(variable[varn].mode & MODE_LOGACC)>>3;
            gtemp=(DOUBLE)logacc;
            (void)getInput("Accumulator Logging", "", FORMAT_B, &gtemp, &ftemp, &idF, &idF, 0, 2, 0, 0);
            if(((int)ftemp)!=logacc)
            {
             variable[varn].mode^=(BYTE)(MODE_LOGACC);
             variable[varn].cmptotal++;
            }
            logminmax=(variable[varn].mode & MODE_LOGMINMAX)>>2;
            gtemp=(DOUBLE)logminmax;
            (void)getInput("Min. and Max. Condition Logging", "", FORMAT_B, &gtemp, &ftemp, &idF, &idF, 0, 2, 0, 0);
            if(((int)ftemp)!=logminmax)
            {
             variable[varn].mode^=(MODE_LOGMINMAX);
             variable[varn].cmptotal++;
            }
            }
          } else
          {
                // printf("Action Cancelled.\n");
            }
         } else
        {
        // silent var    
        printf("Silent Variables Cannot Be Logged.\n");
        }
    } else
    {
    printf("No Parameters Can be Changed For this Variable.\n");
    }
    return 0;
}

int putInfo(SYSTEMVAR* inptr, int prioritymin, int prioritymax, DWORD* err)
{
    // writes the system information
    int exit;
    DWORD error, pA;
    DWORD totalerror;

    totalerror=0;
    exit=0;
    while((exit==0)&&(totalerror==0))
    {
     if(inptr->type==END_TYPE)exit=1;
     else
     if((inptr->type & WR_TYPE)!=0)
     {
        if((inptr->priority>=prioritymin)&&(inptr->priority<=prioritymax))
        {
        putInfoSystemVar(inptr, &error);
        totalerror|=error;
        }
     }
   
/*
  	// for these variables, the extra function pointer is used to post process, as callback
     	//   printf("CallBack()\n");
	// itemp is the inverse value
     	itemp=inptr->inverseFunction(0.0);
        rval=getInput(inptr->title, inptr->unit, inptr->format, &itemp, &ftemp, inptr->function, inptr->inverseFunction, (DOUBLE)inptr->minValue, (DOUBLE)inptr->maxValue, inptr->array, inptr->nvalues);
	// pA is now the new value to change to as computed by the inverse function
	// we pass this to the post processing function (callback)
	// and it's up to that function to write to EE or RAM or etc...
	if(rval!=0)
		{
		myarg.arg=ftemp;
		myarg.ptr=inptr;
		inptr->setFunction(myarg);
		}
	// done!
     }
  
*/
     inptr++;
    }      
    *err=totalerror;
    return totalerror;  
}

void showSystemVar(char *title)
{
    SYSTEMVAR* inptr;
    char ibuffer[MAX_STRING_SIZE];
    //
    inptr=systemVarLookUpTitle(title, &systemSystem[0]);
    if(inptr->type!=END_TYPE)
    {
     if((inptr->type & SHOW_TYPE)!=0)
     {
      // this is a show variable so show it if it is within the priority given
       inptr->showFunction(inptr, ibuffer, VAR_TAB);
       printf("%s\n", ibuffer);
     }
    }
}

void showInfo(SYSTEMVAR *inptr, INT prioritymin, INT prioritymax)
{
    // shows the system variables
    int exit;
    DWORD pA;
    DWORD error;
    DOUBLE ftemp, itemp;
    char ibuffer[MAX_STRING_SIZE];

    exit=0;
    while(exit==0)
    {
     if(inptr->type==END_TYPE)exit=1;
     else                           
     if((inptr->type & SHOW_TYPE)!=0)
     {
      // this is a show variable so show it if it is within the priority given
      if((inptr->priority>=prioritymin)&&(inptr->priority<=prioritymax))
      {               
       inptr->showFunction(inptr, ibuffer, VAR_TAB);
       printf("%s\n", ibuffer);
       }
     }
     inptr++;
     }      
}

void showSystemInfo(int min, int max)
{
    showInfo(&systemSystem[0], min, max);
}

/*
void showSystemInfo(void)
{
    printf("System Information\n");
    doDots("Number of Symbols");               printf(": %d\n",mapTableSize);
    doDots("Firmware Version");                printf(": %0.2d.%0.2d\n", verhigh, verlow);
    doDots("Size of Variable Data Structure"); printf(": %d\n", szVariable);
    doDots("Maximum String Size");             printf(": %d\n", maxStringSize);
    doDots("Address of Variable Flash");       printf(": 0x%4.4X\n", addressVariableFlash);
    doDots("Address of String Flash");         printf(": 0x%4.4X\n", addressStringFlash);
    doDots("T0CON");                           printf(": 0x%2.2X\n", t0con);
    doDots("tmr0Con");                         printf(": 0x%2.2X\n", tmr0con);
    doDots("tmr0ConLog");                      printf(": 0x%2.2X\n", tmr0conlog);
    doDots("Fosc4div1000");                    printf(": %d \n", (fosc4div1000));
    doDots("tmr0HPeriod");                     printf(": 0x%2.2X\n", tmr0HPeriod);
    doDots("Tmr0 Period");                     printf(": %0.3f\n",tmr0Period);
    doDots("Variable Update Frequency");       printf(": %0.1f Hz\n", varUpdateFreq);
    doDots("Logging Update Frequency");        printf(": %0.1f Hz\n", logUpdateFreq);
    doDots("LDR Level");                       printf(": %0.1f%c (%d)\n", (ldrPercent/10.0), '%', ldrLevel);
    doDots("Min Brightness");                  printf(": %d\n", minBrightness);
    doDots("Max Brightness");                  printf(": %d\n", maxBrightness);
    doDots("Set Brightness");                  printf(": %d \n", screenOnPeriod);
    doDots("Battery Level");                   printf(": %0.1fV (Level: %d, Scaling: %d)\n", (DOUBLE)(battLevel*ibattScaling), battLevel, battScaling);
    doDots("Rounding Mode");                   printf(": %d\n", roundingMode);
    doDots("Scroll Speed");                    printf(": %d\n", scrollSpeed);
    printf("\n");
    
}

#define BIG_FONT_MIN					0x00
#define BIG_FONT_MAX					0xFF
#define BIG_FONT_LINE					6
#define SMALL_FONT_MIN					0x20
#define SMALL_FONT_MAX					0x53
#define SMALL_FONT_LINE					4

const int SmallFont[]=
{    	

		0x00,0x00,0x00,0x00,		// 20
		0x00,0x00,0x00,0x00,	   	// 21
	     	0x80,0x80,0x80,0x80,		// 22
		0x00,0x00,0x00,0x00,	   	// 23 
     		0x00,0x00,0x00,0x00,		// 24 
		0x00,0x00,0x00,0x00,	   	// 25 
     		0x00,0x00,0x00,0x00,		// 26
		0x00,0x00,0x00,0x00,	   	// 27
     		0x00,0x00,0x00,0x00,		// 28
		0x00,0x00,0x00,0x00,   		// 29
	     	0x00,0x00,0x00,0x00,		// 2A
		0x00,0x00,0x00,0x00,		// 2B
		0x00,0x00,0x00,0x00,		// 2C

		0x04,0x04,0x04,0x00,	   	// 2D
     		0x80,0x01,0x00,0x80,		// 2E
		0x04,0x04,0x04,0x00,   		// 2F     	
		0x1F,0x11,0x1F,0x00,		// 30
		0x00,0x00,0x1F,0x00, 		// 31
	   	0x17,0x15,0x1D,0x00,		// 32
		0x15,0x15,0x1F,0x00, 		// 33
     		0x1C,0x04,0x1F,0x00, 		// 34
		0x1D,0x15,0x17,0x00,		// 35
     		0x1F,0x15,0x17,0x00,		// 36
		0x10,0x10,0x1F,0x00,   		// 37
     		0x1F,0x15,0x1F,0x00,		// 38
		0x1D,0x15,0x1F,0x00,   		// 39 
	     	0x00,0x00,0x00,0x00,		// 3A

		0x00,0x00,0x00,0x00,		// 3B
		0x00,0x00,0x00,0x00,		// 3C
		0x00,0x00,0x00,0x00,	   	// 3D
     		0x00,0x00,0x00,0x00,		// 3E
		0x00,0x00,0x00,0x00,   		// 3F

		0x00,0x00,0x00,0x00,		// 40
		0x1F,0x14,0x1F,0x00,   		// 41
     		0x1F,0x15,0x0A,0x00,		// 42
		0x1F,0x11,0x11,0x00,   		// 43
     		0x1F,0x11,0x0E,0x00,		// 44
		0x1F,0x15,0x15,0x00,	   	// 45
	     	0x1F,0x14,0x14,0x00,		// 46

		0x00,0x00,0x00,0x00,	   	// 47
     		0x00,0x00,0x00,0x00,		// 48
		0x00,0x00,0x00,0x00,	   	// 49
     		0x00,0x00,0x00,0x00,		// 4A
		0x11,0x0A,0x04,0x1F,		// K
		0x00,0x01,0x01,0x1F,		// L
		0x1F,0x08,0x08,0x1F,	   	// M
     		0x00,0x00,0x00,0x00,		// N
		0x00,0x00,0x00,0x00,	   	// O
     	
		0x00,0x00,0x00,0x00,		// P
		0x00,0x00,0x00,0x00,	   	// Q
	     	0x00,0x1D,0x16,0x1F,		// R
		0x00,0x00,0x00,0x00,	   	// 53
};
	
const int BigFont[]=
{ 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00
0x3E, 0x51, 0x45, 0x51, 0x3E, 0x00, // 0x01
0x3E, 0x6B, 0x7B, 0x6B, 0x3E, 0x00, // 0x02
0x1C, 0x3E, 0x1F, 0x3E, 0x1C, 0x00, // 0x03
0x0C, 0x1E, 0x3F, 0x1E, 0x0C, 0x00, // 0x04
0x06, 0x36, 0x7F, 0x36, 0x06, 0x00, // 0x05
0x0C, 0x1D, 0x3F, 0x1D, 0x0C, 0x00, // 0x06
0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, // 0x07
0x7F, 0x7F, 0x73, 0x73, 0x7F, 0x7F, // 0x08
0x00, 0x1E, 0x12, 0x12, 0x1E, 0x00, // 0x09
0x7F, 0x61, 0x6D, 0x6D, 0x61, 0x7F, // 0x0A
0x38, 0x36, 0x29, 0x09, 0x06, 0x00, // 0x0B
0x30, 0x4A, 0x4F, 0x4A, 0x30, 0x00, // 0x0C
0x10, 0x20, 0x7E, 0x07, 0x03, 0x00, // 0x0D
0x7E, 0x56, 0x28, 0x3F, 0x03, 0x00, // 0x0E
0x2A, 0x1C, 0x36, 0x1C, 0x2A, 0x00, // 0x0F
0x08, 0x1C, 0x3E, 0x7F, 0x00, 0x00, // 0x10
0x00, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 0x11
0x14, 0x36, 0x7F, 0x36, 0x14, 0x00, // 0x12
0x00, 0x7D, 0x00, 0x7D, 0x00, 0x00, // 0x13
0x7F, 0x40, 0x7F, 0x48, 0x30, 0x00, // 0x14
0x22, 0x4D, 0x55, 0x59, 0x22, 0x00, // 0x15
0x00, 0x03, 0x03, 0x03, 0x03, 0x00, // 0x16
0x14, 0x36, 0x7F, 0x36, 0x14, 0x00, // 0x17
0x10, 0x30, 0x7F, 0x30, 0x10, 0x00, // 0x18
0x04, 0x06, 0x7F, 0x06, 0x04, 0x00, // 0x19
0x08, 0x1C, 0x3E, 0x08, 0x08, 0x00, // 0x1A
0x08, 0x08, 0x3E, 0x1C, 0x08, 0x00, // 0x1B
0x01, 0x01, 0x01, 0x01, 0x0F, 0x00, // 0x1C
0x08, 0x3E, 0x08, 0x3E, 0x08, 0x00, // 0x1D
0x06, 0x1E, 0x7E, 0x1E, 0x06, 0x00, // 0x1E
0x60, 0x78, 0x7E, 0x78, 0x60, 0x00, // 0x1F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x00, 0x30, 0x7D, 0x30, 0x00, 0x00, // 0x21
0x60, 0x70, 0x00, 0x60, 0x70, 0x00, // 0x22
0x12, 0x3F, 0x12, 0x3F, 0x12, 0x00, // 0x23
0x00, 0x24, 0x2B, 0x6A, 0x12, 0x00, // 0x24
0x63, 0x13, 0x08, 0x64, 0x63, 0x00, // 0x25
0x05, 0x02, 0x35, 0x49, 0x36, 0x00, // 0x26
0x00, 0x00, 0x60, 0x70, 0x00, 0x00, // 0x27
0x00, 0x41, 0x3E, 0x00, 0x00, 0x00, // 0x28
0x00, 0x00, 0x3E, 0x41, 0x00, 0x00, // 0x29
0x08, 0x3E, 0x1C, 0x3E, 0x08, 0x00, // 0x2A
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, // 0x2B
0x00, 0x00, 0x03, 0x03, 0x00, 0x00, // 0x2C
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x2D
0x80, 0x00, 0x03, 0x03, 0x00, 0x80, // 0x2E
0x20, 0x10, 0x08, 0x04, 0x02, 0x00, // 0x2F
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, // 0x30
0x00, 0x01, 0x7F, 0x21, 0x00, 0x00, // 0x31
0x31, 0x49, 0x49, 0x45, 0x23, 0x00, // 0x32
0x36, 0x49, 0x49, 0x49, 0x22, 0x00, // 0x33
0x04, 0x7F, 0x24, 0x14, 0x0C, 0x00, // 0x34
0x46, 0x49, 0x49, 0x49, 0x7A, 0x00, // 0x35
0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, // 0x36
0x60, 0x50, 0x48, 0x47, 0x40, 0x00, // 0x37
0x36, 0x49, 0x49, 0x49, 0x36, 0x00, // 0x38
0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, // 0x39
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x80, // 0x3A
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x00, // 0x3B
0x00, 0x41, 0x22, 0x14, 0x08, 0x00, // 0x3C
0x12, 0x12, 0x12, 0x12, 0x12, 0x00, // 0x3D
0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // 0x3E
0x30, 0x48, 0x4D, 0x40, 0x20, 0x00, // 0x3F
0x3C, 0x55, 0x5D, 0x41, 0x3E, 0x00, // 0x40
0x3F, 0x44, 0x44, 0x44, 0x3F, 0x00, // 0x41
0x36, 0x49, 0x49, 0x49, 0x7F, 0x00, // 0x42
0x22, 0x41, 0x41, 0x41, 0x3E, 0x00, // 0x43
0x3E, 0x41, 0x41, 0x41, 0x7F, 0x00, // 0x44
0x41, 0x49, 0x49, 0x49, 0x7F, 0x00, // 0x45
0x40, 0x48, 0x48, 0x48, 0x7F, 0x00, // 0x46
0x2F, 0x49, 0x49, 0x41, 0x3E, 0x00, // 0x47
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, // 0x48
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, // 0x49
0x7E, 0x01, 0x01, 0x01, 0x06, 0x00, // 0x4A
0x41, 0x22, 0x14, 0x08, 0x7F, 0x00, // 0x4B
0x01, 0x01, 0x01, 0x01, 0x7F, 0x00, // 0x4C
0x7F, 0x20, 0x10, 0x20, 0x7F, 0x00, // 0x4D
0x7F, 0x08, 0x10, 0x20, 0x7F, 0x00, // 0x4E
0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, // 0x4F
0x30, 0x48, 0x48, 0x48, 0x7F, 0x00, // 0x50
0x3D, 0x42, 0x45, 0x41, 0x3E, 0x00, // 0x51
0x33, 0x4C, 0x48, 0x48, 0x7F, 0x00, // 0x52
0x26, 0x49, 0x49, 0x49, 0x32, 0x00, // 0x53
0x40, 0x40, 0x7F, 0x40, 0x40, 0x00, // 0x54
0x7E, 0x01, 0x01, 0x01, 0x7E, 0x00, // 0x55
0x7C, 0x02, 0x01, 0x02, 0x7C, 0x00, // 0x56
0x7E, 0x01, 0x1E, 0x01, 0x7E, 0x00, // 0x57
0x63, 0x14, 0x08, 0x14, 0x63, 0x00, // 0x58
0x70, 0x08, 0x07, 0x08, 0x70, 0x00, // 0x59
0x00, 0x61, 0x51, 0x49, 0x47, 0x00, // 0x5A
0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, // 0x5B
0x02, 0x04, 0x08, 0x10, 0x20, 0x00, // 0x5C
0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, // 0x5D
0x10, 0x20, 0x40, 0x20, 0x10, 0x00, // 0x5E
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x5F
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x60
0x0F, 0x15, 0x15, 0x15, 0x02, 0x00, // 0x61 = a
0x0E, 0x11, 0x11, 0x11, 0x7F, 0x00, // 0x62 = b
0x0A, 0x11, 0x11, 0x11, 0x0E, 0x00, // 0x63 = c
0x7F, 0x11, 0x11, 0x11, 0x0E, 0x00, // 0x64 = d
0x08, 0x15, 0x15, 0x15, 0x0E, 0x00, // 0x65 = e
0x00, 0x48, 0x48, 0x3F, 0x08, 0x00, // 0x66 = f
0x1E, 0x25, 0x25, 0x25, 0x18, 0x00, // 0x67 = g (*)
0x00, 0x0F, 0x10, 0x10, 0x7F, 0x00, // 0x68 = h
0x00, 0x01, 0x5F, 0x00, 0x00, 0x00, // 0x69 = i
0x00, 0x5E, 0x11, 0x11, 0x02, 0x00, // 0x6A = j (*)
0x00, 0x11, 0x0A, 0x04, 0x7F, 0x00, // 0x6B = k
0x00, 0x01, 0x7F, 0x00, 0x00, 0x00, // 0x6C = l
0x0F, 0x10, 0x0C, 0x10, 0x1F, 0x00, // 0x6D = m
0x00, 0x0F, 0x10, 0x10, 0x1F, 0x00, // 0x6E = n
0x0E, 0x11, 0x11, 0x11, 0x0E, 0x00, // 0x6F = o
0x0C, 0x12, 0x12, 0x12, 0x1F, 0x00, // 0x70 = p (*)
0x1F, 0x12, 0x12, 0x12, 0x0C, 0x00, // 0x71 = q (*)
0x08, 0x10, 0x11, 0x0F, 0x11, 0x00, // 0x72 = r
0x02, 0x15, 0x15, 0x15, 0x08, 0x00, // 0x73 = s
0x00, 0x12, 0x11, 0x3E, 0x10, 0x00, // 0x74 = t
0x00, 0x1F, 0x02, 0x01, 0x1E, 0x00, // 0x75 = u
0x1C, 0x02, 0x01, 0x02, 0x1C, 0x00, // 0x76 = v
0x1E, 0x03, 0x06, 0x03, 0x1E, 0x00, // 0x77 = w
0x00, 0x1B, 0x04, 0x04, 0x1B, 0x00, // 0x78 = x
0x00, 0x3E, 0x09, 0x09, 0x32, 0x00, // 0x79 = y (*)
0x00, 0x19, 0x15, 0x15, 0x13, 0x00, // 0x7A = z 
0x00, 0x41, 0x41, 0x3E, 0x08, 0x00, // 0x7B
0x00, 0x00, 0x77, 0x00, 0x00, 0x00, // 0x7C
0x08, 0x3E, 0x41, 0x41, 0x00, 0x00, // 0x7D
0x00, 0x40, 0x20, 0x40, 0x20, 0x00, // 0x7E
0x1E, 0x32, 0x62, 0x32, 0x1E, 0x00, // 0x7F
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x80
0x00, 0x5F, 0x02, 0x01, 0x5E, 0x00, // 0x81
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x82
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x83
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x84
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x85
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x86
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x87
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x88
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x89
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x8A
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x8B
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x8C
0x00, 0x01, 0x1F, 0x40, 0x00, 0x00, // 0x8D
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x8E
0x0F, 0x7A, 0x52, 0x7A, 0x0F, 0x00, // 0x8F
0x51, 0x55, 0x15, 0x15, 0x1F, 0x00, // 0x90
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x91
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x92
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x93
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x94
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x95
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x96
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x97
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x98
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x99
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x9A
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x9B
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x9C
0x4A, 0x2A, 0x1F, 0x2A, 0x4A, 0x00, // 0x9D
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x9E
0x00, 0x00, 0x70, 0x60, 0x00, 0x00, // 0x9F
0x0F, 0x55, 0x55, 0x15, 0x02, 0x00, // 0xA0
0x00, 0x41, 0x5F, 0x00, 0x00, 0x00, // 0xA1
0x00, 0x4E, 0x51, 0x11, 0x0E, 0x00, // 0xA2
0x00, 0x5F, 0x42, 0x01, 0x1E, 0x00, // 0xA3
0x00, 0x47, 0x28, 0x48, 0x2F, 0x00, // 0xA4
0x00, 0x4F, 0x22, 0x44, 0x2F, 0x00, // 0xA5
0x3D, 0x55, 0x55, 0x55, 0x08, 0x00, // 0xA6
0x00, 0x39, 0x45, 0x45, 0x39, 0x00, // 0xA7
0x02, 0x01, 0x59, 0x09, 0x06, 0x00, // 0xA8
0x10, 0x10, 0x10, 0x10, 0x1E, 0x00, // 0xA9
0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, // 0xAA
0x05, 0x2B, 0x19, 0x08, 0x74, 0x00, // 0xAB
0x0F, 0x2A, 0x16, 0x08, 0x74, 0x00, // 0xAC
0x00, 0x06, 0x5F, 0x06, 0x00, 0x00, // 0xAD
0x14, 0x08, 0x00, 0x14, 0x08, 0x00, // 0xAE
0x08, 0x1C, 0x3E, 0x7F, 0x00, 0x00, // 0xAF
0x44, 0x11, 0x44, 0x11, 0x44, 0x11, // 0xB0
0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, // 0xB1
0x3B, 0x6E, 0x3B, 0x6E, 0x3B, 0x6E, // 0xB2
0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, // 0xB3
0x00, 0x00, 0x7F, 0x08, 0x08, 0x08, // 0xB4
0x00, 0x00, 0x7F, 0x28, 0x28, 0x28, // 0xB5
0x00, 0x00, 0x7F, 0x00, 0x7F, 0x08, // 0xB6
0x00, 0x00, 0x0F, 0x08, 0x0F, 0x08, // 0xB7
0x00, 0x00, 0x3F, 0x28, 0x28, 0x28, // 0xB8
0x00, 0x00, 0x7F, 0x00, 0x6F, 0x28, // 0xB9
0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, // 0xBA
0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, // 0xBB
0x00, 0x00, 0x78, 0x08, 0x68, 0x28, // 0xBC
0x00, 0x00, 0x78, 0x08, 0x78, 0x08, // 0xBD
0x00, 0x00, 0x78, 0x28, 0x28, 0x28, // 0xBE
0x00, 0x00, 0x0F, 0x08, 0x08, 0x08, // 0xBF
0x08, 0x08, 0x78, 0x00, 0x00, 0x00, // 0xC0
0x08, 0x08, 0x78, 0x08, 0x08, 0x08, // 0xC1
0x08, 0x08, 0x0F, 0x08, 0x08, 0x08, // 0xC2
0x08, 0x08, 0x7F, 0x00, 0x00, 0x00, // 0xC3
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // 0xC4
0x08, 0x08, 0x7F, 0x08, 0x08, 0x08, // 0xC5
0x28, 0x28, 0x7F, 0x00, 0x00, 0x00, // 0xC6
0x08, 0x08, 0x7F, 0x00, 0x7F, 0x00, // 0xC7
0x28, 0x28, 0x68, 0x08, 0x78, 0x00, // 0xC8
0x28, 0x28, 0x2F, 0x20, 0x3F, 0x00, // 0xC9
0x28, 0x28, 0x68, 0x08, 0x68, 0x28, // 0xCA
0x28, 0x28, 0x2F, 0x20, 0x2F, 0x28, // 0xCB
0x28, 0x28, 0x6F, 0x00, 0x7F, 0x00, // 0xCC
0x28, 0x28, 0x28, 0x28, 0x28, 0x28, // 0xCD
0x28, 0x28, 0x6F, 0x00, 0x6F, 0x28, // 0xCE
0x28, 0x28, 0x68, 0x28, 0x28, 0x28, // 0xCF
0x08, 0x08, 0x78, 0x08, 0x78, 0x08, // 0xD0
0x28, 0x28, 0x2F, 0x28, 0x28, 0x28, // 0xD1
0x08, 0x08, 0x0F, 0x08, 0x0F, 0x08, // 0xD2
0x08, 0x08, 0x78, 0x08, 0x78, 0x00, // 0xD3
0x28, 0x28, 0x78, 0x00, 0x00, 0x00, // 0xD4
0x28, 0x28, 0x3F, 0x00, 0x00, 0x00, // 0xD5
0x08, 0x08, 0x0F, 0x08, 0x0F, 0x00, // 0xD6
0x08, 0x08, 0x7F, 0x00, 0x7F, 0x08, // 0xD7
0x28, 0x28, 0x6F, 0x28, 0x28, 0x28, // 0xD8
0x00, 0x00, 0x78, 0x08, 0x08, 0x08, // 0xD9
0x08, 0x08, 0x0F, 0x00, 0x00, 0x00, // 0xDA
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 0xDB
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, // 0xDC
0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, // 0xDD
0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, // 0xDE
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, // 0xDF
0x12, 0x0C, 0x12, 0x12, 0x0C, 0x00, // 0xE0
0x00, 0x16, 0x29, 0x29, 0x3F, 0x00, // 0xE1
0x00, 0x60, 0x40, 0x40, 0x7F, 0x00, // 0xE2
0x20, 0x3F, 0x20, 0x3F, 0x20, 0x00, // 0xE3
0x00, 0x63, 0x49, 0x55, 0x63, 0x00, // 0xE4
0x10, 0x1C, 0x12, 0x12, 0x0C, 0x00, // 0xE5
0x00, 0x1C, 0x02, 0x02, 0x1F, 0x00, // 0xE6
0x00, 0x10, 0x0F, 0x10, 0x08, 0x00, // 0xE7
0x08, 0x55, 0x77, 0x55, 0x08, 0x00, // 0xE8
0x00, 0x3E, 0x49, 0x49, 0x3E, 0x00, // 0xE9
0x19, 0x27, 0x20, 0x27, 0x19, 0x00, // 0xEA
0x00, 0x06, 0x4D, 0x55, 0x22, 0x00, // 0xEB
0x0C, 0x12, 0x0C, 0x12, 0x0C, 0x00, // 0xEC
0x0C, 0x12, 0x3F, 0x12, 0x0C, 0x00, // 0xED
0x00, 0x2A, 0x2A, 0x2A, 0x1C, 0x00, // 0xEE
0x00, 0x1E, 0x20, 0x20, 0x1E, 0x00, // 0xEF
0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, // 0xF0
0x00, 0x12, 0x3A, 0x12, 0x00, 0x00, // 0xF1
0x00, 0x11, 0x29, 0x29, 0x45, 0x00, // 0xF2
0x00, 0x45, 0x29, 0x29, 0x11, 0x00, // 0xF3
0x10, 0x20, 0x1F, 0x00, 0x00, 0x00, // 0xF4
0x00, 0x00, 0x7E, 0x01, 0x02, 0x00, // 0xF5
0x08, 0x08, 0x2A, 0x08, 0x08, 0x00, // 0xF6
0x00, 0x24, 0x12, 0x24, 0x12, 0x00, // 0xF7
0x00, 0x30, 0x48, 0x48, 0x30, 0x00, // 0xF8
0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, // 0xF9
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, // 0xFA
0x20, 0x20, 0x3E, 0x01, 0x06, 0x00, // 0xFB
0x00, 0x38, 0x40, 0x38, 0x40, 0x00, // 0xFC
0x00, 0x00, 0x28, 0x58, 0x48, 0x00, // 0xFD
0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, // 0xFE
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xFF
};

void produceFontForCorelDraw(void)
{
   int linecounter, bytecounter;
    int totallines, totallinelength;

    printf("\n\tRem The Font Data Starts Here\n");

    printf("\tDim BigFontLine As Integer\n");
    printf("\tBigFontLine= %d \n", BIG_FONT_LINE);

    printf("\tDim SmallFontLine As Integer\n");
    printf("\tSmallFontLine= %d \n", SMALL_FONT_LINE);

    printf("\tDim BigFontMin As Integer\n");
    printf("\tBigFontMin= %d \n", BIG_FONT_MIN);

    printf("\tDim BigFontMax As Integer\n");
    printf("\tBigFontMax= %d \n", BIG_FONT_MAX);

    printf("\tDim SmallFontMin As Integer\n");
    printf("\tSmallFontMin= %d \n", SMALL_FONT_MIN);

    printf("\tDim SmallFontMax As Integer\n");
    printf("\tSmallFontMax= %d \n", SMALL_FONT_MAX);

    printf("\tDim SmallFont( %d To %d , %d To %d ) As Byte\n", SMALL_FONT_MIN, SMALL_FONT_MAX, 0, SMALL_FONT_LINE);
    printf("\tDim BigFont( %d To %d , %d To %d ) As Byte\n", BIG_FONT_MIN, BIG_FONT_MAX, 0, BIG_FONT_LINE);

    printf("\n\tRem The Big Font Begins Here\n");

    totallinelength=BIG_FONT_LINE;
    bytecounter=0;
    for(i=BIG_FONT_MIN; i<=BIG_FONT_MAX; i++)
    {
	for(j=0; j<totallinelength; j++)
	{
	printf("\tBigFont( %d , %d )= %d \n", i, j, BigFont[bytecounter++]);
	}
	
    }

    printf("\n\tRem The Small Font Begins Here\n");

    totallinelength=SMALL_FONT_LINE;
    bytecounter=0;
    for(i=SMALL_FONT_MIN; i<=SMALL_FONT_MAX; i++)
    {
	for(j=0; j<totallinelength; j++)
	{
	printf("\tSmallFont( %d , %d )= %d \n", i, j, SmallFont[bytecounter++]);
	}
	
    }

    printf("\nRem The Fonts End Here\n");

    return 0;

}

*/

int main(int argc, char *argv[])
{
    SYMBOL *symptr;
    DOUBLE tempPolyBuffer[MAX_POLY];
    long i, j, k, m, ww, xx, yy, zz;
    long nlogsamples=0;
    DWORD duplicate;
    DWORD nb;    
    long exit, logexit, pointAdded;
    long num_samples;
    long myargument;
    DWORD localerror, myerror;
    DOUBLE ftemp, jtemp;
    char ibuffer[MAX_STRING_SIZE];
    CHARP icharp;
    INT iindex;
    int logmask;
    int logminmax;
    int cancel;
    char argBuffer[2][MAX_STRING_SIZE];

/*
    DOUBLE poly1[50];
    DOUBLE poly2[50];
    int result, deg1;
    DOUBLE alpha;

    poly1[0]=-20.0;
    poly1[1]=24.0;
    poly1[2]=6.0;
    deg1=2;
    printf("Before: ");
    printPolynomialPtr(&poly1[0], deg1);  
    printf("\n");
    alpha=findAlpha(&poly1[0], deg1, 0.5, -2.0, 0.0000001, 10.0, &result);
    printf("After. Alpha: %6.6f Result: %d\n", alpha,result);
    printPolynomialPtr(&poly1[0], deg1);
    printf("\n");
    return 0;
    iindex=getPolynomialPtr("120X^29+      X^7+ 23.4X^5+43X^6+128.65X^2-10.90X+1.2", (DOUBLE*) &polyTemp[0], 10, &deg, &syntaxerr);
    if(iindex==0)
    {
    printf("Deg= %d Polynomial is: ", deg);
    printPolynomialPtr((DOUBLE*)&polyTemp[0], deg);
    printf("\n");
    }
    else
    {
        printf("Syntax Error: %s\n", syntaxerr);
    }
  */  
    printf("\n");
    settingsSize=0;
    finalSystemWrite=0;
    for(i=0; i<MAX_SETTINGS_RAM; i++)
    {
        settingsRAM[i]=0;
    }

    for(i=0; i<MAXSTRINGSSIZE; i++)
    {
    StringsCmp[i]=0;
    Strings[i]=0;
    }

    autoSizeErrors=0;
    open=0;
    reqReset=0;
    currentVariableNumber=0;
    currentIndexNumber=0;

    for(i=0; i<NUM_VARS; i++)
    {
     variable[i].updateTime=0;
     variable[i].oldupdateTime=0;   
     variable[i].cmptotal=0;
    }
    for(i=0; i<EPSIZE;i++){ datapacket._byte[i]=0; indatapacket._byte[i]=0; }
    doDotsSys("Car Scrolling Display Interface. M.G. Oct. 2008 (c). PC Host Version", ":"); 
    printf("%2.2d.%2.2d\n", HOSTVERHIGH, HOSTVERLOW);
    if(SIZEBYTE!=sizeof(char))
    {
        printf("Bad Size of Char.\n");
        return 0;
    }
    if(SIZEDOUBLE!=sizeof(DOUBLE))
    {
        printf("Bad Size of Double.\n");
        return 0;
    }
    if(SIZEINT!=sizeof(INT))
    {
        printf("Bad Size of Int.\n");
        return 0;
    }
    if(SIZEBYTE!=sizeof(BYTE))
    {
        printf("Bad Size of Byte.\n");
        return 0;
    }
    if(SIZECHARP!=sizeof(CHARP))
    {
        printf("Bad Size of Char Ptr.\n");
        return 0;
    }
    if(SIZELONG!=sizeof(int))
    {
        printf("Bad Size of Long.\n");
        return 0;
    }
    
    temp=MPUSBGetDLLVersion();
    sprintf(printBuffer, "MPUSBAPI Version: %d.%d", HIWORD(temp), LOWORD(temp));
    doDotsSys(printBuffer, ":");
    
    if(sizeof(datapacket)!=EPSIZE)
    {
    printf("DataPacket Size Error.\n"); 
    printf("Size is: %d Bytes. Should be: %d Bytes\n", sizeof(datapacket), EPSIZE);
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }
    
    if((HIWORD(temp)>TARGET_HI_VERSION)||((HIWORD(temp)==TARGET_HI_VERSION)&&(LOWORD(temp)>=TARGET_LO_VERSION)))printf("Ok.\n");
    else
    {
    printf("Old MPUSBAPI Version.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0;
    }
                                                        
    myOutPipe= myInPipe = INVALID_HANDLE_VALUE;
    exit=0;
    pointAdded=0;
    num_samples=0;

    i=loadMapTable();
    if(i==0)
    { 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //outcalibrationfile.close();
    //mapfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } 

  //showPacket((BYTE*)&mapTable.ramMap[0], DEVICE_TOTAL_RAM);
/*
    GetSummary();
    doDotsSys("Total Device Ram Auto Sized",":");
    printf("%d Bytes\n", mapTable.autSizeTotalRam);
    symptr=lookUpSymbol("PORTE");
    printf("Symbol: PORTE Address: %4.4x Size: %d NOAUTOSIZE: %d \n", symptr->pAdr, symptr->size, symptr->noAutoSize);
*/  
   //setWaitImode(0);
  
    doDotsSys("Gathering System Settings", ":");
    i=getSystemInfo(&localerror);
    if(localerror!=0)
    { 
    printf("Error.\n"); 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } else printf("Ok.\n");
       
    if((szVariable+OVER_HEAD)>EPSIZE)
    {
    printf("Error. Packet Size Too Small.\n");
    doDotsSys("Minimum Packet Size Required", ":"); printf("%d Bytes\n", szVariable+OVER_HEAD);
    doDotsSys("Actual Packet Size Implemented",":"); printf("%d Bytes\n", EPSIZE);
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }
    
    if(stringsSize<=0)
    {
    printf("Error. Bad stringsSize.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }

    if(stringsSize>MAXSTRINGSSIZE)
    {
    printf("Error. Strings Size Memory Too Big.\n");
    doDotsSys("Maximum Strings Size Memory Allowed", ":"); printf("%d Bytes\n", MAXSTRINGSSIZE);
    doDotsSys("Actual Strings Size in Device",":"); printf("%d Bytes\n", stringsSize);
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }

    if((stringsSize % 32)!=0)
    {
    printf("Error. Strings Size Not Aligned To Device Flash Boundary.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }

    if((stringsSize % STRINGPKSIZE)!=0)
    {
    printf("Error. Strings Size Not Aligned To Local Packet Size.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }

    if((szVariable % 32)!=0)
    {
    printf("Error. Variable Data Structure Size Not Aligned To Device Flash Boundary.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    }

    sprintf(printBuffer, "Comparing Firmware (%2.2d.%2.2d) and PC Host Program (%2.2d.%2.2d) Versions", verhigh, verlow, HOSTVERHIGH, HOSTVERLOW);
    doDotsSys(printBuffer, ":");
    if((HOSTVERHIGH>verhigh)||((HOSTVERHIGH==verhigh)&&(HOSTVERLOW>=verlow)))
    {
    if((HOSTVERHIGH==verhigh)&&(HOSTVERLOW==verlow))printf("Ok.\n");
    else printf("Firmware Older.\n");
    }
    else
    {
    printf("PC Host Version Older.\nUpgrade Required.\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0;
    }
    
    doDotsSys("Gathering Variable Information", ":");
    i=getAllVariableInfo(&localerror);
    if(localerror!=0)
    { 
    printf("Error.\n"); 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } else printf("Ok.\n");

/*
    // must take two snapshots to zero the cmp totals!
    zz=copyCmpVariables(&variable[0], &cmpvariable[0], 0, NUM_VARS);
    zz=copyCmpVariables(&variable[0], &cmpvariable[0], 0, NUM_VARS);
    // 
    doDotsSys("Caching Variable Information", ":");
    if(zz==0)printf("Ok.\n");
    else
    printf("Error.\n");
*/
    
    //for(i=0; i<stringsSize; i++)Strings[i]+=(i>>3);
   
   /*
    showPacketASCII((BYTE*)&Strings, stringsSize); 
    printf("Computing Amount of String Memory In Use: %d Bytes\n", getStringsSubIndex(0, endIndex, STRING_DELIMITER)); 
    
    insertsString("Hello", 0, ':', &localerror);
    showPacketASCII((BYTE*)&Strings, stringsSize); 
    printf("Computing Amount of String Memory In Use: %d Bytes\n", getStringsSubIndex(0, endIndex, STRING_DELIMITER)); 
     
    insertsString("Bye", 0, ':', &localerror);
    showPacketASCII((BYTE*)&Strings, stringsSize); 
    printf("Computing Amount of String Memory In Use: %d Bytes\n", getStringsSubIndex(0, endIndex, STRING_DELIMITER)); 
    
    deletesString(0, STRING_DELIMITER);
    showPacketASCII((BYTE*)&Strings, stringsSize); 
    printf("Computing Amount of String Memory In Use: %d Bytes\n", getStringsSubIndex(0, endIndex, STRING_DELIMITER)); 
*/
    
    doDotsSys("Gathering Polynomial Table and Indexes. Polynomial Memory In Use", ":");
    i=getPolyInfo(&localerror);
    if(localerror!=0)
    { 
    printf("Error.\n"); 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } else 
    {
    polyUpdate=0;
    printf("%2.0f%c\n", (double)polyMemoryUsed*100.0/(MAX_POLY-1), '%');
    }
    loadCalibrationPointsWithPolynomialData();
    

/*
    i=loadCalibrationPoints();
    if(i!=0)
    { 
    printf("Errors! Aborting...\n"); 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    datalog.close();
    outcalibrationfile.close();
    mapfile.close();
    calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } 
 
    showPolyInfo();
    sprintf(printBuffer, "Computing and Inserting Polynomials. Polynomial Memory In Use: %d%c", (int)(polyMemoryUsedPercent), '%');
    doDotsSys(printBuffer, ":");
    i=computeInsertAllPolynomials();
    if(i!=0)
    {
    printf("Errors! Aborting...\n");
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    datalog.close();
    outcalibrationfile.close();
    mapfile.close();
    calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } else 
    {
      printf("Ok.\n");
    }

    showPolyInfo();
*/

//  i=showAllPolynomials();

//    printf("SystemName autosized: %d \n", autoSizeName("systemName"));

    printf("\n");
    exit=0;
    cancel=0;
    num_samples=0;
    currentVariableNumber=0;
    currentIndexNumber=0;
    if(argc==1)
    {
    //  synchronise command if no arguments
        printf("No arguments entered...\n");
        showHelpScreen();
    //  changeSystemSettings();
    }
    else
    if(argc>1)
    { 
        m=1;
        while((exit==0)&&(cancel==0)&&(m<argc))
        {
        if(argv[m][0]=='-')
            {
                if(argv[m][1]=='i')
                {
                    // see system settings 'information'
                    doDotsCommand("System Settings", ":");
                    getSystemInfo(&localerror);
                    if(localerror==0)
                    {
                    printf("Ok.\n");
                    showSystemInfo(1, MAX_PRIORITY); 
                    printf("\nThe Following are Currently Displayed Readings (In Order):\n");
                    i=showDisplayObjects(0, 0);
                    } else
                    {
                    printf("Error.\n");
                    exit=1;
                    }
                } else
                if(argv[m][1]=='e')
                {
                    // see extended system settings
                    doDotsCommand("Extended System Settings", ":");
                    getSystemInfo(&localerror);
                    if(localerror==0)
                    {
                    printf("Ok.\n");
                    showSystemInfo(0, MAX_PRIORITY); 
                    } else
                    {
                    printf("Error.\n");
                    exit=1;
                    }
                } else
                if(argv[m][1]=='s')
                {
                     //  set system parameters
                     if(argv[m][2]=='\0')
                     {
                     doDotsCommand("Change System Settings", ": Ok");
                     printf("\n");
                     putInfo((SYSTEMVAR*)&systemSystem[0], 1, 1, &localerror);
                     if(localerror!=0)
                     {
                       printf("Error.\n"); 
                       exit=1; 
                     } else
                     {
                     getSystemInfo(&localerror);
                     if(localerror!=0)
                     {
                       printf("Error.\n");
                       exit=1;
                       } else
                       {
                       printf("\nCurrent System Settings:\n");
                       showSystemInfo(1, 1);
                       }
                      }
                    } else
                    if(argv[m][2]==':')
                    {
                       myargument=(long)atof(&argv[m][3]);
                       if(myargument>0)
                       {
                       doDotsCommand("Change Extended System Settings", ": Ok");
                       printf("\n");
                       putInfo((SYSTEMVAR*)&systemSystem[0], myargument, myargument, &localerror);
                       if(localerror!=0)
                       {
                        printf("Error.\n"); 
                        exit=1; 
                       } else
                       {
                        getSystemInfo(&localerror);
                        if(localerror!=0)
                        {
                        printf("Error.\n");
                        exit=1;
                        } else
                        {
                        printf("\nCurrent System Settings:\n");
                        showSystemInfo(myargument, myargument);
                        }
                        }
                        } else 
                        {
                       doDotsCommand("Change All Extended System Settings", ": Ok");
                       printf("\n");
                       putInfo((SYSTEMVAR*)&systemSystem[0], 1, 32000, &localerror);
                       if(localerror!=0)
                       {
                        printf("Error.\n"); 
                        exit=1; 
                       } else
                       {
                        getSystemInfo(&localerror);
                        if(localerror!=0)
                        {
                        printf("Error.\n");
                        exit=1;
                        } else
                        {
                        printf("\nCurrent System Settings:\n");
                        showSystemInfo(1, 32000);
                        }
                        }
                    }
                   }
                } else
                if(argv[m][1]=='o')
                {
                    // set the output channel parameters
                    yy=doOutputMenu();
                    if(yy!=0)
                    {
                    cancel=1;
                    }
                    exit=1;
                    
                } else
                if(argv[m][1]=='c')
                {
                    yy=doCalibrationMenu();
                    if(yy!=0)
                    {
                    cancel=1;
                    }
                    exit=1;   
                 } else
                if(argv[m][1]=='v')
                {
                    yy=doVariableMenu();
                    if(yy!=0)
                    {
                    cancel=1;
                    }
                    exit=1;
                }
                else
                if(argv[m][1]=='d')
                {
                    yy=displayMenu();
                    if(yy!=0)
                    {
                        cancel=1;
                    }
                    exit=1;
                    
                } else
                if((argv[m][1]=='x')&&(argv[m][2]==':'))
                {
                    // read the variable NN information...
                    myargument=(long)atof(&argv[m][3]);
                    if(myargument<0)myargument=0; else if(myargument>=NUM_VARS)myargument=NUM_VARS-1;
                    sprintf(printBuffer, "Reading Variable %d Information", myargument);
                    doDotsCommand(printBuffer, ":");
                    i=readVariable(myargument, &localerror);
                    if(localerror!=0){ printf("Error.\n"); exit=1; } 
                    else
                    {
                        printf("Ok.\n");
                        //showPacket(&indatapacket.data[0], EPSIZE);
                        showVariableInfo(myargument, 0x0F, 0x0F, 0xFF);
                    }
                } else
                if((argv[m][1]=='q')&&(argv[m][2]==':'))
                {
                    // read the variable NN information...
                    myargument=(long)atof(&argv[m][3]);
                    if(myargument<0)myargument=0; else if(myargument>=NUM_VARS)myargument=NUM_VARS-1;
                    sprintf(printBuffer, "Reading Variable %d Information", myargument);
                    doDotsCommand(printBuffer, ":");
                    i=readVariable(myargument, &localerror);
                    if(localerror!=0){ printf("Error.\n"); exit=1; } 
                    else
                    {
                        printf("Ok.\n");
                        //showPacket(&indatapacket.data[0], EPSIZE);
                        showVariableInfoNice(myargument);
                    }
                } else
                if(argv[m][1]=='z')
                {
                   // sleeping for so many milliseconds!
                   setWaitImode(0);
                   myargument=(long)atof(&argv[m][3]);
                   if(myargument<1)myargument=1; else if(myargument>=320000)myargument=320000;
                 
                   i=0;
                   j=-1;
                   startt=clock();
                   while((!kbhit())&&(j<100))
                   {
                   endt=clock();
                   timeElapsed=(DOUBLE)(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                   i=(long)(100000.0*timeElapsed/myargument);
                   if(i!=j)
                   {
                   sprintf(printBuffer, "Waiting For %0.3f sec. Total Requested Wait Elapsed", (DOUBLE)(myargument/1000.0));
                   doDotsCommand(printBuffer, ":");
                   printf("%d%c\r", i, '%');
                   j=i;
                   }
                  }
                  printf("\n");
                } else
                if((argv[m][1]=='w')&&(argv[m][2]==':'))
                {
                    // write all settings to file!
                    sprintf(ibuffer, "%s", &argv[m][3]);                    
                    if(ibuffer[0]!='\0')
                    {
                    i=writeSettingsFile(ibuffer, (BYTE*)&settingsRAM[0], MAX_SETTINGS_RAM);
                    sprintf(printBuffer, "Write the Following Settings to File: %s. Number of Bytes Written", ibuffer);
                    doDotsCommand(printBuffer, ":");
                    if(i>0)
                        {
                        printf("%d\n", i);
                        showInfoDirect(&systemSystem[0],0, 32000);
                        } else printf("Error.\n");
                    } else
                    {
                    sprintf(printBuffer, "Write Settings");
                    doDotsCommand(printBuffer, ":");
                    printf("No file Specified\n");
                    }
                    //
                } else
                if((argv[m][1]=='r')&&((argv[m][2]=='\0')||(argv[m][2]==':')))
                {
                    // read settings for file!
                    setWaitImode(0);
                    if(argv[m][2]==':')
                    {
                    sprintf(ibuffer, "%s", &argv[m][3]);
                    i=readSettingsFile(ibuffer, (BYTE*)&settingsRAM[0], MAX_SETTINGS_RAM);
                    sprintf(printBuffer, "Read the Following Settings from File: %s. Number of Bytes Read", ibuffer);
                    doDotsCommand(printBuffer, ":");
                    if(i>0)
                        {
                        printf("%d\n", i);
                        showInfoDirect(&systemSystem[0],0, 32000);
                        sprintf(printBuffer, "Do You Wish to Load These Settings? Press (Y)es/(N)o");
                        sdoDots(printBuffer, printBuffer, COMMAND_TAB, '.');
                        sprintf(printBuffer, "%s> ", printBuffer);
                        printf("%s", printBuffer);
                        icharp=mygetch(&globalcontrolcode);
                        printf("%c\n", icharp);
                        if((icharp=='Y')||(icharp=='y'))
                        {
                        // committ the changes
                        sprintf(printBuffer, "Loading Settings");
                        doDotsCommand(printBuffer, ":");
                        i=sendSettings(&systemSystem[0], &localerror);
                        if(localerror==0)printf("Ok.\n"); else printf("Error.\n");
                        exit=1;
                        } else
                        {
                        printf("Settings Not Loaded.\n");
                        }
                        } else printf("Error.\n");
                    } else
                    {
                    sprintf(printBuffer, "Read Settings");
                    doDotsCommand(printBuffer, ":");
                    printf("Bad File or File Not Specified\n");
                    //  since no file name was specified, we assume reset is required instead...
                    // reset the system and restore default values
                    sprintf(printBuffer, "Reset the Display and Load Default Values? Press (Y)es/(N)o");
                    sdoDots(printBuffer, printBuffer, COMMAND_TAB, '.');
                    sprintf(printBuffer, "%s> ", printBuffer);
                    printf("%s", printBuffer);
                    icharp=mygetch(&globalcontrolcode);
                    printf("%c\n", icharp);
                    if((icharp=='Y')||(icharp=='y'))
                    {
                    doDotsCommand("Reset Sequence Commenced. Press Any Key to Abort", ":");
                    printf("Waiting.\n");
                    startt=clock();
                    timeElapsed=0;
                    while((!kbhit())&&(timeElapsed<RESET_DELAY))
                    {
                    doDotsCommand("Preparing For Reset. All Default Values will be Restored", ":");
                    endt=clock();
                    timeElapsed=(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                    printf("%0.1f sec.\r", RESET_DELAY+0.1-timeElapsed);
                    DelayMs(100);
                    }

                    printf("\n");
                    if(timeElapsed>=RESET_DELAY)
                    {
                    k=MPUSBGetDeviceCount(vid_pid);
                    if(k>0)writeEEVariable(MAGIC_VALUE_ADR,MAGIC_VALUE+1,SIZEBYTE,&localerror); else localerror=1;
                    if(localerror!=0)
                    {
                    
                    doDotsCommand("Requesting Reset", ":");
                    printf("Error.\n");
                    exit=1;
                    }
                    else
                    {
                    eraseStringFlash(&localerror);
                    if(localerror!=0)
                    {
                        doDotsCommand("Erasing String Flash", ":");
                        printf("Error.\n");
                        exit=1;
                    } else
                    {
                    datapacket.cmd=CAR_DISPLAY_RESET;
                    i=sendCommand(&datapacket, &nb, &localerror); 
                    if(localerror!=0)
                    { 
                    doDotsCommand("Requesting Reset", ":");
                    printf("Error.\n"); 
                    exit=1; 
                    }
                    else
                    {
                    open=0;     
                    reqReset=1;
                    ftemp=0.0;
                    jtemp=0.0;
                    startt=clock();
                    myargument=RESET_DELAY*2.0;  
                    while((reqReset==1)&&(timeElapsed<=myargument))
                    {
                    endt=clock();
                    timeElapsed=(DOUBLE)(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                    ftemp=timeElapsed;
                    if(((ftemp-jtemp)>0.10)&&((ftemp-jtemp)<1.9))
                    {
                    doDotsCommand("Requesting Reset. All Default Values will be Restored", ":");
                    //printf("%0.1f sec.\r", ftemp);
                    printf("Waiting.\r");
                    DelayMs(100);
                    }
                    else
                    if((ftemp-jtemp)>=1.9)
                    {
                    jtemp=ftemp;
                    k=MPUSBGetDeviceCount(vid_pid);
                    if(k>0)
                    {
                    reqReset=readRamVariableAutoSize("reqReset", 0, 0, &localerror);
                    if(localerror!=0)
                    {
                    reqReset=1;
                    }
                    }                          
                    }
                    }
                    doDotsCommand("Requesting Reset", ":");
                    exit=1;
                    if(reqReset==0)localerror=0; else localerror=1;
                    if(localerror!=0)
                    printf("Time Out Error!    \n", timeElapsed); else printf("Ok.     \n", timeElapsed);
                    }
                    }
                    }
                    } else
                     {
                     printf("Reset Aborted.\n");
                     }
                     } else
                     {
                           printf("Reset Request Ignored.\n");
                           }
                    }
                    }
/*
                if(argv[m][1]=='q')
                {
                    // write a string
                    copyString(&argv[m][3], &datapacket.data[0], maxStringSize);
                    printf("Writing String: %s to Variable No. %d at Index No. %d...", &datapacket.data[0], currentVariableNumber, currentIndexNumber);
                    i=writeStringFlash(currentVariableNumber, currentIndexNumber, &localerror);
                    if(localerror!=0){ printf("Error.\n"); exit=1; }
                    else
                    {
                        printf("Ok.\n");
                    }
                    printf("Updating Variable Information...");
                    i=readVariable(currentVariableNumber, &localerror);
                    if(localerror!=0){ printf("Error.\n"); exit=1; }
                    else
                    {
                        // now update pointers...
                        variable[currentVariableNumber].name[currentIndexNumber]=getStringFlashAddress(currentVariableNumber, currentIndexNumber);
                        i=putVariable(currentVariableNumber, &localerror);
                        if(localerror!=0){ printf("Error.\n"); exit=1; }
                        else
                        {
                            printf("Ok.\n");
                        }
                    }

                } else
*/
                else
                if((argv[m][1]=='u')&&(argv[m][2]==':'))
                {
                    for(i=0; i<NUM_VARS; i++)
                    {
                        for(j=0; j<MAX_DATALOG_SAMPLES;j++)
                        {
                          for(k=0; k<NUM_VALUES;k++)
                          {
                          DataLogger[i][j].value[k]=0.0;
                          if(k<NUM_RAW)DataLogger[i][j].raw[k]=0.0;
                          }
                          }
                    }
                    // do data logging
                    num_samples=(long)atof(&argv[m][3]);
                    if(num_samples>MAX_DATALOG_SAMPLES)num_samples=MAX_DATALOG_SAMPLES; else if(num_samples<=1)num_samples=1;
                    sprintf(printBuffer, "Logging the Readings Below (Max. Number of Samples: %3.1fk)..Number of Samples", (MAX_DATALOG_SAMPLES/1000.0));
                    doDotsSys(printBuffer, ":");
                    printf("%d\n", num_samples);
                    printLogObject('+', VAR_BATT, 0);
                    printLogObject('+', VAR_LDR, 0);
                    for(i=0; i<NUM_VARS; i++)
                    {
                      for(j=0; j<NUM_VALUES;  j++)
                      {
                        logmask=(variable[i].mode & MODE_LOGMASK)>>4;
                        k=((1<<j) & logmask);
                        if(k!=0)printLogObject('*', i, j);
                      }
                     }
                    printf("\n");
                    doDotsSys("Press Any Key to Stop Data Logging", ":");
                    printf("Waiting.\r");
                    i=setWaitImode(LOGGING_MODE);
                    if(i==0)
                    {
                    DelayMs(1000);
                    doDotsSys("Press Any Key to Stop Data Logging", ":");
                    printf("Starting!\n");
                    nlogsamples=0;
                    logexit=0;
                    startt=clock();
                    endt=startt;
                    totalt=startt;
                    totalTimeElapsed=0.0;
                    timeElapsed=0.0;
                    while((logexit==0)&&(nlogsamples<num_samples))
                    {
                    zz=0;
                    while((logexit==0)&&(zz<NUM_UPDATE_VARS))
                    {
                    i=readVariable(zz, &localerror);
                    if(localerror!=0)
                    { 
                                     printf("Error.\n"); 
                                     exit=1; 
                    } 
                    if((zz<NUM_VARS)&&(variable[zz].updateTime<=variable[zz].oldupdateTime))zz--; 
                    else 
                    {
                    copyToDataLogger(zz, nlogsamples);
                    variable[zz].oldupdateTime=variable[zz].updateTime;
                    }
                    zz++;
                    }
                    startt=endt;
                    endt=clock();
                    timeElapsed=(DOUBLE)(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                    if(timeElapsed>0.0)samplingFreq=1.0/timeElapsed; else samplingFreq=0.0;
                    totalTimeElapsed=(DOUBLE)(endt-totalt)/(DOUBLE)CLOCKS_PER_SEC;
                    if(exit==0)
                    sprintf(printBuffer, "Time Elapsed: %3.3f sec. Sampling Frequency: %3.3f Hz. Data Logging Completed", totalTimeElapsed, samplingFreq);
                    doDotsSys(printBuffer, ":");
                    printf("%d%c\r",(nlogsamples+1)*100/num_samples, '%');
                    nlogsamples++;
                    if(kbhit())logexit=1;
                    }
                    //i=setWaitImode(0);
                    printf("\n");
                    if((num_samples>0)&&(nlogsamples>0))
                    { 
                    writeDataLoggerToFile(nlogsamples, num_samples, "", 0); 
                    }
                    exit=1; 
                    } else
                    {
                          localerror=1;
                          exit=1;
                    }
                } else
                if((argv[m][1]=='l')&&(argv[m][2]==':'))
                {
                    for(i=0; i<NUM_VARS; i++)
                    {
                        for(j=0; j<MAX_DATALOG_SAMPLES;j++)
                        {
                          for(k=0; k<NUM_VALUES;k++)
                          {
                          DataLogger[i][j].value[k]=0.0;
                          if(k<NUM_RAW)DataLogger[i][j].raw[k]=0.0;
                          }
                          }
                    }
                    // do data logging
                    copyStringSubIndexGeneral(argBuffer[0], &argv[m][3], 0, ':');
                    copyStringSubIndexGeneral(argBuffer[1], &argv[m][3], 1, ':');
                    num_samples=(long)atof(argBuffer[0]);
                    if(num_samples>MAX_DATALOG_SAMPLES)num_samples=MAX_DATALOG_SAMPLES; else if(num_samples<=1)num_samples=1;
                    sprintf(printBuffer, "Logging the Readings Below (Max. Number of Samples: %3.1fK)..Number of Samples", (MAX_DATALOG_SAMPLES/1000.0));
                    doDotsSys(printBuffer, ":");
                    printf("%d\n", num_samples);
                    printLogObject('+', VAR_BATT, 0);
                    printLogObject('+', VAR_LDR, 0);
                    for(i=0; i<NUM_VARS; i++)
                    {
                      for(j=0; j<NUM_VALUES;  j++)
                      {
                        logmask=(variable[i].mode & MODE_LOGMASK)>>4;
                        k=((1<<j) & logmask);
                        if(k!=0)printLogObject('*', i, j);
                      }
                     }
                    printf("\n");
                    doDotsSys("Press Any Key to Stop Data Logging", ":");
                    printf("Waiting.\r");
                    i=setWaitImode(LOGGING_MODE);
                    if(i==0)
                    {
                    DelayMs(1000);
                    doDotsSys("Press Any Key to Stop Data Logging", ":");
                    printf("Starting!\n");
                    nlogsamples=0;
                    logexit=0;
                    startt=clock();
                    endt=startt;
                    totalt=startt;
                    totalTimeElapsed=0.0;
                    timeElapsed=0.0;
                    while((logexit==0)&&(nlogsamples<num_samples))
                    {
                    zz=0;
                    while((logexit==0)&&(zz<NUM_UPDATE_VARS))
                    {
                    i=readVariable(zz, &localerror);
                    if(localerror!=0)
                    { 
                                     printf("Error.\n"); 
                                     exit=1; 
                    } 
                    if((zz<NUM_VARS)&&(variable[zz].updateTime<=variable[zz].oldupdateTime))zz--; 
                    else 
                    {
                    copyToDataLogger(zz, nlogsamples);
                    variable[zz].oldupdateTime=variable[zz].updateTime;
                    }
                    zz++;
                    }
                    startt=endt;
                    endt=clock();
                    timeElapsed=(DOUBLE)(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                    if(timeElapsed>0.0)samplingFreq=1.0/timeElapsed; else samplingFreq=0.0;
                    totalTimeElapsed=(DOUBLE)(endt-totalt)/(DOUBLE)CLOCKS_PER_SEC;
                    if(exit==0)
                    sprintf(printBuffer, "Time Elapsed: %3.3f sec. Sampling Frequency: %3.3f Hz. Data Logging Completed", totalTimeElapsed, samplingFreq);
                    doDotsSys(printBuffer, ":");
                    printf("%d%c\r",(nlogsamples+1)*100/num_samples, '%');
                    nlogsamples++;
                    if(kbhit())logexit=1;
                    }
                    //i=setWaitImode(0);
                    printf("\n");
                    if((num_samples>0)&&(nlogsamples>0))
                    { 
                    writeDataLoggerToFile(nlogsamples, num_samples, &argBuffer[1][0], 1); 
                    }
                    exit=1; 
                    } else
                    {
                          printf("\n");
                          localerror=1;
                          exit=1;
                    }
                }
                else
              if(argv[m][1]=='h')
              {
                    showHelpScreen();
              } else
              {
               printf("Syntax Error. Try one of the following options:\n");
               showHelpScreen();
               }
            }
            m++;
        } 
    }

    printf("\n");

    if(cancel==0)
    {
    i=putStrings((BYTE*)&Strings, (BYTE*)&StringsCmp, stringsSize, &localerror);
    if(localerror!=0)
    {
    doDotsSys("Writing Strings.",":");
    printf("Error.\n");
    }
    else
    {
    if(i!=0)
    {
    sprintf(printBuffer, "Writing Flash. Bytes Written: %d Bytes. Flash Programmed: %d%c. Flash Verified", i, (int)(100.0*alignNumberBoundary(i, STRINGPKSIZE)/stringsSize), '%');
    doDotsSys(printBuffer, ":");
    zz=getStrings((BYTE*)&StringsCmp, (BYTE*)&StringsCmp, stringsSize, &localerror);
    if(localerror==0)
    {
        zz=stringsSize-(cmpPtr((BYTE*)&Strings, (BYTE*)StringsCmp, stringsSize));
        zz=(int)(zz*100.0/stringsSize);
        printf("%d%c\n", zz, '%');
        if(zz<100)localerror=1; else localerror=0;
        
     } else
     { 
     printf("Error.\n");
     localerror=1;
     }
     }
    }

    if(polyUpdate==0)
    {
    //doDotsSys("Polynomial Table and Indexes Unchanged. Polynomial Memory In Use", ":");
    } else
    {
    doDotsSys("Updating Polynomial Table and Indexes. Polynomial Memory In Use", ":");
    i=putPolyInfo(&localerror);
    printf("%2.0f%c\n", (double)polyMemoryUsed*100.0/(MAX_POLY-1), '%');
    polyUpdate=0;
    }

    if(localerror!=0)
    { 
    printf("Error.\n"); 
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //outcalibrationfile.close();
    //calibrationfile.close();
    doDotsSys("Status", ":");
    printf("Some Errors.\n");
    return 0; 
    } else 
    {
    //printf("%2.0f%c\n", (double)polyMemoryUsed*100.0/(MAX_POLY-1), '%');
    }

    // now write outstanding variables...
    zz=0;
    ibuffer[0]=0;
    for(i=0; i<NUM_VARS; i++)
    {
    if(variable[i].cmptotal!=0)
        { 
            (void)setWaitImode(FLASHWRITE_MODE);
            sprintf(ibuffer, "%s #%d", ibuffer, i); 
            putVariable(i, &myerror);
            if(myerror!=0)localerror|=myerror;
            if(variable[i].cmptotal!=0)zz++;
        }
    }
    //
    sprintf(printBuffer, "Checking for Unwritten Cached Variables%s", ibuffer); 
    doDotsSys(printBuffer, ":");
    if(zz==0)printf("Ok.\n"); else { printf("Error.\n"); }
    if(finalSystemWrite!=0)
    {
    (void)setWaitImode(FLASHWRITE_MODE);
    sprintf(printBuffer, "Flushing System Settings");
    doDotsSys(printBuffer, ":");
    i=sendSettings(&systemSystem[0], &localerror);
    if(localerror==0)printf("Ok.\n"); else printf("Error.\n");
    } else
    {


    }
/*
    i=writeCalibrationPoints();
    if(i!=0)
    {
    localerror|=setWaitImode(0);
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    datalog.close();
    outcalibrationfile.close();
    mapfile.close();
    calibrationfile.close();
    return 0; 
    } 
  */

    } else
    {
        doDotsSys("Actions Cancelled. No Settings Will Be Saved", ":");
        printf("Abort!\n");
    }

    localerror|=(setWaitImode(0));
    if (myOutPipe != INVALID_HANDLE_VALUE)MPUSBClose(myOutPipe);
    if (myInPipe  != INVALID_HANDLE_VALUE)MPUSBClose(myInPipe);
    myOutPipe = myInPipe = INVALID_HANDLE_VALUE;
    //datalog.close();
    //mapfile.close();
    //calibrationfile.close();
    //outcalibrationfile.close();
    doDotsSys("Status", ":");
    if(autoSizeErrors!=0)printf("Auto Size Errors: %d\n", autoSizeErrors);
    else
    {
    if(localerror==0)printf("All Ok.\n"); 
    else printf("Some Errors.\n");
    }
    return 0;
}

//end main

//---------------------------------------------------------------------------
                /*
                else
                if(argv[m][1]=='v')
                {
                    //  set current variable number
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        currentVariableNumber=(int)atof(&argv[m][3]);
                        if(currentVariableNumber<0)currentVariableNumber=0; else if(currentVariableNumber>=NUM_VARS)currentVariableNumber=NUM_VARS-1;
                        printf("Current Variable Number set to %d...Ok.\n", currentVariableNumber);
                    } else printf("Syntax error. Please provide an argument.\n");
                } else
                if(argv[m][1]=='i')
                {
                    //  set current index number
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        currentIndexNumber=(int)atof(&argv[m][3]);
                        if(currentIndexNumber<0)currentIndexNumber=0; else if(currentIndexNumber>=NUM_STRINGS_PER_VAR)currentIndexNumber=NUM_STRINGS_PER_VAR-1;
                        printf("Current Index Number set to %d...Ok.\n", currentIndexNumber);
                    } else printf("Syntax error. Please provide an argument.\n");
                } else
                if(argv[m][1]=='x')
                {
                    //  read variable information
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Reading Variable %d...", (int)myargument);
                        datapacket.index=0;
                        datapacket.cmd=CAR_DISPLAY_READ_VARIABLE_INFORMATION;
                        datapacket.varn=myargument;
                        //
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        j=getVariableInfo((int)myargument, &indatapacket,GET_DIR,VARIABLE_MODE);
                        showVariableInfo((int)myargument);
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");
              
                } else
                if(argv[m][1]=='t')
                {
                    //  read variable information
                    myargument=0;
                    i=openDevice();
                    if(i==0)
                    {
                    printFailedToOpenDeviceMessage();
                    } else
                    if(i==1)
                    {
                        printf("Reading String...");
                        datapacket.cmd=CAR_DISPLAY_READ_STRING;
                        datapacket.varn=currentVariableNumber;
                        datapacket.index=currentIndexNumber;
                        //
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        printf("String is: %s\n",&indatapacket.data[0]);
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                } else
                if(argv[m][1]=='m')
                {
                    // set the variable's mode
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        j=(int)(myargument);
                        printf("Setting the variable mode to: %d...",j);
                        datapacket.cmd=CAR_DISPLAY_SET_MODE;
                        datapacket.varn=currentVariableNumber;
                        datapacket.index=currentIndexNumber;
                        datapacket.mode=j;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");
                } else
                if(argv[m][1]=='q')
                {
                    // set the variable's update frequency
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        j=(int)(myargument);
                        printf("Setting the update frequency to : %d...",j);
                        datapacket.cmd=CAR_DISPLAY_SET_FREQUENCY;
                        datapacket.varn=currentVariableNumber;
                        datapacket.index=currentIndexNumber;
                        datapacket.arg=j;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");
                } else
                if(argv[m][1]=='p')
                {
                    // set the scroll speed
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the scroll speed to : %d...", (myargument));
                        datapacket.cmd=CAR_DISPLAY_SET_SCROLL_SPEED;
                        datapacket.arg=(int)myargument;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");      
                } else
                 if(argv[m][1]=='d')
                {
                    // set the current variable
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the current display object to : %d...", (myargument));
                        datapacket.cmd=CAR_DISPLAY_SET_DISPLAY_OBJECT;
                        datapacket.arg=(int)myargument;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");      
                } else
                if(argv[m][1]=='b')
                {
                    // set the display brightness level
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the Display Brightness to : %d...", (myargument));
                        datapacket.cmd=CAR_DISPLAY_SET_BRIGHTNESS;
                        datapacket.arg=(int)myargument;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");      
                } else
                if(argv[m][1]=='z')
                {
                    // Enter Graphics Mode
                    enterGraphicsMode();
                } else
                if(argv[m][1]=='u')
                {
                    // Get all variable's information: data logging...
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        setImode(2);
                        exit=0;
                        myargument=1;               // default
                        myargument=(int)atof(&argv[m][3]);
                        num_samples=myargument;
                        if(num_samples>MAX_DATALOG_SAMPLES)num_samples=MAX_DATALOG_SAMPLES; else if(num_samples<=0)num_samples=1;
                        printf("Reading All Variables, Samples: %d (max: %d)\n", num_samples, MAX_DATALOG_SAMPLES);
                        nn=0;
                        while((exit==0)&&(nn<num_samples))
                        {
                        zz=0;
                        while((exit==0)&&(zz<NUM_VARS))
                        {
                        datapacket.index=0;
                        datapacket.cmd=CAR_DISPLAY_READ_VARIABLE_INFORMATION;
                        datapacket.varn=zz;
                        //
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        j=getVariableInfo(zz, &indatapacket,GET_DIR,VARIABLE_MODE);
//                        printf("j=%d\n",j);
                        if(variable[zz].updateTime<=variable[zz].oldupdateTime)zz--; else 
                        {
                          copyToDataLogger(zz, nn);
                        }
                        } 
                        else 
                        {
                          printf("\nFailed, Aborting.\n");
                          num_samples=0;
                          exit=1;
                        }
                        } else 
                        {
                          printf("\nFailed, Aborting.\n");
                          num_samples=0;
                          exit=1;
                         }
                         zz++;
                        }
                        if(exit==0)printf("Data Logging: %d%c complete...\r", (nn+1)*100/num_samples, '%');
                        nn++;
                        }
                        exit=1;  
                        printf("Number of samples written: %d...\n",num_samples);
                        setImode(0);                  
                        }
                    }
                } else
                if(argv[m][1]=='c')
                {
                    // push point for calibration...
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Pushing a Calibration Point on Channel No.: %d ...", (int)(myargument));
                        datapacket.cmd=CAR_DISPLAY_PUSH_POINT;
                        datapacket.varn=myargument+1;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        printf("Press the S1 button to freeze the point...\n");
                        exit=0;
                        pushVariable=(myargument+1);
                        freezePoint.done=0;
                        pushVariable=1;
                        while((freezePoint.done==0)&&(exit==0))
                        {
                        datapacket.index=0;
                        datapacket.cmd=CAR_DISPLAY_READ_VARIABLE_INFORMATION;
                        datapacket.varn=myargument;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                         j=getVariableInfo((int)myargument, &indatapacket,GET_DIR,VARIABLE_MODE);
                         showVariableInfo((int)myargument);
                         updateTime();
                        } else { printf("Error.\n"); exit=1; }
                        } else { printf("Error.\n"); exit=1; }   
                                                   
                        }
                        if(exit==0)
                        {
                        j=getVariableInfo((int)myargument, &indatapacket,GET_DIR,VARIABLE_MODE);
                        printf("Point Captured... Please Enter the correct Value: ");
                        scanf("%f", &ftemp);
                        printf("Is the value %6.6f correct? (Y/N)\n",ftemp);
                        ctemp=mygetch(&globalcontrolcode);
                            if((ctemp=='y')||(ctemp=='Y'))
                            {
                            printf("Understood...\n");
                            } else printf("Discarded...\n");
                        datapacket.cmd=CAR_DISPLAY_PUSH_POINT;
                        datapacket.varn=0;
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        } else printf("Error.\n");
                        } else printf("Error.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");                     
                } else
                if(argv[m][1]=='y')
                {
                    // set the twenty four hour time mode
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the twenty four hour time mode to: %d ...", (int)(myargument));
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");                     
                } else
                if(argv[m][1]=='d')
                {
                    // set the display timeout period
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the display timeout period to: %d second(s) ...", (int)(myargument));
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");                     
                }
                else
                if(argv[m][1]=='r')
                {
                    i=openDevice();
                    if(i==0)
                    {
                        printFailedToOpenDeviceMessage();
                        
                    } else
                    if(i==1)
                    {
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                    } else
                    {
                        printf("Device is not open!\n");
                    }  
                } else
                if(argv[m][1]=='c')
                {
                    //  set the reference sense resistor in mOhms
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the reference sense resistor value to: %d mOhms...", (int)myargument);
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");
              
                } else
                if(argv[m][1]=='v')
                {
                    //  set the reference voltage in mV
                    myargument=0;
                    if(argv[m][2]==':')
                    {
                        myargument=(int)atof(&argv[m][3]);
                        i=openDevice();
                        if(i==0)
                        {
                        printFailedToOpenDeviceMessage();
                        } else
                        if(i==1)
                        {
                        printf("Setting the reference voltage to: %d mV...", (int)myargument);
                        res=MPUSBWrite(myOutPipe,&datapacket,EPSIZE,&nb,USBTIMEOUT);
                        if(res==MPUSB_SUCCESS)
                        {
                        res=MPUSBRead(myInPipe, &indatapacket, BOOT_EP_SIZE, &nb, 500);
                        if(res==MPUSB_SUCCESS)
                        {
                        printf("Ok.\n");
                        if(m+1==argc)showInfo(&indatapacket);
                        }
                        else
                        {
                        printf("Error.\n");
                        }
                        } else printf("Error.\n");
                        
                        } else
                        {
                        printf("Device is not open!\n");
                        }
                    } else printf("Syntax error. Please provide an argument.\n");
              
                } else
                {
                    printf("Try one of the following options instead:\n");
                    showHelpScreen();
            }
            
            } 
*/
/*
                if(argv[m][1]=='c')
                {
                    // get a freezepoint calibration point
                    myargument=(long)atof(&argv[m][3]);
                    if(myargument<0)myargument=0; else if(myargument>=NUM_VARS)myargument=NUM_VARS-1;
                    getFreezePoint(currentVariableNumber,&localerror);
                    if(localerror!=0)exit=1;
                    else
                    {
                tryagain:
                    printf("Point Captured... Please Enter the Correct Value: ");
                    scanf("%f", &ftemp);
                    printf("Is the value %6.6f correct? Y(es)/N(o)/(D)iscard...",ftemp);
                    ctemp=mygetch(&globalcontrolcode);
                    if((ctemp=='y')||(ctemp=='Y'))
                    {
                        printf("Understood...\n");
                        freezePoint.value[currentIndexNumber]=ftemp;
                        printf("Adding Point...");
                        addCalibrationPoint(currentVariableNumber, currentIndexNumber, &freezePoint, &localerror, &duplicate);
                        if(localerror!=0)
                        {
                            if(localerror==1)
                            printf("Out of Memory Error.\n");
                            else
                            if(localerror==2)
                            printf("Zero X Point Error.\n");
                            else
                            {
                                printf("Error.\n");
                            }
                            exit=1;
                        } else
                        {
                            if(duplicate==0)
                            {
                                  printf("New Point Added...Ok\n");
                                  variable[currentVariableNumber].interpolation[currentIndexNumber]+=1;
                            } else
                            {
                                  printf("New Point Updated (Duplicate X value previously loaded)... Ok.\n");
                            }                       
                            pointAdded=1;     
                            printf("Total Number of Calibration Points: %d\n", getNumberOfCalibrationPoints());
                            printf("Recomputing Polynomial...");
                            i=computeInsertAllPolynomials();
                            if(i!=0)
                            { 
                            printf("Error.\n"); 
                            } 
                            else 
                            {
                            printf("Ok.\n");
                            printf("The new polynomial is: ");
                            printPolynomial(currentVariableNumber, currentIndexNumber);
                            printf("Writing Variable Information...");
                            i=putVariable(currentVariableNumber, &localerror);
                            if(localerror!=0)
                            { 
                              printf("Error.\n"); 
                              exit=1; 
                            }
                            else
                            {
                              printf("Ok.\n");
                              printf("Updating Polynomial Memory...");
                              putPolyInfo(&localerror);
                              if(localerror!=0)
                              {
                              printf("Error.\n");
                              exit=1;
                              } else
                              {
                                    
                                    printf("Writing EEPROM Polynomial Tables and Coefficients...");
                                    i=writePolyEE((byte*)&polyMemory[0], &localerror);
                                    if(localerror!=0)
                                    {
                                      printf("Error.\n"); exit=1; 
                                    }
                                    else
                                    {
                                    printf("Ok.\n");    
                                    }
                                }
                              }
                            }
                         }
                        } else 
                        if((ctemp=='D')||(ctemp=='d'))
                        {
                               printf("Point Discarded...\n");
                        } else { printf("\n"); goto tryagain; }
                        
                        
                        i=writeRamVariable("pushVariable", 1, 0, SIZEBYTE, &localerror);
                        if(localerror!=0){ printf("Error.\n"); exit=1; }
                        else
                        {
                        i=writeRamVariable("pushVariable", 0, 0, SIZEBYTE, &localerror);
                        if(localerror!=0){ printf("Error.\n"); exit=1; }
                        else
                        {
                        printf("Ok.\n");
                        }
                    }
                  }
                } else
                
                if(argv[m][1]=='q')
                {
                // rename a variable
                sprintf(ibuffer, "%s", &argv[m][2]);
                // ibuffer is now the string
                iindex=insertsString(ibuffer, endIndex, STRING_DELIMITER, &localerror);
                if(localerror==0)
                {
                i=setWaitImode(FLASHWRITE_MODE);
                if(i==0)
                {
                   icharp=(CHARP)addressStringFlash + iindex;
                   //variable[0].name[0]=icharp;
                   //putVariable(0, &localerror);
                   systemName=iindex;
                   writeEEAndRamVariableAutoSize("systemName", systemName, SYSTEMNAMEL_ADR, &localerror);
                   if(localerror==0)printf("String Inserted Ok!\n"); else exit=1;
                 } else localerror=i;
                }
                } else
                if(argv[m][1]=='R')
                {
                // reset the system and restore default values
                writeEEVariable(MAGIC_VALUE_ADR,MAGIC_VALUE+1,SIZEBYTE,&localerror);
                if(localerror!=0)
                {
                doDotsCommand("Requesting Reset", ":");
                printf("Error.\n");
                exit=1;
                }
                else
                {
                 datapacket.cmd=CAR_DISPLAY_RESET;
                 i=sendCommand(&datapacket, &nb, &localerror); 
                 if(localerror!=0)
                 { 
                   doDotsCommand("Requesting Reset", ":");
                   printf("Error.\n"); 
                   exit=1; 
                 }
                 else
                 {
                 open=0;     
                 reqReset=1;
                 ftemp=0.0;
                 jtemp=0.0;
                 startt=clock();
                 myargument=10.0;             // wait up to 10 seconds...
                 while((reqReset==1)&&(timeElapsed<=myargument))
                 {
                  endt=clock();
                  timeElapsed=(DOUBLE)(endt-startt)/(DOUBLE)CLOCKS_PER_SEC;
                  ftemp=timeElapsed;
                  if(((ftemp-jtemp)>0.80)&&((ftemp-jtemp)<1.99))
                  {
                  doDotsCommand("Requesting Reset. All Default Values will be Restored", ":");
                  printf("%0.1f sec.\r", ftemp);
                  }
                  else
                  if((ftemp-jtemp)>=1.99)
                  {
                  jtemp=ftemp;
                  k=MPUSBGetDeviceCount(vid_pid);
                  if(k>0)
                  {
                  reqReset=readRamVariableAutoSize("reqReset", 0, &localerror);
                  if(localerror!=0)
                  {
                  reqReset=1;
                  }
                  }                         
                 }
                }
                doDotsCommand("Requesting Reset. All Default Values will be Restored", ":");
                exit=1;
                if(reqReset==0)localerror=0; else localerror=1;
                if(localerror!=0)
                printf("%0.1f sec. Time Out Error!\n", timeElapsed); else printf("%0.1f sec. Ok.\n", timeElapsed);
                }
               }
              }
              else
              */
