 #include <EEPROM.h>
 #include "EEPROMAnything.h"
 #include <SerialCommand.h>
-
-const int N_ANGLES = 360;                                       // # of angles (0..359)
-const int SHOW_ALL_ANGLES = N_ANGLES;                           // value means 'display all angle data, 0..359'
-
+// ******************************************************************
+// WARNING: If you change 'xv_config', you must change '_EEPROM_ID' *
+//          When it is changed, the EEPROM data will be initialized *
+// ******************************************************************
+const byte _EEPROM_ID = 0x07;                        // used to validate EEPROM initialized (Current as of 26NOV2015 - DSH)
+const byte _EEPROM_SAFETY_CHECK = (-1 - _EEPROM_ID); // used to validate that we haven't written past the end of the EEPROM
+// You may change 'szCURRENT_EEPROM_VERSION' to indicate a new software version, but it is not checked, just displayed
+const char szCURRENT_EEPROM_VERSION[6] = "1.3.0";    // as of 24NOV2015 - DSH
+
+const int _N_ANGLES = 360;                           // # of angles in a circle (0..359)
+// These constants will let us read and write individual variables to the EEPROM - DSH
+const byte _BITS_PER_BYTE = 8;
+const byte _MASK_BYTE = (1 << _BITS_PER_BYTE) - 1;                // (value: 0xFF)
+const unsigned int _MASK_WORD_LSB = _MASK_BYTE;                   // Mask off bottom 8 bits of INTEGER (value:0xFF)
+const unsigned int _MASK_WORD_MSB = _MASK_BYTE << _BITS_PER_BYTE; // Mask off top 8 bits of INTEGER (value:0xFF00)
+
+const int _LEN_BYTE = 1;
+const int _LEN_BOOLEAN = 1;
+const int _LEN_INTEGER = 2;
+const int _LEN_DOUBLE = 4;
+/*
+ * An enumerated list of "What we're displaying" commands
+ * WARNING: IF YOU ADD A VALUE, FIX VARIOUS swich (eOUT) STATEMENTS IN THE CODE BELOW!!!
+ * WARNING: MUST BE LESS THAN 256 VALUES (masked by 0xFF)
+ */
+const byte _eOUT_UNKNOWN = 0;                 // Unknown or uninitialized (value: 0)
+const byte _eOUT_RAW = _eOUT_UNKNOWN + 1;     // ShowRaw = retransmit the seiral data to the USB port (value: 1)
+const byte _eOUT_DIST = _eOUT_RAW + 1;        // ShowDist = display distance data (value: 2)
+const byte _eOUT_ANGLE = _eOUT_DIST + 1;      // ShowAngle = display angle data (value: 3)
+const byte _eOUT_MAX = _eOUT_ANGLE + 1;       // WARNING: This value must fit in 8 bits (range: 0-255) (value: 4)
+/*
+ * An enumerated list of special output requirements, e.g., Show Errors, Show RPM, Show Interval, Show CSV format
+ * NOTE: These are bit-values, so they can be individually set/cleared individually
+ */
+const unsigned int _eSHOW_RPM = 0;                        // Show R.P.M.
+const unsigned int _eSHOW_CSV = _eSHOW_RPM + 1;           // Show in .csv format
+const unsigned int _eSHOW_ERRORS = _eSHOW_CSV + 1;        // Show Errors
+const unsigned int _eSHOW_INTERVAL = _eSHOW_ERRORS + 1;   // Show Interval
+const unsigned int _eSHOW_MAX = _eSHOW_INTERVAL + 1;      // WARNING: This value is a bit shift number, so it must be 0-7 (fits into top byte of 'eOUT')
+/*
+ * The top 8-bits of eOUT indicate special output requirements
+ */
+const unsigned int _OUT_MOD_BASE = 1 << _BITS_PER_BYTE;   // Start the display modifiers in the top 8-bits (value: 0x100)
+/*      MSB                 LSB
+   7 6 5 4 3 2 1 0    7 6 5 4 3 2 1 0
+   x x x x x x x x    n n n n n n n n
+   | | | | | | | + RPM
+   | | | | | | + CSV
+   | | | | } + ERROR
+   | | | | + Interval
+   | | | + RFU 1
+   | | + RFU 2
+   | + RFU 3
+   + RFU 4           
+*/             
+// NOTE: if you add or change these, don't forget to fix up 'showRaw'
+const unsigned int _OUT_MOD_SHOW_RPM =      _OUT_MOD_BASE;              // 1 = show RPM (value: 0x100) manipulated by showRPM/hideRPM
+const unsigned int _OUT_MOD_SHOW_CSV =      _OUT_MOD_SHOW_RPM * 2;      // 1 = show CSV format (value: 0x200)
+const unsigned int _OUT_MOD_SHOW_ERRORS =   _OUT_MOD_SHOW_CSV * 2;      // 1 = show errors (value: 0x400)
+const unsigned int _OUT_MOD_SHOW_INTERVAL = _OUT_MOD_SHOW_ERRORS * 2;   // 1 = show interval (value: 0x800)
+const unsigned int _OUT_MOD_SHOW_RFU_1 =    _OUT_MOD_SHOW_INTERVAL * 2; // 1 = reserved future use 1 (value: 0x1000)
+const unsigned int _OUT_MOD_SHOW_RFU_2 =    _OUT_MOD_SHOW_RFU_1 * 2;    // 1 = reserved future use 2 (value: 0x2000)
+const unsigned int _OUT_MOD_SHOW_RFU_3 =    _OUT_MOD_SHOW_RFU_2 * 2;    // 1 = reserved future use 3 (value: 0x4000)
+const unsigned int _OUT_MOD_SHOW_RFU_4 =    _OUT_MOD_SHOW_RFU_3 * 2;    // 1 = reserved future use 4 (value: 0x8000)
+
+#define _MASK_eOUT_SHOW _MASK_WORD_LSB                  // mask 'eOUT' for what we're showing (value:0xFF)
+#define _MASK_eOUT_MODIFIER _MASK_WORD_MSB              // mask 'eOUT' for display modifiers (value:0xFF00)
+
+const int _EE_LEN_ID = _LEN_BYTE;                       // value:1
+const int _EE_LEN_VERSION = 6;                          // value:6 (arbitrary, but currently contains, e.g., string "1.3.0" (plus 0-terminator)
+const int _EE_LEN_MOTOR_PWM_PIN = _LEN_BYTE;            // value:1
+const int _EE_LEN_RPM_SETPOINT = _LEN_DOUBLE;           // value:4
+const int _EE_LEN_RPM_MIN = _LEN_DOUBLE;                // value:4
+const int _EE_LEN_RPM_MAX = _LEN_DOUBLE;                // value:4
+const int _EE_LEN_PWM_MAX = _LEN_DOUBLE;                // value:4
+const int _EE_LEN_PWM_MIN = _LEN_DOUBLE;                // value:4
+const int _EE_LEN_SAMPLE_TIME = _LEN_INTEGER;           // value:2
+const int _EE_LEN_Kp = _LEN_DOUBLE;                     // value:4
+const int _EE_LEN_Ki = _LEN_DOUBLE;                     // value:4
+const int _EE_LEN_Kd = _LEN_DOUBLE;                     // value:4
+const int _EE_LEN_MOTOR_ENABLE = _LEN_BOOLEAN;          // value:1
+const int _EE_LEN_SHOW_ALL_ANGLES = _LEN_BOOLEAN;       // value:1
+const int _EE_LEN_eOUT = _LEN_INTEGER;                  // value:2
+const int _EE_LEN_aryAngles = _N_ANGLES * _LEN_BOOLEAN; // value:360
+const int _EE_LEN_SAFETY = _LEN_BYTE;                   // value:1
+
+const int _EE_OFFSET_ID = 0;                                                            // value:0
+const int _EE_OFFSET_VERSION = _EE_OFFSET_ID + _EE_LEN_ID;                              // value:1
+const int _EE_OFFSET_MOTOR_PWM_PIN = _EE_OFFSET_VERSION + _EE_LEN_VERSION ;             // value:7
+const int _EE_OFFSET_RPM_SETPOINT = _EE_OFFSET_MOTOR_PWM_PIN + _EE_LEN_MOTOR_PWM_PIN ;  // value:8
+const int _EE_OFFSET_RPM_MIN = _EE_OFFSET_RPM_SETPOINT + _EE_LEN_RPM_SETPOINT ;         // value:12
+const int _EE_OFFSET_RPM_MAX = _EE_OFFSET_RPM_MIN + _EE_LEN_RPM_MIN ;                   // value:16
+const int _EE_OFFSET_PWM_MAX = _EE_OFFSET_RPM_MAX + _EE_LEN_RPM_MAX ;                   // value:20
+const int _EE_OFFSET_PWM_MIN = _EE_OFFSET_PWM_MAX + _EE_LEN_PWM_MAX ;                   // value:24
+const int _EE_OFFSET_SAMPLE_TIME = _EE_OFFSET_PWM_MIN + _EE_LEN_PWM_MIN ;               // value:28
+const int _EE_OFFSET_Kp = _EE_OFFSET_SAMPLE_TIME + _EE_LEN_SAMPLE_TIME ;                // value:30
+const int _EE_OFFSET_Ki = _EE_OFFSET_Kp + _EE_LEN_Kp ;                                  // value:34
+const int _EE_OFFSET_Kd = _EE_OFFSET_Ki + _EE_LEN_Ki ;                                  // value:38
+const int _EE_OFFSET_MOTOR_ENABLE = _EE_OFFSET_Kd + _EE_LEN_Kd ;                        // value:42
+const int _EE_OFFSET_SHOW_ALL_ANGLES = _EE_OFFSET_MOTOR_ENABLE + _EE_LEN_MOTOR_ENABLE ; // value:43
+const int _EE_OFFSET_eOUT = _EE_OFFSET_SHOW_ALL_ANGLES + _EE_LEN_SHOW_ALL_ANGLES ;      // value:44
+const int _EE_OFFSET_aryAngles = _EE_OFFSET_eOUT + _EE_LEN_eOUT ;                       // value:46
+const int _EE_OFFSET_SAFETY = _EE_OFFSET_aryAngles + _EE_LEN_aryAngles ;                // value:406
+const int _EEPROM_Config_LEN = _EE_OFFSET_SAFETY + _EE_LEN_SAFETY ;                     // value:407
+/*
+ * Default values for EEPROM
+ */
+const byte _DEFAULT_motor_pwm_pin = 9;            // pin connected N-Channel Mosfet
+const double _DEFAULT_rpm_setpoint = 200;         // desired RPM (arrived at this value by testing)
+const double _DEFAULT_rpm_min = 200;
+const double _DEFAULT_rpm_max = 300;
+const double _DEFAULT_pwm_min = 100;
+const int _DEFAULT_pwm_max = 1023;
+const int _DEFAULT_sample_time = 20;  
+const double _DEFAULT_Kp = 2.0;                   // PID tuning values
+const double _DEFAULT_Ki = 1.0;
+const double _DEFAULT_Kd = 0.0;
+const boolean _DEFAULT_bMotorEnable = true;       // default is to turn the motor ON  
+const boolean _DEFAULT_bShowAllAngles = false;    // default 
+const byte _DEFAULT_eOUT = _eOUT_RAW;             // default to "RAW" display
+const boolean _DEFAULT_bANGLE = false;            // default for entries in 'aryAngle'
+const double _DEFAULT_pwm_val = 500;              // 50% duty cycle
+const unsigned long _DEFAULT_motor_check_interval = 200;
+const unsigned int _DEFAULT_rpm_err_thresh = 10;
+/* 
+ *  Define the structure of the record that gets written to the EEPROM
+ */
 struct EEPROM_Config {
-  byte id;
-  char version[6];
-  int motor_pwm_pin;    // pin connected to mosfet for motor speed control
-  double rpm_setpoint;  // desired RPM (uses double to be compatible with PID library)
+  byte id;                                // value == _EEPROM_ID
+  char szVersion[_EE_LEN_VERSION];        // e.g., "1.3.0" plus 0-terminator
+  byte motor_pwm_pin;                     // pin connected to mosfet for motor speed control, e.g., 9
+  double rpm_setpoint;                    // desired RPM (uses double to be compatible with PID library)
   double rpm_min;
   double rpm_max;
-  double pwm_max;       // max analog value.  probably never needs to change from 1023
-  double pwm_min;       // min analog pulse value to spin the motor
-  int sample_time;      // how often to calculate the PID values
-
+  double pwm_max;                         // max analog value.  probably never needs to change from 1023
+  double pwm_min;                         // min analog pulse value to spin the motor
+  int sample_time;                        // how often to calculate the PID values
   // PID tuning values
   double Kp;
   double Ki;
   double Kd;
-
-  boolean motor_enable;  // to spin the laser or not.  No data when not spinning
-  boolean raw_data;  // to retransmit the seiral data to the USB port
-  boolean show_dist;  //  controlled by ShowDist and HideDist commands
-  boolean show_rpm;  // controlled by ShowRPM and HideRPM commands
-  unsigned int show_angle;  // controlled by ShowAngle (0 - 359, 360 shows all)
+  boolean bMotorEnable;                   // true = spin the motor.  NOTE: No data is available when not spinning
+  boolean bShowAllAngles;                 // true = shows all angles
+  unsigned int eOUT;                      // What we're displaying now (2 8-bit nibbles)
+  // Bottom 8-bits = a value indicating what we're supposed to print, i.e., { unknown; raw; distance; angle }
+  // Top 8-bits = a bit-mask with display modifiers, e.g., {show RPM; show CSV format; show errors; show interval}
+  boolean aryAngles[_N_ANGLES];           // each entry = true if we're supposed to display the corresponding angle
+  byte safety;                            // a value to make sure that EEPROM data hasn't been overwritten
 } 
 xv_config;
 
