Arduino IDE 2.3.3 auto format error ?

Hi,
I am using Arduino 2.3.3 on Windows 11. My code includes:

#define DEBUG true
#define Serial  if (DEBUG) Serial

When I auto-format (cntl-T) the above is converted to:

#define DEBUG true
#define Serial \
  if (DEBUG) Serial

which causes an error in the compilation.
Version 1.8.18 did not do this.

I find this method of turning debug statements on and off preferable to #ifdef, etc.

Is there something I'm doing wrong?

Thank you,
Morty Tarr

yep it would.

i would do it like this,

#define _DEBUG_
#ifdef _DEBUG_
  #define Serial Serial
#else
  #define Serial
#endif

Mind you it still does depend on how the rest of your code is set up.
You should be able to setup auto-format specifications the same way you can in IDE 1.8.x , not really sure where that file is though.

@mtarr00
You can disable formatting of certain sections of code using clang-format off and clang-format off as demonstrated below

int formatted_code;
// clang-format off
    void    unformatted_code  ;
// clang-format on
void formatted_code_again;

Source: Clang-Format Style Options — Clang 20.0.0git documentation

You will have to create the file if you want to modify the behaviour of the auto-formatter; one location is C:\Users\yourUsername\.arduinoIDE (for Windows users). You can also have it on a per-sketch basis which will override the global behaviour.

Attached my slightly modified version of the original from Arduino's github page.

.clang-format.zip (2.0 KB)

Note that the file does not have an extension.

So that has changed from IDE 1.8.x ?
From C:\Users\UserName\Appdata\Local\Arduino15
(same location as the Preferences.txt )
Where it was Formatter.Conf

That is correct. The new system is documented here:

https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-customize-auto-formatter

I tried Deva_Rishi's solution and I could not get it to work.
If I #undef DEBUG I get errors.
If I #define DEBUG false I still get the serial commands in the compiled version.

Will try sterretje's version next.

Thank you to all who have responded.
-Morty

I can't reproduce this. It works perfectly fine for me, and I can't imagine why this change would have any functional effect.

Please provide a sketch code that compiles prior to the formatting, and does not compile after the formatting. Ideally this would be a simple sketch that doesn't require me to go on a long scavenger hunt looking for random libraries before I can compile it.

This time, make sure to post your code properly. A moderator had to fix your post because the code had been corrupted due to you not posting it correctly. You can learn how to do that by reading the "How to get the best out of this forum" guide:

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum/679966#use-code-tags

I apologize for posting the code incorrectly. I hope this is better.
The re-post was also incorrect, the code before re-fromat looks like this:

#define DEBUG true
#define Serial if (DEBUG) Serial

and the code after re-format looks like this:

#define DEBUG true
#define Serial \
  if (DEBUG) Serial

I have investigated further.
In some cases, when I re-format, I get an error, but if I save the sketch and re-compile, there is no error. I think that auto format is adding a character that does not display, which causes the error.

I tried to create smaller sketch that behaves the same way, but I was unsuccessful. So here is the code, the errors are on lines 15 - 20.

I don't claim to be good at coding, but this code works in v1.1.18 even after a re-format. It does not compile after a re-format in v2.3.3, but it does after I save it after the re-format and then compile. So something strange is going on here.

My PC is running the latest updates to Windos 11 Pro. I have v2.3.3 installed and also v1.8.18 (I have multiple projects built on v1.8.18). The target processor is an Arduino Micro (we need the crystal timebase for ToneAC), but I'm developing on a Nano.

Thank you for your help,
Morty

Here is the complete sketch (as it is today):
/*
   Turntable Speed Control using Teknic synchronous motor
   UI only so far...
*/


#define filename "Turntable_Speed_Control_05.2"  // 26 char
#define displayname "TT SpeedControlv05.2"       //

//  if DEBUG is false, do not print to Serial port
//  less "disturbing" than #ifdef and #endif
//  if DEBUG is false, do not print to Serial port
//  less "disturbing" than #ifdef and #endif

#define DEBUG true
#define Serial if (DEBUG) Serial

#include <toneAC.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);  // Change to (0x27,16,2) for 16x2 LCD.

/*
  Procedures:

  void lcdPrintMainMenu ()
  void lcdPrintChangeSpeed()
  void lcdPrintAdjustSpeed()
  void lcdPrintSaveDefault ()
  void selectLine (int line)
  void deselectLine (int line)

  void pressInterrupt()
  void configureCommon()
  void configureDistinct()
  void press(uint8_t button)
  void buttonHandler ()
  void buttonReset ()
  void incr ()
  void decr ()
  void calcRPM ()

  void UP ()
  void DOWN ()
  void SEL ()

*/

