 data block is YY 80 00 00 maybe it's a code to say what type of error ? (35 is preponderant, 21 seems to be when the beam is 
 interrupted by the supports of the cover) .
 */
-const byte STRENGTH_WARNING_FLAG = (1 << 6);  // Mask for byte 1 of each data quat "Strength Warning"
+const byte _STRENGTH_WARNING_FLAG = (1 << 6);  // Mask for byte 1 of each data quat "Strength Warning"
 /*
 The bit 6 of byte 1 is a warning when the reported strength is greatly inferior to what is expected at this distance. 
 This may happen when the material has a low reflectance (black material...), or when the dot does not have the expected 
 size or shape (porous material, transparent fabric, grid, edge of an object...), or maybe when there are parasitic 
 reflections (glass... ).
 */
-const byte BAD_DATA_MASK = (INVALID_DATA_FLAG | STRENGTH_WARNING_FLAG);
-
-const byte eState_Find_COMMAND = 0;                        // 1st state: find 0xFA (COMMAND) in input stream
-const byte eState_Build_Packet = eState_Find_COMMAND + 1;  // 2nd state: build the packet
-int eState = eState_Find_COMMAND;
+const byte _BAD_DATA_MASK = (_INVALID_DATA_FLAG | _STRENGTH_WARNING_FLAG);
+
+const byte _eState_Find_COMMAND = 0;                        // 1st state: find 0xFA (COMMAND) in input stream
+const byte _eState_Build_Packet = _eState_Find_COMMAND + 1;  // 2nd state: build the packet
+int eState = _eState_Find_COMMAND;
+
 PID rpmPID(&motor_rpm, &pwm_val, &xv_config.rpm_setpoint, xv_config.Kp, xv_config.Ki, xv_config.Kd, DIRECT);
 
 uint8_t inByte = 0;  // incoming serial byte
 uint8_t motor_rph_high_byte = 0; 
 uint8_t motor_rph_low_byte = 0;
-uint16_t aryDist[N_DATA_QUADS] = {0,0,0,0};      // thre are (4) distances, one for each data quad
-// so the maximum distance is 16383 mm (0x3FFF)
-uint16_t aryQuality[N_DATA_QUADS] = {0,0,0,0};   // same with 'quality'
+uint16_t aryDist[_N_DATA_QUADS] = {0,0,0,0};     // thre are (4) distances, one for each data quad
+// NOTE: the maximum distance is 16383 mm (0x3FFF)
+uint16_t aryQuality[_N_DATA_QUADS] = {0,0,0,0};  // same with 'quality'
 uint16_t motor_rph = 0;
 uint16_t startingAngle = 0;                      // the first scan angle (of group of 4, based on 'index'), in degrees (0..359)