-const byte EEPROM_ID = 0x05;  // used to validate EEPROM initialized
-
-double pwm_val = 500;  // start with ~50% power
+double pwm_val = _DEFAULT_pwm_val;        // start with ~50% power
 double pwm_last;
 double motor_rpm;
 unsigned long now;
 unsigned long motor_check_timer = millis();
-unsigned long motor_check_interval = 200;  
-unsigned int rpm_err_thresh = 10;  // 2 seconds (10 * 200ms) to shutdown motor with improper RPM and high voltage
+unsigned long motor_check_interval = _DEFAULT_motor_check_interval;  
+unsigned int rpm_err_thresh = _DEFAULT_rpm_err_thresh;  // 2 seconds (10 * 200ms) to shutdown motor with improper RPM and high voltage
 unsigned int rpm_err = 0;
 unsigned long curMillis;
 unsigned long lastMillis = millis();
 
-// Added by DSH
-const unsigned char COMMAND = 0xFA;        // Start of new packet
-const int INDEX_LO = 0xA0;                 // lowest index value
-const int INDEX_HI = 0xF9;                 // highest index value
-
-const int N_DATA_QUADS = 4;                // there are 4 groups of data elements
-const int N_ELEMENTS_PER_QUAD = 4;         // viz., 0=distance LSB; 1=distance MSB; 2=sig LSB; 3=sig MSB
+// Some Packet-related constants (DSH)
+const unsigned char _COMMAND = 0xFA;       // Start of new packet
+const int _INDEX_LO = 0xA0;                // lowest index value
+const int _INDEX_HI = 0xF9;                // highest index value
+
+const int _N_DATA_QUADS = 4;               // there are 4 groups of data elements
+const int _N_ELEMENTS_PER_QUAD = 4;        // viz., 0=distance LSB; 1=distance MSB; 2=sig LSB; 3=sig MSB
 
 // Offsets to bytes within 'Packet'