//define button pins
const int buttonCommon = 2;             //ButtonCommon is pin D2 (pin 5, interrrupt)
const int buttonPins[] = { 4, 5, A3 };  // tact switches: up - sel - down

// define buttons
volatile bool upButton = false;
volatile bool downButton = false;
volatile bool selectButton = false;
volatile bool buttonActive = false;
volatile bool firstPress = true;
volatile bool selActive = false;  // SEL is active after new screen and any button press

//  button variables
unsigned long lastButtonPress = 0;
const unsigned long debounceTime = 50;            // debounce time in msec
const unsigned long buttonTimeOut = 10UL * 1000;  // button press cancelled (in sec = 10)
const unsigned long longPressTime = 2UL * 1000;   // long press >= 2 seconds
volatile unsigned long buttonTime = 0;            // timer for botton presses
volatile unsigned long buttonTimer = 0;           // timer for botton timeout
volatile uint8_t buttonNumber = 0;                // buttons: 0=none, 1=up, 2=sel, 3=down


byte speed = 0;  // 1=33 RPM, 2=45 RPM, 3=78 RPM
// define speeds
#define _33RPM 1
#define _45RPM 2
#define _78RPM 3

// definitions from toneAC_steps_1
#define targetFreq33 1333.33333  // target frequency for 33 RPM; replaced by value from EEPROM
#define targetFreq45 2500.0      // target frequency for 45 RPM; replaced by value from EEPROM
#define targetFreq78 5800.0      // target frequency for 78 RPM; replaced by value from EEPROM

#define stepResCalibrate (0.05 / 100.0)  // step resolution for Calibrate menu
#define stepResAdjust (0.50 / 100.0)     // step resolution for Adjust menu

float freq33float = targetFreq33;                           //Frequency as float
float freq45float = targetFreq45;                           //Frequency as float
float freq78float = targetFreq78;                           //Frequency as float
float periodFloat = 1.0 / freq33float;                      // target period as float
const float rnd = 0.50;                                     // add to float before convert to int
const float timeInterval = 0.125E-6;                        // Timer resolution = 0.0625 usec * 2 here for sq wave (in seconds)
float intervalsFloat = (1.0 / freq33float / timeInterval);  // timer intervals as float
const float stepRes = stepResCalibrate;                     // Spacing between frequency steps for Calibrate (0.05%) & Adjust (0.50%)
int intervalsInt = int(intervalsFloat + rnd);               // Timer intervals rounded to int
const int numberSteps = 100;                                // steps on each side of target for variable speed
int stepNumber = 0;                                         // step number for Adjust / Calibrate Speed
float currentSpeed = 33.0 + 1.0 / 3.0;                      // 33.333 RPM
// float currentSpeed = 78.0;         // 78 RPM

// >> Need convert frequency to RPM variables, constants, and code <<

// Computed values sent to ToneAC
int intSpeed33 = 0;
int intSpeed45 = 0;
int intSpeed78 = 0;

/*
Serial.println(F("Int Speeds:"));
Serial.println(intSpeed33);
Serial.println(intSpeed45);
Serial.println(intSpeed78);
*/

// misc variables
int i = 0;  // index for loops

// LCD variables and constants
int menuActive = 0;  // Startup (invalid value)
int prevMenu = 0;
#define mainMenu 1
#define changeSpeed 2
#define adjustSpeed 3
#define saveDefault 4
#define calibrateSpeed 5
#define mainMenu2 6

int lineNumber = 0;                                   // current LCD line number (0-3)
volatile unsigned long backlightStartTime = 0;        // used for backlight timer
const unsigned long backlightOnTime = (30UL * 1000);  // backlight ON time = 0.5 minute (30 seconds)
bool backlightON = false;

//  EEPROM constants & variables
// EEPROM Address Pointers
const unsigned int CurrentRpmPointerAddress = 10;  // this value only is a byte (0=33, 1=45, 2=78)
const unsigned int Rpm33PointerAddress = 20;       // all RPM values stored in EEPROM are floats (4 bytes)
const unsigned int Rpm45PointerAddress = 30;
const unsigned int Rpm78PointerAddress = 40;


//  LCD Display buffers
//  Static buffers in PROGMEM; copied to displayBuffer to print to LCD
char displayBuffer[21];  // display buffer in RAM (20 char, 21 including terminator)
//  use strcpy_P to copy from PRGMEM to RAM
char floatLCD[7];             // floating point number to print on LCD (XX.YYYY)
bool mainMenuScroll = false;  //  true if line number 4 (Calibrate Speed) selected