-boolean bShowErrors = false;                     // true = show 3 kinds of errors
-
-SerialCommand sCmd;
-
-const int ledPin = 11;
-boolean ledState = LOW;
+int iCurrentAngle = 0;
+SerialCommand sCmd;                              // an instance of the serial device handler
+
+const int ledPin = 11;                           // blink the LED
+boolean ledState = LOW;                          // Toggle LOW/HIGH
+byte aryInvalidDataFlag[_N_DATA_QUADS] = {0,0,0,0};  // non-zero = _INVALID_DATA_FLAG or _STRENGTH_WARNING_FLAG is set
+int eShow;                                              // What to display {UNKNOWN; RAW; DISTANCE; ANGLE}
+int oldAngle = 0;
 
 // initialization (before 'loop')
 void setup() {
-  EEPROM_readAnything(0, xv_config);
-  if( xv_config.id != EEPROM_ID) { // verify EEPROM values have been initialized
-    initEEPROM();
-  }
-  pinMode(xv_config.motor_pwm_pin, OUTPUT); 
-  Serial.begin(115200);                            // USB serial
-  Serial1.begin(115200);                           // XV LDS data 
-
+  Serial.begin(115200);                           // USB serial
+  // Software consistency checks (catchable programmer mistakes)
+  if ((_eOUT_MAX != 4) || (_eOUT_MAX > _MASK_BYTE)) { // limit decimal value to what will fit in 1 byte
+    Serial.println(F("SOFTWARE ERROR: _eOUT_MAX invalid. HALT!"));
+    while (1);                                     // HANG!!!!!!
+  }
+  if (_eSHOW_MAX >= _BITS_PER_BYTE) {              // limit binary value to what can be expressed in 8-bits
+    Serial.println(F("SOFTWARE ERROR: _eSHOW_MAX invalid. HALT!"));
+    while (1);                                     // HANG!!!!
+  } 
+  EEPROM_readAnything(_EE_OFFSET_ID, xv_config);   // read the saved EEPROM configuration
+  if(xv_config.id != _EEPROM_ID) {                 // If EEPROM ID has changed...
+    Serial.println(F("EEPROM version is different from last time. Initializing EEPROM"));
+    initEEPROM();                                  // ...initialize EEPROM to new layout
+    //showConfig();                                  // for DEBUGGING: display EEPROM configuration data
+  }  
+  pinMode(xv_config.motor_pwm_pin, OUTPUT);        // set the pin that drives the LIDAR motor
+  Serial1.begin(115200);                           // XV LDS data   
   Timer3.initialize(30);                           // set PWM frequency to 32.768kHz  
-
   rpmPID.SetOutputLimits(xv_config.pwm_min,xv_config.pwm_max);
   rpmPID.SetSampleTime(xv_config.sample_time);
   rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
   rpmPID.SetMode(AUTOMATIC);
-
-  initSerialCommands();
+  initSerialCommands();                             // Add commands to te 'sCmd' object
   pinMode(ledPin, OUTPUT);
-  
-  eState = eState_Find_COMMAND;
-  for (ixPacket = 0; ixPacket < PACKET_LENGTH; ixPacket++)  // Initialize
+  eState = _eState_Find_COMMAND;                   // Initialize the 'state' for the main loop
+  for (ixPacket = 0; ixPacket < _PACKET_LENGTH; ixPacket++)  // Initialize
     Packet[ixPacket] = 0;
-  ixPacket = 0; 
-  setLowRPM(xv_config.rpm_min);                      // Make the motor go as slow as possible
-  //hideRaw();                                         // DSH ONLY!!!!!!!!!!!!  
-}
+  ixPacket = 0;   
+  if (xv_config.bMotorEnable == false)             // Turn on the motor
+    forceMotorOn();                                // enable the motor
+  forceRaw();                                      // Default mode = 'show raw data'
+  //hideRaw();                                     // DSH ONLY!!!!!!!!!!!!   
+}
+
 // Main loop (forever)