-const int OFFSET_TO_START = 0;
-const int OFFSET_TO_INDEX = OFFSET_TO_START + 1;
-const int OFFSET_TO_SPEED_LSB = OFFSET_TO_INDEX + 1;
-const int OFFSET_TO_SPEED_MSB = OFFSET_TO_SPEED_LSB + 1;
-const int OFFSET_TO_4_DATA_READINGS = OFFSET_TO_SPEED_MSB + 1;
-const int OFFSET_TO_CRC_L = OFFSET_TO_4_DATA_READINGS + (N_DATA_QUADS * N_ELEMENTS_PER_QUAD);
-const int OFFSET_TO_CRC_M = OFFSET_TO_CRC_L + 1;
-const int PACKET_LENGTH = OFFSET_TO_CRC_M + 1;  // length of a complete packet
+const int _OFFSET_TO_START = 0;
+const int _OFFSET_TO_INDEX = _OFFSET_TO_START + 1;
+const int _OFFSET_TO_SPEED_LSB = _OFFSET_TO_INDEX + 1;
+const int _OFFSET_TO_SPEED_MSB = _OFFSET_TO_SPEED_LSB + 1;
+const int _OFFSET_TO_4_DATA_READINGS = _OFFSET_TO_SPEED_MSB + 1;
+const int _OFFSET_TO_CRC_L = _OFFSET_TO_4_DATA_READINGS + (_N_DATA_QUADS * _N_ELEMENTS_PER_QUAD);
+const int _OFFSET_TO_CRC_M = _OFFSET_TO_CRC_L + 1;
+const int _PACKET_LENGTH = _OFFSET_TO_CRC_M + 1;  // length of a complete packet
 // Offsets to the (4) elements of each of the (4) data quads