// Screen Buffers
const char PROGMEM ChangeSpeed[][21]{
  "    Change Speed    ",  // 0
  "     33 1/3 RPM     ",  // 1
  "       45 RPM       ",  // 2
  "       78 RPM       ",  // 3
};

const char PROGMEM MainMenu[][21]{
  "      Main Menu     ",  // 0
  " Speed:         RPM ",  // 1  use dtostrf() to add speed to this line
  "    Change Speed    ",  // 2
  "    Adjust Speed    ",  // 3
};

const char PROGMEM MainMenu2[][21]{
  " Speed:         RPM ",  // 0  use dtostrf() to add speed to this line
  "    Change Speed    ",  // 1
  "    Adjust Speed    ",  // 2
  "   Calibrate Speed  "   // 3
};

const char PROGMEM AdjustSpeed[][21]{
  "    Adjust Speed    ",  // 0
  "  Incr:             ",  // 1  use dtostrf() to add speed to this line
  "  Decr:             ",  // 2  use dtostrf() to add speed to this line
  "  Save as Default   ",  // 3  save current value to EEPROM (go to confirm screen)
};

const char PROGMEM SaveDefault[][21]{
  "   Save as Default  ",  // 0
  "          RPM       ",  // 1  use dtostrf() to add speed to this line (2 digits only)
  "        Yes         ",  // 2
  "        No          ",  // 3
};

const char PROGMEM CalibrateSpeed[][21]{
  "  Calibrate Speed   ",  // 0
  "  Incr:             ",  // 1  use dtostrf() to add speed to this line
  "  Decr:             ",  // 2  use dtostrf() to add speed to this line
  "  Save as Default   ",  // 3  save current value to EEPROM (go to confirm screen)
};

char floatBuffer[]{ 33.333 };  // buffer for dtostrf output
const char selectLeft[3]{ ">>" };
const char selectRight[3]{ "<<" };
const char deselect[3]{ "  " };


//  Procedures