-void loop() {
-  byte aryInvalidDataFlag[N_DATA_QUADS] = {0,0,0,0};  // non-zero = INVALID_DATA_FLAG or STRENGTH_WARNING_FLAG is set
-  
-  sCmd.readSerial();  // check for incoming serial commands
-  if (Serial1.available() > 0) {                  // read byte from LIDAR and relay to USB    
-    inByte = Serial1.read();                      // get incoming byte:
-    if (xv_config.raw_data)
-      Serial.print(inByte, BYTE);                 // relay
-
+void loop() {  
+  sCmd.readSerial();                                      // check for incoming serial commands
+  if (Serial1.available() > 0) {                          // If a byte is available...
+    inByte = Serial1.read();                              // ...fetch incoming byte
+    eShow = (xv_config.eOUT & _MASK_eOUT_SHOW);           // what are we supposed to display?
+    if (eShow == _eOUT_RAW)                               // if we're doing 'RAW' data...
+      Serial.print(inByte, BYTE);                         // ... echo input to output
     // Switch, based on 'eState':
     // State 1: We're scanning for 0xFA (COMMAND) in the input stream
     // State 2: Build a complete data packet
-    if (eState == eState_Find_COMMAND) {          // flush input until we get COMMAND byte
-      if(inByte == COMMAND) {
-        eState++;                                 // switch to 'build a packet' state
-        Packet[ixPacket++] = inByte;              // store 1st byte of data into 'Packet'
+    if (eState == _eState_Find_COMMAND) {                 // flush input until we receive a COMMAND (value: 0xFA)
+      if(inByte == _COMMAND) {
+        eState++;                                         // switch to 'build a packet' state
+        Packet[ixPacket++] = inByte;                      // store 1st byte of data into 'Packet'
       }
     }
-    else {                                            // eState == eState_Build_Packet
-      Packet[ixPacket++] = inByte;                    // keep storing input into 'Packet'
-      if (ixPacket == PACKET_LENGTH) {                // we've got all the input bytes, so we're done building this packet
-        if (eValidatePacket() == VALID_PACKET) {      // Check packet CRC
-          startingAngle = processIndex();             // get the starting angle of this group (of 4), e.g., 0, 4, 8, 12, ...        
-          processSpeed();                             // process the speed
+    else {                                                // eState == _eState_Build_Packet
+      Packet[ixPacket++] = inByte;                        // keep storing input into 'Packet'
+      if (ixPacket == _PACKET_LENGTH) {                   // we've got all the input bytes, so we're done building this packet
+        if (eValidatePacket() == _VALID_PACKET) {         // Check packet CRC
+          startingAngle = processIndex();                 // get the starting angle of this group (of 4), e.g., 0, 4, 8, 12, ...        
+          processSpeed();                                 // process the speed
           // process each of the (4) sets of data in the packet        
-          for (int ix = 0; ix < N_DATA_QUADS; ix++)   // process the distance
+          for (int ix = 0; ix < _N_DATA_QUADS; ix++)      // process the distance
             aryInvalidDataFlag[ix] = processDistance(ix);
-          for (int ix = 0; ix < N_DATA_QUADS; ix++) { // process the signal strength (quality)
+          for (int ix = 0; ix < _N_DATA_QUADS; ix++) {    // process the signal strength (quality)
             aryQuality[ix] = 0;
-            if (aryInvalidDataFlag[ix] == 0)
+            if (aryInvalidDataFlag[ix] == 0) {
               processSignalStrength(ix);
+            } // if (aryInvalidDataFlag[ix] == 0)
+          } // for (int ix = 0; ix < _N_DATA_QUADS; ix++)          
+          switch (eShow) {
+            case _eOUT_UNKNOWN :                                // eShow = Unknown or uninitialized (value: 0)
+              break;
+            case _eOUT_DIST :                                   // eShow = display distance data (value: 2)
+              //break;
+            case _eOUT_ANGLE :                                  // eShow = display angle data (value: 3)              
+              for (int ix = 0; ix < _N_DATA_QUADS; ix++) {
+                // We can't count on being able to display speed data at angle = 0
+                // so we look for the angle to go from a high value to a lower value
+                // which is safe to assume that it's either 0 or the closest value that is valid
+                iCurrentAngle = startingAngle + ix;             // convert unsigned to signed integer for compare
+                if (iCurrentAngle < oldAngle)                   // the angle has gone from, e.g., 359 to 0
+                  if (xv_config.eOUT & _OUT_MOD_SHOW_RPM)       // if we're supposed to be showing RPM...
+                    if (xv_config.bMotorEnable)                 // if the motor is spinning...
+                      showSpeed();                              // ...display RPM once per rev, at angle 0 (or as close as possible)
+                oldAngle = iCurrentAngle;
+                if (xv_config.aryAngles[startingAngle + ix]) {  // if we're supposed to display that angle                    
+                  if (aryInvalidDataFlag[ix] == 0) {            // make sure that the 'Invalid Data' flag is clear
+                    if (xv_config.eOUT & _OUT_MOD_SHOW_CSV) {   // Display in CSV format?
+                      Serial.print(startingAngle + ix);
+                      Serial.print(F(","));
+                      Serial.print(int(aryDist[ix]));
+                      Serial.print(F(","));
+                      Serial.println(aryQuality[ix]);
+                    }
+                    else {
+                      Serial.print(startingAngle + ix);
+                      Serial.print(F(": "));
+                      Serial.print(int(aryDist[ix]));
+                      Serial.print(F(" ("));
+                      Serial.print(aryQuality[ix]);
+                      Serial.println(F(")"));                         
+                    }                      
+                  } // if (aryInvalidDataFlag[ix] == 0)
+                  else if (xv_config.eOUT & _OUT_MOD_SHOW_ERRORS) { // If we're supposed to show errors...
+                    if (xv_config.bMotorEnable) {                   // and if the motor is spinning...
+                      if (xv_config.eOUT & _OUT_MOD_SHOW_CSV) {     // Display in CSV format?
+                        Serial.print(startingAngle + ix);
+                        Serial.print(F(","));
+                        if (aryInvalidDataFlag[ix] & _INVALID_DATA_FLAG)
+                          Serial.println(F("I,"));
+                        if (aryInvalidDataFlag[ix] & _STRENGTH_WARNING_FLAG) 
+                          Serial.println(F("S,"));                                                
+                      }
+                      else {                                        // display in normal format
+                        Serial.print(startingAngle + ix);
+                        Serial.print(F(": "));
+                        if (aryInvalidDataFlag[ix] & _INVALID_DATA_FLAG)
+                          Serial.println(F("{I}"));
+                        if (aryInvalidDataFlag[ix] & _STRENGTH_WARNING_FLAG) 
+                          Serial.println(F("{S}"));                        
+                      }
+                    } // if (xv_config.bMotorEnable)
+                  }  // else if (xv_config.eOUT & _OUT_MOD_SHOW_ERRORS)
+                }  // if (xv_config.aryAngles[startingAngle + ix])
+              }  // for (int ix = 0; ix < _N_DATA_QUADS; ix++)
+            break;
+          } // switch (eShow)
+      }  // if (eValidatePacket() == 0
+      else {                                                  // Packet did not pass CRC check!
+        if (xv_config.eOUT & _OUT_MOD_SHOW_ERRORS) {          // Show errors?
+          /* DEBUGGING ONLY: Dump the contents of 'Packet'
+          for (int ix = 0; ix < _PACKET_LENGTH; ix++) {       // a full error display (dump Packet to screen)
+            if (Packet[ix] < 0x10)
+              Serial.print(F("0"));
+            Serial.print(Packet[ix], HEX);
+            Serial.print(F(" "));
           }
-          if (xv_config.show_dist) {                           // the 'ShowDistance' command is active
-            for (int ix = 0; ix < N_DATA_QUADS; ix++) {
-              if (aryAngles[startingAngle + ix]) {             // if we're supposed to display that angle
-                if (aryInvalidDataFlag[ix] & BAD_DATA_MASK) {  // if LIDAR reported a data error...
-                  if (bShowErrors) {                           // if we're supposed to show data errors...
-                    Serial.print(F("A,"));
-                    Serial.print(startingAngle + ix);                
-                    Serial.print(F(","));
-                    if (aryInvalidDataFlag[ix] & INVALID_DATA_FLAG)
-                      Serial.println(F("-2"));                  
-                    if (aryInvalidDataFlag[ix] & STRENGTH_WARNING_FLAG)
-                      Serial.println(F("-3"));                 
-                  }
-                }
-                else {                                         // show clean data
-                  Serial.print(F("A,"));
-                  Serial.print(startingAngle + ix);                
-                  Serial.print(F(","));
-                  Serial.print(int(aryDist[ix]));
-                  Serial.print(F(","));
-                  Serial.println(aryQuality[ix]);
-                }
-              }  // if (aryAngles[startingAngle + ix])
-            }  // for (int ix = 0; ix < N_DATA_QUADS; ix++)
-          }  // if (xv_config.show_dist)
-        }  // if (eValidatePacket() == 0
-        else if (bShowErrors) {                                // we have encountered a CRC error
-          Serial.println(F("C,-1"));
-        }
-        // initialize a bunch of stuff before we switch back to State 1
-        for (int ix = 0; ix < N_DATA_QUADS; ix++) {
-          aryDist[ix] = 0;
-          aryQuality[ix] = 0;
-          aryInvalidDataFlag[ix] = 0;
-        }
-        for (ixPacket = 0; ixPacket < PACKET_LENGTH; ixPacket++)  // clear out this packet
-          Packet[ixPacket] = 0;
-        ixPacket = 0;      
-        eState = eState_Find_COMMAND;                // This packet is done -- look for next COMMAND byte        
-      }  // if (ixPacket == PACKET_LENGTH)
-    }  // if (eState == eState_Find_COMMAND)
+          */
+          Serial.println(F("CRC"));                           // an abbreviated error display
+        } // if (xv_config.eOUT & _OUT_MOD_SHOW_ERRORS)
+      } // if not (eValidatePacket() == 0
+      // initialize a bunch of stuff before we switch back to State 1
+      for (int ix = 0; ix < _N_DATA_QUADS; ix++) {
+        aryDist[ix] = 0;
+        aryQuality[ix] = 0;
+        aryInvalidDataFlag[ix] = 0;
+      }
+      for (ixPacket = 0; ixPacket < _PACKET_LENGTH; ixPacket++)  // clear out this packet
+        Packet[ixPacket] = 0;
+      ixPacket = 0;      
+      eState = _eState_Find_COMMAND;                // This packet is done -- look for next COMMAND byte        
+      }  // if (ixPacket == _PACKET_LENGTH)
+    }  // if not (eState == _eState_Find_COMMAND)
   }  // if (Serial1.available() > 0)
-  if (xv_config.motor_enable) {  
+  //
+  if (xv_config.bMotorEnable) {  
     rpmPID.Compute();
     if (pwm_val != pwm_last) {
       Timer3.pwm(xv_config.motor_pwm_pin, pwm_val);  // replacement for analogWrite()
       pwm_last = pwm_val;
     }
     motorCheck();
-  }  // if (xv_config.motor_enable)
+  }  // if (xv_config.bMotorEnable)  
 }  // loop
 /*
  * processIndex - Process the packet element 'index'

 *                                     so maximum distance is 0x3FFF (16383 decimal) millimeters (mm)
 * Calls:      N/A
 * Exits with: 0 = okay
 * Error:      1 << 7 = INVALID_DATA_FLAG is set
 *             1 << 6 = STRENGTH_WARNING_FLAG is set
 */
byte processDistance(int iQuad) {
  uint8_t dataL, dataM;
  aryDist[iQuad] = 0;                     // initialize
  int iOffset = OFFSET_TO_4_DATA_READINGS + (iQuad * N_DATA_QUADS) + OFFSET_DATA_DISTANCE_LSB;    
  // byte 0 : <distance 7:0> (LSB)
  // byte 1 : <"invalid data" flag> <"strength warning" flag> <distance 13:8> (MSB)
  dataM = Packet[iOffset + 1];           // get MSB of distance data + flags    
  if (dataM & BAD_DATA_MASK)             // if either INVALID_DATA_FLAG or STRENGTH_WARNING_FLAG is set...
    return dataM & BAD_DATA_MASK;        // ...then return non-zero
  dataL = Packet[iOffset];               // LSB of distance data
  aryDist[iQuad] = dataL | ((dataM & 0x3F) << 8);
  return 0;                              // okay

  }

  if (syntax_error) {
    if ((xv_config.eOUT & _MASK_eOUT_SHOW) != _eOUT_RAW) {  // can't do this if we're in RAW mode
      Serial.println(F(" "));
      Serial.println(F("Incorrect syntax.  Example: SetKp 1.0")); 
    }
  }
  else {
    if ((xv_config.eOUT & _MASK_eOUT_SHOW) != _eOUT_RAW) {  // can't do this if we're in RAW mode
      Serial.println(F(" "));
      Serial.print(F("Setting Kp to: "));
      Serial.println(sVal);
    }
    xv_config.Kp = sVal;
    EEPROM_writeAnything(_EE_OFFSET_Kp, xv_config.Kp);
    rpmPID.SetTunings(xv_config.Kp, xv_config.Ki, xv_config.Kd);
  }
}
/*
 * setKi
 */
void setKi() {
  double sVal = 0.0;
  char *arg;