-const int OFFSET_DATA_DISTANCE_LSB = 0;
-const int OFFSET_DATA_DISTANCE_MSB = OFFSET_DATA_DISTANCE_LSB + 1;
-const int OFFSET_DATA_SIGNAL_LSB = OFFSET_DATA_DISTANCE_MSB + 1;
-const int OFFSET_DATA_SIGNAL_MSB = OFFSET_DATA_SIGNAL_LSB + 1;
-
-int Packet[PACKET_LENGTH];                 // an input packet
-int ixPacket = 0;                          // index into 'Packet' array
-const int VALID_PACKET = 0;
-const int INVALID_PACKET = VALID_PACKET + 1;
-const byte INVALID_DATA_FLAG = (1 << 7);   // Mask for byte 1 of each data quad "Invalid data"
-boolean bShowInterval;                     // true = show time interval, once per revolution, at angle=0
-
-boolean aryAngles[N_ANGLES];               // true if we're supposed to display the corresponding angle
+const int _OFFSET_DATA_DISTANCE_LSB = 0;
+const int _OFFSET_DATA_DISTANCE_MSB = _OFFSET_DATA_DISTANCE_LSB + 1;
+const int _OFFSET_DATA_SIGNAL_LSB = _OFFSET_DATA_DISTANCE_MSB + 1;
+const int _OFFSET_DATA_SIGNAL_MSB = _OFFSET_DATA_SIGNAL_LSB + 1;
+
+int Packet[_PACKET_LENGTH];                 // an input packet
+int ixPacket = 0;                           // index into 'Packet' array
+const int _VALID_PACKET = 0;
+const int _IN_VALID_PACKET = _VALID_PACKET + 1;
+const byte _INVALID_DATA_FLAG = (1 << 7);   // Mask for byte 1 of each data quad "Invalid data"
+
+boolean bEEPROM_Initialized = false;        // true if EEPROM was upgraded to latest software version
 
 /* REF: https://github.com/Xevel/NXV11/wiki
 The bit 7 of byte 1 seems to indicate that the distance could not be calculated.

/*
  XV Lidar Controller v1.2.2
 
 Copyright 2014 James LeRoy getSurreal
 https://github.com/getSurreal/XV_Lidar_Controller
 http://www.getsurreal.com/products/xv-lidar-controller
 
 Modified to add CRC checking - Doug Hilton, WD0UG November, 2015 mailto: six.speed (at) yahoo (dot) com
 Modified to add ShowErrors / HideErrors - DSH
 Modified to add ShowAngles - DSH
 Modified SerialCommand.h to increase # of characters allowed to be input and command length - DSH
           #define SERIALCOMMAND_BUFFER 100		// ORIGINAL: 32   MODIFIED BY DSH
           #define SERIALCOMMAND_MAXCOMMANDLENGTH 20	// ORIGINAL: 8
 ****************************************************************************************
 NOTE: DON'T FORGET TO COPY THE NEW SerialCommand.h TO YOUR ARDUINO LIBRARY DIRECTORY!!!
 ****************************************************************************************
 Modified to merge ShowAngles command into ShowAngle Command - DSH
 Modified to add ShowInterval and HideInterval command (show interval, in milliseconds, every revolution, at angle=0
 See README for additional information 
 
 The F() macro in the Serial statements tells the compiler to keep your strings in PROGMEM
 */

#include <TimerThree.h> // used for ultrasonic PWM motor control


  arg = sCmd.next();
  if (arg != NULL) {
    sVal = atoi(arg);                                         // Converts a char string to an integer
  }
  else {
    syntax_error = true;