//Buttons
void UP()  // actions to take on UP button press - menu dependent
{
  // Serial.print("UP button press, lineNumber = ");
  // Serial.println(lineNumber);

  if (firstPress)  //  need to set up each screen separately
  {
    Serial.print(F("First press = "));
    Serial.println(firstPress);
    selectLine(lineNumber);
    firstPress = false;
  } else {
    deselectLine(lineNumber);
    lineNumber = lineNumber - 1;
    if (menuActive == mainMenu) {
      //  lcdPrintMainMenu();
      if (lineNumber < 2) lineNumber = 0;  // debug here
      if (lineNumber > 4) lineNumber = 4;
      if (lineNumber < 4) {
        menuActive = mainMenu;
        selectLine(lineNumber);
      } else {
        if (lineNumber == 4) {
          menuActive = mainMenu2;
          lineNumber = lineNumber - 1;
        }
      }
    }
    if (menuActive == mainMenu2) {
      Serial.print(F("button UP, mainMenu2, lineNumber = "));
      Serial.println(lineNumber);
      deselectLine(lineNumber + 1);
      //  lcdPrintmainMenu2 ();
      if (lineNumber == -1) {
        lcdPrintMainMenu();
      }
      if (lineNumber < 0) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
    if (menuActive == changeSpeed) {
      //  lcdPrint changeSpeed();
      if (lineNumber < 0) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      Serial.print(F("line number = "));
      Serial.println(lineNumber);
      selectLine(lineNumber);
      if (lineNumber == 1) selectSpeed33;
      if (lineNumber == 2) selectSpeed45;
      if (lineNumber == 3) selectSpeed78;
    }
    if (menuActive == adjustSpeed) {
      //  lcdPrintadjustSpeed ();
      if (lineNumber < 0) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
    if (menuActive == saveDefault) {
      //  lcdPrintMainMenu();
      if (lineNumber < 2) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
    if (menuActive == calibrateSpeed) {
      //  lcdPrintCalibrateSpeed();
      if (lineNumber < 0) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
  }
  selActive = true;
}

void DOWN()  // actions to take on DOWN button press - menu dependent
{
  Serial.println("DOWN button press");
  if (firstPress)  //  need to set up each screen separately
  {
    Serial.print(F("First press = "));
    Serial.println(firstPress);
    selectLine(lineNumber);
    firstPress = false;
  } else {  // not first press
    deselectLine(lineNumber);
    lineNumber = lineNumber + 1;
    if (menuActive == mainMenu) {
      //  lcdPrintMainMenu();
      Serial.print(F("Main Menu; lineNumber = "));
      Serial.println(lineNumber);
      if (lineNumber < 1) lineNumber = 1;
      if (lineNumber > 4) lineNumber = 4;

      if (lineNumber < 4) {
        Serial.println(F("print Main Menu"));
        selectLine(lineNumber);
        menuActive == mainMenu;
      } else {
        Serial.println(F("print Main Menu 2"));
        menuActive = mainMenu2;
        selectLine(lineNumber - 1);
      }
    }

    if (menuActive == mainMenu2) {
      //  lcdPrintMainMenu();
      Serial.print(F("button DOWN, mainMenu2, lineNumber = "));
      Serial.println(lineNumber);
      deselectLine(lineNumber - 1);
      selectLine(lineNumber);
      if (lineNumber < 1) lineNumber = 1;
      if (lineNumber > 3) lineNumber = 3;
      if (lineNumber == 1) {
        lcd.setCursor(0, i);  // (COL, ROW) reprint line 0, mainMenu2
        strcpy_P(displayBuffer, MainMenu2[0]);
        lcd.print(displayBuffer);
        lcd.setCursor(9, 0);
        dtostrf(currentSpeed, 6, 3, floatLCD);
        if (strcmp(floatLCD, "78.000") == 0) {
          lcd.setCursor(10, 0);
          dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 78 instead of 78.000
        }
        if (strcmp(floatLCD, "45.000") == 0) {
          lcd.setCursor(10, 0);
          dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 45 instead of 45.000
        }
        lcd.print(floatLCD);
      }
    }

    if (menuActive == changeSpeed) {
      //  lcdPrint changeSpeed();
      if (lineNumber < 1) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      Serial.print(F("DOWN - CH SPD line number = "));
      Serial.println(lineNumber);
      selectLine(lineNumber);
    }
    if (menuActive == adjustSpeed) {
      //  lcdPrintadjustSpeed ();
      if (lineNumber < 0) lineNumber = 0;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
      Serial.print(F("Button DOWN, Adjust Speed, line number = "));
      Serial.println(lineNumber);
    }
    if (menuActive == saveDefault) {
      //  lcdPrintSaveDefault()
      if (lineNumber < 2) lineNumber = 2;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
    if (menuActive == calibrateSpeed) {
      //  lcdPrintSaveDefault()
      if (lineNumber < 2) lineNumber = 2;
      if (lineNumber > 3) lineNumber = 3;
      selectLine(lineNumber);
    }
  }
  selActive = true;
}

/*
  #define mainMenu 1
  #define changeSpeed 2
  #define adjustSpeed 3
  #define saveDefault 4
*/
void SEL()  // actions to take on SEL button press - menu dependent
//  >> SEL initiates all the activity <<
{
  Serial.println(F("SEL button press"));
  Serial.print(F("Line Number = "));
  Serial.println(lineNumber);

  if (firstPress)  //  need to set up each screen separately
  {
    Serial.print(F("First press = "));
    Serial.println(firstPress);
    Serial.print(F("SEL - firstPres line number = "));
    Serial.println(lineNumber);
    selectLine(lineNumber);
    firstPress = false;
  }


  if (lineNumber == 0) {  // SEL menu name (line 0) goes back to main menu
    menuActive = mainMenu;
    lcdPrintMainMenu();
    return;
  }



  // SEL has to be sorted by screen, then line number selected
  if (!selActive) {
    selActive = true;
    Serial.print(F("SEL - (!selActive) line number = "));
    Serial.println(lineNumber);
    selectLine(lineNumber);  // show selected line
    return;
  }
  if (selActive) {
    if (menuActive == mainMenu) {
      if (lineNumber == 2) menuActive = changeSpeed;
      if (lineNumber == 3) menuActive = adjustSpeed;
      return;
    }

    if (menuActive == mainMenu2) {
      if (lineNumber == 1) menuActive = changeSpeed;
      if (lineNumber == 2) menuActive = adjustSpeed;
      if (lineNumber == 3) menuActive = calibrateSpeed;
      return;
    }

    if (menuActive == changeSpeed) {
      if (lineNumber == 1) selectSpeed33();  // tell ToneAC to play 33 1/3 RPM (as a frequency)
      if (lineNumber == 2) selectSpeed45();  // play 45 RPM
      if (lineNumber == 3) selectSpeed78();  // 78 RPM
      Serial.print(F("SEL - CH SPD line number = "));
      Serial.println(lineNumber);
      menuActive = mainMenu;  // back to Main Menu
      selActive = false;
      return;
    }

    if (menuActive == adjustSpeed) {
      if (lineNumber == 1) incrSpeed();               // compute next increment to speed and dislay
      if (lineNumber == 2) decrSpeed();               // compute next decrement to speed and dislay
      if (lineNumber == 3) menuActive = saveDefault;  // 78 RPM
      Serial.print(F("menuActive == adjustSpeed, lineNumber = "));
      Serial.println(lineNumber);
      selActive = false;
      return;
    }

    if (menuActive == calibrateSpeed) {
      if (lineNumber == 1) incrSpeed();               // compute next increment to speed and dislay
      if (lineNumber == 2) decrSpeed();               // compute next decrement to speed and dislay
      if (lineNumber == 3) menuActive = saveDefault;  // 78 RPM
      Serial.print(F("menuActive == adjustSpeed, lineNumber = "));
      Serial.println(lineNumber);
      selActive = false;
      return;
    }

    if (menuActive == saveDefault) {
      Serial.println(F("SEL - MenuActive"));
      if (lineNumber == 2 || 3) menuActive = mainMenu;
      // compute new values here
      selActive = false;
      return;
    }
  }
  selActive = true;
}  // end SEL ()

void buttonReset()  // reset button logic to initial state (nothing selected)
{
  buttonActive = false;
  upButton = false;
  downButton = false;
  selectButton = false;
  selActive = false;
  firstPress = true;
  deselectLine(lineNumber);
}

// end Button Procedures

// LCD Procedures
//select line
void selectLine(int line)  // line is local variable
{
  lcd.setCursor(0, line);
  lcd.print(selectLeft);
  lcd.setCursor(18, line);
  lcd.print(selectRight);
}
// deselect line
void deselectLine(int line) {
  lcd.setCursor(0, line);
  lcd.print(deselect);
  lcd.setCursor(18, line);
  lcd.print(deselect);
}

// Print Menus to LCD

void lcdPrintMainMenu() {
  menuActive = mainMenu;  // Main Menu
  lineNumber = 2;
  buttonReset();
  delay(1);  // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, MainMenu[i]);
    lcd.print(displayBuffer);
  }
  lcd.setCursor(9, 1);
  dtostrf(currentSpeed, 6, 3, floatLCD);
  if (strcmp(floatLCD, "78.000") == 0) {
    lcd.setCursor(10, 1);
    dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 78 instead of 78.000
  }
  if (strcmp(floatLCD, "45.000") == 0) {
    lcd.setCursor(10, 1);
    dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 45 instead of 45.000
  }
  lcd.print(floatLCD);
  Serial.print(F("lcdPrintMainMenu, lineNumber = "));
  Serial.println(lineNumber);
}

void lcdPrintMainMenu2() {
  menuActive = mainMenu2;  // Main Menu 2
  // lineNumber = 3;    // lineNumber should be 1 when press down from line 0
  buttonReset();
  stepNumber = 0;  // reset step number to 0
  delay(1);        // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, MainMenu2[i]);
    lcd.print(displayBuffer);
  }
  lcd.setCursor(9, 0);
  dtostrf(currentSpeed, 6, 3, floatLCD);
  if (strcmp(floatLCD, "78.000") == 0) {
    lcd.setCursor(10, 0);
    dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 78 instead of 78.000
  }
  if (strcmp(floatLCD, "45.000") == 0) {
    lcd.setCursor(10, 0);
    dtostrf(currentSpeed, 2, 0, floatLCD);  // Print 45 instead of 45.000
  }
  lcd.print(floatLCD);
  Serial.print(F("lcdPrintMainMenu2, lineNumber = "));
  Serial.println(lineNumber);
}



void lcdPrintChangeSpeed() {
  menuActive = changeSpeed;  // ChangeSpeed Menu
  lineNumber = 1;
  buttonReset();
  delay(1);  // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, ChangeSpeed[i]);
    lcd.print(displayBuffer);
  }
  Serial.print(F("lcdPrintChangeSpeed, lineNumber = "));
  Serial.println(lineNumber);
}


void lcdPrintAdjustSpeed() {
  menuActive = adjustSpeed;  // AdjustSpeed Menu
  lineNumber = 1;
  buttonReset();
  delay(1);  // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, AdjustSpeed[i]);
    lcd.print(displayBuffer);
  }
  Serial.print(F("lcdPrintAdjustSpeed, lineNumber = "));
  Serial.println(lineNumber);
}

void lcdPrintSaveDefault() {
  menuActive = saveDefault;  // Save Default Value Menu
  lineNumber = 3;
  buttonReset();
  delay(1);  // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, SaveDefault[i]);
    lcd.print(displayBuffer);
  }
  Serial.print(F("lcdPrintSaveDefault, lineNumber = "));
  Serial.println(lineNumber);
}

void lcdPrintCalibrateSpeed() {
  menuActive = calibrateSpeed;  // CaibrateSpeed Menu
  lineNumber = 1;
  buttonReset();
  delay(1);  // delay needed for LCD write timing
  for (i = 0; i < 4; i++) {
    lcd.setCursor(0, i);  // (COL, ROW)
    strcpy_P(displayBuffer, CalibrateSpeed[i]);
    lcd.print(displayBuffer);
  }
  Serial.print(F("lcdPrintCalibrateSpeed, lineNumber = "));
  Serial.println(lineNumber);
}

// Change Turntable Speed
void selectSpeed33() {
  currentSpeed = 33.0 + 1.0 / 3.0;
  toneAC(intSpeed33, 0, true);  // play tone (turntable speed) in background and unitl changed
}
// Change Turntable Speed
void selectSpeed45() {
  currentSpeed = 45.0;
  toneAC(intSpeed45, 0, true);
}
// Change Turntable Speed
void selectSpeed78() {
  currentSpeed = 78.0;
  toneAC(intSpeed78, 0, true);
}

// Compute next Turntable Speed

void incrSpeed() {
  stepNumber = stepNumber + 1;
  if (stepNumber > 120) stepNumber = 120;
  calcRPM();
  // compute next TT Speed here....
}

void decrSpeed() {
  stepNumber = stepNumber - 1;
  if (stepNumber < -120) stepNumber = -120;
  calcRPM();
  // compute next TT Speed here....
}

void calcRPM() {
  // test for adjustMenu or CalibrateMenu
  // Calculate Frequency, target RPM, actual RPM
  true;
}

//********************************
//  ISR for Button(s)
//********************************

void pressInterrupt() {                             // ISR
  if (millis() - lastButtonPress < debounceTime) {  // Debounce
    return;
  }
  lastButtonPress = millis();
  // Serial.println(F("pressInterrupt"));

  configureDistinct();  // Setup pins for testing individual buttons

  for (buttonNumber = 0; buttonNumber < sizeof(buttonPins) / sizeof(int); buttonNumber++) {  // Test each button for press
    if (!digitalRead(buttonPins[buttonNumber])) {
      press(buttonNumber);
      //  Serial.print (">>  pressInterrupt: button = ");
      //  Serial.println (buttonNumber);
    }
  }

  configureCommon();  // Return to original state
}


//********************************
//  ISR & Switch Pin Configuration
//********************************

void configureCommon() {
  pinMode(buttonCommon, INPUT_PULLUP);

  for (unsigned int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

void configureDistinct() {
  pinMode(buttonCommon, OUTPUT);
  digitalWrite(buttonCommon, LOW);

  for (unsigned int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

void press(uint8_t button) {  // Our handler - we get here from qualified button press only
  //  Serial.println (F("press function"));
  buttonActive = true;
  buttonTime = millis();          // start button timeout
  backlightStartTime = millis();  //  start backlight timeout
  if (button == 2) {
    upButton = true;
    // Serial.println ("upButton (button press)");
  }
  if (button == 1) {
    selectButton = true;
    // Serial.println ("selectButton (button press)");
  }
  if (button == 0) {
    downButton = true;
    // Serial.println ("downButton (button press)");
  }
  // buttonTime used as follows:   if (millis() - buttonTime <= buttonTest) { do this }
}

// buttonHandler runs in loop (not interrupt level)
void buttonHandler() {
  //  Serial.println (F("Button handler here..."));
  if (upButton || selectButton || downButton) {
    lcd.backlight();
    backlightON = true;
    buttonTimer = millis();
  }

  if (upButton) {
    UP();
    upButton = false;
    /*
      Serial.print ("buttonTime = ");
      Serial.println (buttonTime);
      Serial.println (F("upButton buttonHandler"));
    */
  }

  if (selectButton) {
    SEL();
    selectButton = false;

    Serial.print("buttonTime = ");
    Serial.println(buttonTime);
    Serial.println(F("selButton buttonHandler"));
  }

  if (downButton) {
    DOWN();
    downButton = false;
    /*
         Serial.print ("buttonTime = ");
         Serial.println (buttonTime);
         Serial.println (F("downButton buttonHandler"));
    */
  }

  //  end of buttonHandler
}


void setup() {
  lcd.init();
  Serial.begin(115200);
  Serial.print("  file:  ");
  Serial.println(filename);
  Serial.print("backlightOnTime = ");
  Serial.print(backlightOnTime / 1000);
  Serial.println(" seconds");

  // Button interrupt
  attachInterrupt(digitalPinToInterrupt(buttonCommon), pressInterrupt, FALLING);
  // interrupt on button press - detect button DOWN
  // for interrupt on both edges use CHANGE instead of FALLING
  configureCommon();  // Setup pins for interrupt

  firstPress = true;

  lcd.backlight();
  backlightON = true;
  backlightStartTime = millis();
  lcd.setCursor(1, 0);  // display file version for 3 seconds
  lcd.print("file:");
  lcd.setCursor(0, 1);
  lcd.print(displayname);
  EEPROM.get(CurrentRpmPointerAddress, speed);
  if (speed == 0xFF) {                             // EEPROM not programmed - write default values
    EEPROM.put(CurrentRpmPointerAddress, _33RPM);  // set default RPM to 33 1/3
    EEPROM.put(Rpm33PointerAddress, freq33float);  // set default frequency for 33 1/3 RPM
    EEPROM.put(Rpm45PointerAddress, freq45float);  // set default frequency for 45 RPM
    EEPROM.put(Rpm78PointerAddress, freq78float);  // set default frequency for 78 RPM
  }

  EEPROM.get(Rpm33PointerAddress, freq33float);  // read default frequency for 33 1/3 RPM
  EEPROM.get(Rpm45PointerAddress, freq45float);  // read default frequency for 45 RPM
  EEPROM.get(Rpm78PointerAddress, freq78float);  // read default frequency for 78 RPM

  Serial.print(F("speed = "));
  Serial.println(speed);
  Serial.println(F("EEPROM frequencies: "));
  Serial.println(freq33float, 3);
  Serial.println(freq45float, 3);
  Serial.println(freq78float, 3);

  intSpeed33 = int(freq33float + rnd);
  intSpeed45 = int(freq45float + rnd);
  intSpeed78 = int(freq78float + rnd);

  Serial.println(F("Integer Frequencies:"));
  Serial.println(intSpeed33);
  Serial.println(intSpeed45);
  Serial.println(intSpeed78);

  selectSpeed33();  //  start at 33 RPM

  delay(4000);  // wait 4 seconds
  lcd.clear();
  lcdPrintMainMenu();
  menuActive = mainMenu;
  prevMenu = menuActive;
  buttonReset();
}



void loop() {
  // put your main code here, to run repeatedly:
  //  button - interrupt or in-line code?
  // when button is pressed - turn on backlight (first press)
  // display select at current line (second press)

  // Backlight timer
  if (backlightON == true) {
    if (millis() - backlightStartTime >= backlightOnTime) {
      lcd.noBacklight();
      // Serial.println(F("backlight off"));
      buttonReset();
    }
  }

  // Button Press
  buttonHandler();  // check button status

  // Button timeout
  if (buttonActive) {
    if (millis() - buttonTimer >= buttonTimeOut) {
      // reset after button press
      Serial.println("Button Timeout");
      buttonReset();
      if (menuActive == mainMenu) lineNumber = 2;
      if (menuActive == mainMenu2) lineNumber = 3;
      if (menuActive == changeSpeed) lineNumber = 1;
      if (menuActive == adjustSpeed) lineNumber = 1;
      if (menuActive == saveDefault) lineNumber = 2;
      Serial.print(F("Print Menu "));
      Serial.println(menuActive);
    }
  }

  // Print menu to LCD is changed
  if (prevMenu != menuActive) {
    /*
      #define mainMenu 1
      #define changeSpeed 2
      #define adjustSpeed 3
      #define saveDefault 4
      #define calibrateSpeed 5
      #define mainMenu2 6
    */
    selActive = false;   // update menu, require button press to show select line
    firstPress = false;  // first press will show selected line but not activate it
    Serial.print(F("Print Menu; menuActive = "));
    Serial.println(menuActive);
    prevMenu = menuActive;
    if (menuActive == mainMenu) {
      lcdPrintMainMenu();
    }
    if (menuActive == mainMenu2) {
      lcdPrintMainMenu2();
    }
    if (menuActive == changeSpeed) {
      lcdPrintChangeSpeed();
    }
    if (menuActive == adjustSpeed) {
      lcdPrintAdjustSpeed();
    }
    if (menuActive == saveDefault) {
      lcdPrintSaveDefault();
    }
    if (menuActive == calibrateSpeed) {
      lcdPrintCalibrateSpeed();
    }
  }
}

Now that makes sense and also what i suggested doesn't work.

The issue is that somewhere in the formatting there is a setting that puts every 'if' on a line by itself, and when the statement is on a line by itself, "if (DEBUG) Serial" is a statement that does not belong to the line that includes the #define anymore. Now the macro is empty, and the next line doesn't have a semicolon, nor a function for the object. It is a nice trick, but i don't think it's a really good idea. I would open the file in notepad++ and simply replace any occurrence of 'Serial' with 'if (DEBUG) Serial' , which admittedly is more work to type. Or is the correct #ifdef & #endif method, which actually does look disturbing and the pre-compiler should remove the if statements with literals, but i'm not sure it will.

You missed the fact that the formatter adds a backslash-newline when it breaks the macro into multiple lines for readability:

https://gcc.gnu.org/onlinedocs/cpp/Initial-processing.html#index-backslash-newline

  1. Continued lines are merged into one long line.
    A continued line is a line which ends with a backslash, ‘\’. The backslash is removed and the following line is joined with the current one. No space is inserted, so you may split a line anywhere, even in the middle of a word. (It is generally more readable to split lines only at white space.)

I disagree. The system described by @mtarr00 is excellent and has been used for many years by quite a few members of the Arduino community (including myself) without any significant problems.

Excellent observation. The problem is not specific to the change to the macro code. Arduino IDE 2.x has a bug that causes compilation to fail with a spurious "No such file or directory" error under the following conditions:

  • The sketch is in an unsaved state (AKA "dirty")
  • An #include directive in the dirty version of the code in the IDE editor is located at a line number of a different #include directive in the code saved on disk

The Arduino IDE developers are tracking the bug here:


:exclamation: Please only comment on the GitHub issue thread if you have new technical information that will assist with the resolution. General discussion and support requests are always welcome here on the Arduino Forum.


The workaround is to make sure to save the sketch before compiling, which will ensure the version of the code in the editor matches the code on disk. Arduino IDE has an "auto save" feature that will automatically save the sketch after every change. I'll provide instructions you can follow to enable that feature if you think it will be convenient:

  1. Select File > Preferences... (or Arduino IDE > Settings... for macOS users) from the Arduino IDE menus.
    The "Preferences" dialog will open.
  2. Check the box next to "Auto save" in the "Preferences" dialog.
  3. Click the "OK" button.
    The "Preferences" dialog will close.

Thanks ptillisch for the explanation. It makes sense now.

Just as a point of information:
Based on the fact that I am not an expert software developer, I have turned off auto-save so I can try things out to be sure I have not "broken" my sketch.

Due to the limited debug facilities in Arduino (Uno, Nano, Nano Every, Micro, etc.), I build and debug my sketches function by function. When the code is where it makes sense to save it, I do that. I prefer to have reached some (small) milestone for each save, and not save something that has difficult to find errors. This could be where it may not work exactly as I want, but it compiles properly and has "easy to find" bugs.

That's why auto-save is not a good solution for me; but now that I understand the problem, I can work with it.

Do you have any sense of when this will get fixed?

Thank you and
Best regards,
Morty

You are welcome. I'm glad we were able to solve the mystery at least, even if the "solution" is not very satisfying.

I understand completely. I also prefer to disable the "auto save" feature, as I prefer to have control over if and when my files are saved.

I don't. There are a lot of things on the "to do" lists for the Arduino developers, and limited development resources available to chip away at the lists. But we do have some very talented and dedicated people on the job so progress does occur, even if not so fast as the community might like.

I'm certain that if a community member submitted a high quality fix for the bug in this free open source software, it would be very much welcome.

I tend to leave auto-save on and save with a new name/version whenever i have found a stable state or am intending to start significant modifications that may not work out of the box and will need debugging before they compile. I sometimes do not continue at some point due to other things in life that need attention, and would always prefer to save the work, knowing it at least compiles, or not, but that is a pressing matter that needs attention.

The trickiest compile error is when there is a '{' extra or a '}' missing, sometimes because what should be a '{' or '}' are actually '(' & ')' and vice versa, that in combination with using auto-format to find errors can be hugely disturbing, and that causes me to hit the undo button. When an auto-correct doesn't provide the expected result as consequence of a missing ' " ' can be a real hassle as well when the content is HTML and if the auto-format adds spaces around operators the way i have it setup. If i forget undo and start looking first... well it's just what can happen.
But yeah i save with version numbers, so i also have a working version ready to go. (if it's a;ready working that is)