If statement problem

Compiling code for an ESP32 board.

I'm sure this is a simple thing I am overlooking so I would appreciate someone correcting me. I have coded this if statement:

if((Test==5) || (Test==7) || (Test==8) || (Test==11) || (Test==12)) Bypass = true;

Test is defined as byte and Bypass is Boolean.

Confirmed by diagnostic print statements the input condition is Test=0 and the output is Bypass = 1 while I expect Bypass to be 0 ie.false

Thanks to anyone who tells me what I am doing wrong.

Dale Gloer

Your topic was moved to its current location as it is more suitable.

Could you also take a few moments to Learn How To Use The Forum.

It will help you get the best out of the forum in the future.

Thank you

Bypass = 0


All you did wrong for sure is fail to post a complete we can compile and run it for ourselves sketch.

I was too lazy to code from your words, but @ruilviana seems to have done.


@ruilviana, this comment needs a comment!

  delay(10); // this speeds up the simulation

a7

Sorry, copy and paste cause error.
Comment deleted.

Damn! I thought you were on to something. :wink:

a7

then it means ByPass was true before. You are missing an else clause in your code or just write

  Bypass = ((Test == 5) || (Test == 7) || (Test == 8) || (Test == 11) || (Test == 12));

to ensure you force Bypass to a new value every time, either true or false.

Thank you for the suggestion - it gives the correct result. Perhaps you could explain why my statement didn't work as there are numerous others of the same format that do (I struggle with C++). For example these 4 statements
if((curVal < 50) && (curVal >= 40)) ltemp = ltemp * .75;
if((curVal < 40) && (curVal >= 30)) ltemp = ltemp * .5;
if((curVal < 30) && (curVal >= 20)) ltemp = ltemp * .25;
if(curVal < 20) ltemp = 0;

And since others have chastised me for not including the whole sketch, here it is. The subject line is line number 712.

Regards, Dale Gloer

// Steam Throttle Version 2E_8.1  2-19-2023   EZSBC ESP32 Dev Board
// Based on many enhancements for the Steam Throttle Dave Merrill 12-9-2022,2023 
// Based on Simple Wifi Throttle Version 5.3X  Geoff Bunza 2020,2023
//
// Second throttle built by Dale Gloer 07/04/2023 using an EzSBC ESP32 board
// Throttle name is EzSBC_Throttle 1
//
// Stripped all history updates - see the original for history.
// DG 07072023 Mod to stop sound looping when mute switch is on - tag is DEGMod01
// DG Corrected Sound file list and timing - Tag is DEGMod02
// DG added line of code to prevent continuous restarts of sound when buttons are held ON eg. stoker or water fill - tag is DEGMod03
//  DG added code to select which sounds stop playing when speed goes to zero - tag is DEGMod04  
//
//  Disabled DEGMod01 and DEGMod03 since they are unecessary
//
/*  **********************************************************************************
 *        CAUTION  
 * make sure that the pin assignments in this sketch match the 
 * functions that are assigned to the as built throttle.
 *
 *  **********************************************************************************
*/
//
// Special CONDITIONS:
// Turning Power On and holding the PB (Whistle) switch ON requests a Loco Address change
//  1. Let go of PB, display will change 
//  2. Headlight on changes 1000 digit, 1st Toggle changes 100 digit, 2nd Toggle 
//      changes 10 digit, 3rd Toggle changes 1st digit 
//  3. Press Water Injector switch to increase, press Coal Stoker switch to decrease
//  4. Holding PB for 1 Sec gets out of address set mode
//
// Setting 3 rightmost function switches on before powering up will turn DCC Power On
//
/*  ********************************************************************************
    ********************************************************************************
    *   IMPORTANT    Due to conflicts with another library you must ensure that the copy of 
    *                library  esp-oled-ssd1306  is the one stored in the 
    *                 .../Users/Owner/Documents/Arduino/Alternate_Libraries/SteamThrottle directory
    *                in order to compile this without errors.
    ********************************************************************************
    ********************************************************************************
*/ 
// For a connection via I2C using Wire include
#include <SSD1306Wire.h>
#include <WiFi.h>
#include <EEPROM.h>
#include <HardwareSerial.h>      // Used with DFPlayer
#include <DFRobotDFPlayerMini.h>
#include <TFT_ST7735.h>
#include "_images/Steam_FaceG_96.c"

SSD1306Wire  display(0x3c, 21, 22);   // I2C addr, SDA, SCK  Initialize the OLED display using Wire library
DFRobotDFPlayerMini myDFPlayer;       // Set up the Audio interface
#define __CS  5    // Chip Select, AKA Slave Select VPSI pin 5
#define __DC  16   // Data Command, AKA AO, AKA RS-Register Select
#define __RST 19   // Reset
TFT_ST7735 tft = TFT_ST7735(__CS, __DC, __RST);    // Set up the large display for Water Glass and Steam Gauge

// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
//#define LEVER   // Use with Serial Monitor to see pot reading and resultant for all 3 levers
#define SOUND    //  Use with serial monitor to debug sound problems

// WiFi Server Definitions

const char* ssid       = "TELUS0360-2.4G";
const char* password   = "selkirk5934";
const char* host = "192.168.1.94";  
/*
const char* ssid       = "Railway";
const char* password   = "";
const char* host = "192.168.1.91";  
*/ 
const int tpPort = 12090;              //  12090
String tname="EzSBC_Throttle1";         // This is the defined name of this throttle for the WiThrottle Server display
#define Throttle_audio_volume      30  // 1=30 This is the default audio volume for cab sounds in the throttle
#define background_sounds_volume   30  // 1-30 This is the default audio volume for random background cab sounds
#define background_sound_speed     30  // speed must be > this for background cab sounds to play
//
int speedmin =178;
int speedmax =291;
int jbarmin = 172;
int jbarmax = 287;
int brakemin =178;
int brakemax =319;

//  Switch  assignment table for all pins: 
#define  PB            26   // Pushbutton  active LOW usually assigned to F2 (Whistle)
#define  TA             2   // SPDT toggle active LOW  Headlight
#define  TB             4   // SPDT toggle active LOW  Bell
#define  TC            12   // SPDT toggle active LOW  Mute
#define  TD            14   // SPDT toggle active LOW  Spare
#define  TE            13   // SPDT toggle active LOW  Dim
#define  TF            27   // SPDT push active LOW  Cylinder Cock - Left side upper
#define  mute_sound    TC
#define  cylcockblow   TF
#define  ADC_Ch        39   // Center Wiper of 10K Speed Potentiometer Ends=GND & +3.3V
#define  jBar_Ch       32   // Center wiper of 10K Johnson Bar Potentiometer Ends=GND & +3.3v
#define  brake_Ch      36   // Center wiper of 10K Brake Potentiometer Ends=GND & 3.3v 
#define  waterInj      33   // Water Injector PB
#define  coalStok      15   // Coal Stoke PB
#define  tenderFill    25   // Tender Fill PB
#define  autoFireman   34   // Slide Switch to automatically refill water and steam gauges
#define  spareSlide    35   // Spare slide switch
//Function Assignments - with standard function numbers used with Steam Throttle
#define F0_pin         TA   // Function 0 pin assignment  F0 Headlight
#define F1_pin         TB   // Function 1 pin assignment  F1 Bell
#define F2_pin         PB   // Function 2 pin assignment  F2 Whistle
#define F3_pin         TC   // Function 3 pin assignment  F8 Mute
#define F4_pin         TD   // Function 4 pin assignment  F6 Spare
#define F5_pin         TE   // Function 5 pin assignment  F7 Dim
#define F6_pin         TF   // Function 6 pin assignment  F5 Cylinder Cock

int num_functions = 7;     // Number of functions supported by this throttle
int function_pin [ ]  ={ F0_pin,F1_pin,F2_pin,F3_pin,F4_pin,F5_pin,F6_pin };  // Ordered list of function pins
int function_map [ ]  ={ 0, 1, 2, 8, 6, 7 , 5};  // this will map the pin list to actual DCC function numbers
#define brake_sets_DCC_function   35             // This function will be set if the Brake Lever is >50% on
#define short_whistle_time 400                   // Set to 400ms to enable short whistle function, or 1 to disable

byte function_value [ ]={HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH };    // retained value of each function
byte foffset[ ] = {0, 12, 24, 39, 54, 66, 78};   // These are display offsets in info display for SWitch Abbreves
String fcs[ ] = {"L","B","W","M","S","D","C"};   // These are SWitch Abbreves in info display
boolean fvalue[ ]={false, false, false, false, false, false, false };  // These are the retained values of functions
// the following lines are wrong - silence is track 14 and should be listed last
// therefore the time line should have 200 as the last entry
// silence, CoalStoke, Water, TenderFill, 4hiss, 5rattle, 6hiss, 7clink, 8rattle, 9hiss, 11,12rattle,13blowdown
// unsigned long audio_track_time [ ]={200,22900,28000,42000,2200,86700,3600,1800,29200,3250,12500,118760,118760,62300};
//
// corrected lines follow                 DEGMod02
// CoalStoke, Water, TenderFill, 4hiss, 5rattle, 6hiss, 7clink, 8rattle, 9hiss, 10hiss, 11,12rattle,13blowdown, 14silence
 unsigned long audio_track_time [ ]={22900,28000,42000,2200,86700,3600,1800,29200,3250,12500,118760,118760,62300,200};
//
boolean sound_on = false;
boolean Bypass = false;
byte Test = 0;
byte sound_playing, old_sound = 0;
unsigned long audio_limit = 0;
#define silence_s      14
#define coalshovel_s   1
#define waterinject_s  2
#define tenderfill_s   3
#define blowdown_s     13
byte set_volume_level = 1;
byte setF = 1;
byte setR = 1;
boolean testv = false;
int DCC_address;
int temp_address;
#define  bounce_del  20
#define speed_repeat_bump  5
int speed_repeat_ctr = speed_repeat_bump;
boolean bvalue = false;
int lspeed = 0;      // Speed steps, 0-127
int ltemp = 0;       // Mapped speed pot value
int ltemp2 = 0;      // Temporary value used in calculating speed steps
int ltemp_prev = 5;  // Temporary value used in calculating speed steps
int prevSetSpeed = 1; // Temporary value used in uploading speed
int jbar_prev = 5;   // Temporary value used in calculating jBar value
int brake_prev = 5;  // Temporary value used in calculation brake steps
int tender_prev = 0; // Temporary value used in calculation tender water level
int tenderVal = 0;   // Temporary value used in calculation tender water level
int tenderLevel = 400; // Start level for full tender water 
int speedPot = 0;    // Pot reading used to map speed
int dirPot = 0;      // Pot reading used to map Johnson Bar setting
int brakePot = 0;    // Pot reading used to map brake

boolean ftn_temp = false;
boolean f0temp = false;
int i,j,k,l;
String DCCAdr_string, xmits;
#define fdelay 1
#define ldelay 50
String jmri_res;      //buffer to hold incoming response
int lastread = 0;
WiFiClient client;
boolean setaddr;
#define EEPROM_SIZE  64
const int audiocmddelay = 34;   // Short wait to let the DFPlayer receive & process the command
const uint8_t  bar_Width =     10;
#define dshift  10
byte g;
byte newVal;
byte curVal;
byte oldVal;
byte jbarVal;
byte brakeVal;
byte vgauge;
byte jFactor;
byte autoSwitch;
byte st2;
unsigned int changeSteam;       // Variable for steam consumption
unsigned int changeWater;       // Variable for water consumption
unsigned long changeSpeed;      // Variable for speed limiting
unsigned long currentTimeSteam;
unsigned long currentTimeWater;
unsigned long currentTimeSpeed;
unsigned long currentWaterDraw;
unsigned long currentSteamDraw;
unsigned long loopTimeSteam;
unsigned long loopTimeWater;
unsigned long loopTimeSpeed;
unsigned long loopWaterDraw;
unsigned long loopSteamDraw;
#define  loop_sample_time  250
bool autoFill = HIGH;
bool autoStok = HIGH;
bool firstFill = HIGH;

/////////////////// Setup ////////////////////////////////////////////
void setup()  {
#ifdef DEBUG
    Serial.begin(115200);
#else
#ifdef LEVER
    Serial.begin(115200);
#else    
#ifdef SOUND
    Serial.begin(115200);    
#endif
#endif
#endif
    analogReadResolution(9);   // Sets analog resolution to 9-bit, range 0-511
    tft.begin();               // Intro message until WiFi connects - serves as a reminder
    tft.setRotation(3);        // Reorientation of display based on the Steam Throttle mounting

    tft.drawImage(47, 17, &Steam_FaceG_96, NONE, 0);   // Display the Pressure Gauge Background
    tft.drawFastVLine( dshift+2, 17, 96, WHITE);       // Draw a Scale
    tft.drawFastHLine( dshift, 17, 4, WHITE);
    for (  g = 10; g < 95; g += 10 ) {
     tft.drawFastHLine( dshift, (g + 10), 4, WHITE);
    }
    curVal = 84;
    drawNeedle(curVal, 94, 64, 33, BLACK, WHITE);      // Draw Steam Level at 250

      vgauge = 85;                                     // Draw a pretty level
    tft.drawRect(dshift+4, 17, bar_Width, 97, WHITE);  // Draw the water sight glass
    st2 = map(vgauge, 0, 100, (96 - 2), 0);                                    // 
    tft.fillRect(dshift+5, 1, (bar_Width - 2), st2, BLACK);                    // Empty
    tft.fillRect(dshift+5, (st2 + 18), (bar_Width - 2), (96 - 2 - st2), BLUE); // Fill Up

    tft.setCursor(76, 50);                            // Now display the notice for WiFi Set Up
    tft.setTextColor(BLACK);
    tft.println("WAITING");
    tft.setCursor(73,72);
    tft.println("FOR WI-FI");
    tft.setTextColor(WHITE);

    if (!EEPROM.begin(EEPROM_SIZE))                   // Start the EEPROM interface
    {
  #ifdef DEBUG
      Serial.println("failed to initialise EEPROM");  // Send a message if we are in Debug mode
  #endif
      delay(1000000);
    }
    setaddr = false;
    for (i=0; i<num_functions; i++) {           // now set up the pins as inputs
      pinMode ( function_pin[i], INPUT_PULLUP); // Sets function pins to HIGH defaults
    }
    pinMode (waterInj, INPUT_PULLUP);           // Water Injector button
    pinMode (coalStok, INPUT_PULLUP);           // Coal/Stoker button
    pinMode (tenderFill, INPUT_PULLUP);         // Tendder Fill button - left side lower
    pinMode (autoFireman, INPUT_PULLUP);        // Auto Fireman switch - rear center
    pinMode (spareSlide, INPUT_PULLUP);         // Spare slide switch

#ifdef DEBUG
    Serial.println("Starting Setup");
#endif
    display.init();                             // Initialize the lower Data Display
    display.flipScreenVertically();             // Set the orientation
    display.setFont(ArialMT_Plain_16);          // Set the font to Arial
    display.clear();                            // Start with a clear display
    display.setTextAlignment(TEXT_ALIGN_LEFT);  // Align the text to the left side
    
  while (digitalRead(PB)==LOW)  {               // Starts Set Address if Whistle is activated during power-up
    display.setColor(DWHITE);
    display.drawString(0, 12, "SET ADDR?");
    display.display();
    delay(500);
    display.setColor(DBLACK);
    display.drawString(0, 12, "SET ADDR?");
    display.display();
    delay(350);                                   // Message flashes until PB released
    setaddr = true;                               // Flag the need to enter a new address later
  }
  
  // We get here only when PB was released --> PB == HIGH
  DCC_address = EEPROM.read(1);                     // Read previously saved address from EEPROM
  DCC_address = (DCC_address<<8)+EEPROM.read(2);    // 2 bytes long - we can handle long DCC addresses
  if ((DCC_address <= 0 )||(DCC_address > 9999)) {  // If stored address is out of bounds use address 3
#ifdef DEBUG
    Serial.print("Resetting DCC Addr ");
    Serial.println(DCC_address);
#endif
    DCC_address= 3;                         // We found a bad DCC stored address
    EEPROM.write(1, 0);                     // So We are defaulting to address 3
    EEPROM.write(2, 3);                     // and saving it in EEPROM for next time
    EEPROM.commit();
  }
  
  while (setaddr) {                         // Check if we need to enter a new address
#ifdef DEBUG
    Serial.println("Starting Address");
    delay(500);
#endif
    temp_address = DCC_address;
    display.setColor(DWHITE);
    display.drawString(0, 12, "SET ADDR?");  // Throttle indication to enter new DCC address
    display.drawString(0, 30, String(DCC_address));
    display.display();
    
      while (setaddr==true)  {               // Check each DCC address digit for increment/decrement
        if ((digitalRead(coalStok)==LOW)&&(digitalRead(F4_pin)==LOW)) temp_address++;
        if ((digitalRead(coalStok)==LOW)&&(digitalRead(F3_pin)==LOW)) temp_address = temp_address+10;
        if ((digitalRead(coalStok)==LOW)&&(digitalRead(F1_pin)==LOW)) temp_address = temp_address+100;
        if ((digitalRead(coalStok)==LOW)&&(digitalRead(F0_pin)==LOW)) temp_address = temp_address+1000;
        if ((digitalRead(waterInj)==LOW)&&(digitalRead(F4_pin)==LOW)) temp_address--;
        if ((digitalRead(waterInj)==LOW)&&(digitalRead(F3_pin)==LOW)) temp_address = temp_address-10;
        if ((digitalRead(waterInj)==LOW)&&(digitalRead(F1_pin)==LOW)) temp_address = temp_address-100;
        if ((digitalRead(waterInj)==LOW)&&(digitalRead(F0_pin)==LOW)) temp_address = temp_address-1000;
        if (temp_address <= 1) temp_address = 1;           // Trim address between 1 to 9999
        if (temp_address >= 9999) temp_address = 9999;
        if ((digitalRead(waterInj)==HIGH)&&(digitalRead(coalStok)==HIGH)) {   // Set Neutral
          delay(1000);
          if (digitalRead(PB)==LOW) setaddr = false;   // Exits Set Address by pulling PB Whistle 
        }
        display.setColor(DBLACK);
        display.drawString(0, 30, String(DCC_address)); // Erases previous address from display
        DCC_address = temp_address;
        display.setColor(DWHITE);
        display.drawString(0, 30, String(DCC_address)); // Dispalys current address on display
        display.display();
        delay(1000);       // Loops 1 second until waterInj and coalStok are released and whistle pressed
      }
    }

    if ((DCC_address <= 1 )||(DCC_address > 9999)) DCC_address = 1;   // Make sure we have a legitimate address
    EEPROM.write(1, (DCC_address>>8)&0xff);              // Save the working DCC address for next start up
    EEPROM.write(2, DCC_address&0xff);                   // both pieces for a long address
    EEPROM.commit();                                     // Writes current address to EEPROM
    delay(1000);
    display.clear();

    display.drawString(5, 12, tname);   // throttle name is now Steam Throttle but can be reset by tname
    display.display();
    // Connect to WiFi network
#ifdef DEBUG
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
#endif
    display.drawString(0, 30, "WiFi: " );
    display.drawString(50,30, ssid );
    display.display();
    WiFi.begin(ssid, password);                // Start the WiFi connection  using entered ssid and password
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
    }
#ifdef DEBUG
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("connecting to ");
    Serial.println(host);
    if (!client.connect(host, tpPort)) Serial.println("connection failed");
#endif
    if (!client.connect(host, tpPort)) return;  // Now connect to the WiThrottle server using the host IP Address and port

#ifdef DEBUG
    Serial.print("Throttle Name ");
    Serial.println(tname);
#endif
    client.println("N"+tname);                  // Tell the WiThrottle server the Name of Throttle
    delay(ldelay);
    display.setColor(DWHITE);
    display.clear();
    display.drawString(0, 12, "Loco: ");
    display.drawString(42, 12, String(DCC_address) );
    display.drawString(0, 48, "0  1  2  8         ");
    display.display();
    delay(3000);
    display.setColor(DBLACK);
    display.drawString(0, 48, "0  1  2  8         ");
    display.display();
    display.setColor(DWHITE);
    client.flush();
    display.drawString(0, 30, "Spd: " );
    display.drawString(36,30, String(lspeed) );
    display.display();
// Read all the lines of the reply from server and print them to Serial
    while (client.available()) {
      char c = client.read();
#ifdef DEBUG
      Serial.write(c);
#endif
    }
    delay(fdelay);
#ifdef DEBUG
    Serial.print("set address ");
    Serial.println(DCC_address);
#endif
    DCCAdr_string="S3";   // Unlikely default
    if ((DCC_address>0 ) && (DCC_address<128))  DCCAdr_string="S"+ String(DCC_address);
      else if ((DCC_address>127) && (DCC_address<9999)) DCCAdr_string="L"+ String(DCC_address);
    xmits = "MT+" + DCCAdr_string + "<;>" + DCCAdr_string + "\n\0";
	  client.print(xmits);       // set DCC address
    delay(ldelay);

    while (client.available()) {
      String jmri_res = client.readStringUntil('\n');
      if (jmri_res.startsWith("RPF")) {
#ifdef DEBUG
        Serial.println(jmri_res);
#endif
        jmri_res = jmri_res.substring(15);
        for (i=0; i<num_functions; i++)  {
          if (jmri_res.startsWith("true"))  {
            fvalue[i]= true;
            jmri_res = jmri_res.substring(12);
          }
          else {
            fvalue[i]= false;
            jmri_res = jmri_res.substring(13);
          }
        }
      }
    }
    delay(fdelay);
    //client.flush();

    //////////////  Turn on track power  ////////////
    if ((digitalRead(F1_pin)==LOW) && (digitalRead(F3_pin)==LOW) && (digitalRead(F4_pin)==LOW)) {
#ifdef DEBUG
    Serial.println("Power ON");
#endif
          set_power_on ();              // set POWER ON
          delay(fdelay); 
          client.flush();
       }
       speed_repeat_ctr = 0;

///////////////// Setup for Audio DFPlayer //////////////////
  Serial2.begin (9600, SERIAL_8N1, 34, 17);      // DFPlayer pins are actually 3.3 V compliant
  myDFPlayer.begin (Serial2);                    // set up serial channel to DFPlayer for commands
  delay(100);                                    // Wait for DFPlayer to initialize
  myDFPlayer.volume (Throttle_audio_volume);     // Set the volume level (1-30)
  delay(audiocmddelay);                          // Wait for DFPlayer to process commands

  /////////////////  Setup for SteamWater Gauge    ///////////////////
  tft.begin();                                     // Start the large tft display for gauges
  tft.setRotation(3);                              // Set the orientation
  tft.drawImage(47, 17, &Steam_FaceG_96, NONE, 0); // Draw the background image for the steam gauge
  tft.drawFastVLine( dshift+2, 17, 96, WHITE);     // Draw the Scale
  tft.drawFastHLine( dshift, 17, 4, WHITE);
  for (  g = 10; g < 95; g += 10 ) {
    tft.drawFastHLine( dshift, (g + 10), 4, WHITE);
  }
  vgauge = 5;
  tft.drawRect(dshift+4, 17, bar_Width, 97, WHITE);  // Draw the water sight glass
  st2 = map(vgauge, 0, 100, (96 - 2), 0);                                    // 
  tft.fillRect(dshift+5, 1, (bar_Width - 2), st2, BLACK);                    // Empty
  tft.fillRect(dshift+5, (st2 + 18), (bar_Width - 2), (96 - 2 - st2), BLUE); // Fill Up

  currentTimeSteam = millis();                      //  Set initial values
  currentTimeWater = currentTimeSteam;
  currentTimeSpeed = currentTimeSteam;
  currentWaterDraw = currentTimeSteam;
  currentSteamDraw = currentTimeSteam;
  loopTimeSteam = currentTimeSteam;
  loopTimeWater = currentTimeSteam;
  loopTimeSpeed = currentTimeSteam;
  loopWaterDraw = currentTimeSteam;
  loopSteamDraw = currentTimeSteam;
  curVal=84;
  vgauge = 90;
}   // End of Setup  ///////////////////////////////////////

void loop() {
    /////////          The Need for SPEED             ///////////
    speedPot = analogRead( ADC_Ch );  // Get Throttle pot reading
    speedPot = constrain (speedPot, speedmin, speedmax) ;   // constrain is here for possible future bounding
    ltemp = map(speedPot, speedmin, speedmax, 0, 127);      // First two numbers adjust for
                                                            // lever travel, next two numbers are speed steps
#ifdef DEBUG
    if(ltemp != ltemp_prev){  // If ltemp has changed
      Serial.print("Pot Speed ");
      Serial.print(speedPot);
      Serial.print(" Speed step ");
      Serial.println(ltemp);
      ltemp_prev = ltemp;
    }
#else
#ifdef LEVER
    if(ltemp != ltemp_prev){  // If ltemp has changed
      Serial.print("Pot Speed ");
      Serial.print(speedPot);
      Serial.print(" Speed step ");
      Serial.println(ltemp);
      ltemp_prev = ltemp;
    }
#endif
#endif

    //////////////// Read and Calculate Johnson Bar //////////////////////
    dirPot = analogRead( jBar_Ch );   // Get Johnson Bar pot reading
    dirPot = constrain (dirPot, jbarmin, jbarmax);   // constrain is here for possible future bounding
    jbarVal = map(dirPot, jbarmin, jbarmax, 0, 60);  // First two numbers adjust for
                                                     // lever travel, next two numbers are Johnson bar working values
#ifdef DEBUG
    if(jbarVal != jbar_prev){  // If jBar has changed
      Serial.print("jBar Pot ");
      Serial.print(dirPot);
      Serial.print(" jBar Setting ");
      Serial.println(jbarVal);
      jbar_prev = jbarVal;
    }
#else
#ifdef LEVER
    if(jbarVal != jbar_prev){  // If jBar has changed
      Serial.print("jBar Pot ");
      Serial.print(dirPot);
      Serial.print(" jBar Setting ");
      Serial.println(jbarVal);
      jbar_prev = jbarVal;
    }
#endif
#endif

    // jFactor needs to be defined for neutral JBar!
    if(jbarVal >= 35) jFactor = (jbarVal - 30)/10;  // Define jBar value in Fwd or Rev  jbarval == 1,2,3
    if(jbarVal <= 25) jFactor = (30 - jbarVal)/10;  // jFactor == 1,2,3
    if((jbarVal > 25) && (jbarVal < 35)) ltemp = 0;  // jBar has no effect in neutral
    changeSteam = 10000 - ((ltemp * 9) * jFactor);    // 0 to 1143  -> 6571 to 10000
    changeWater = 14000 - ((ltemp * 33) * jFactor);   // 0 to 4191  -> 1427 to 14000   //change 12000 to 14000

    //////// Limit acceleration based on jBar setting /////////// 
    changeSpeed = 1000/pow(jFactor, 3);      // ==1000/ < 1, 8, 27 > == 1000, 125, 37
#ifdef DEBUG
  Serial.print("changeSpeed= ");
  Serial.print(changeSpeed);
  Serial.print(" lspeed= ");
  Serial.print(lspeed);
  Serial.print(" ltemp= ");
  Serial.println(ltemp);
#endif
    currentTimeSpeed = millis();
    if (ltemp > lspeed) {
     if (currentTimeSpeed < (loopTimeSpeed + changeSpeed)) ltemp=lspeed+1;
      else loopTimeSpeed = currentTimeSpeed;
    }
    if (ltemp < lspeed) {
     if (currentTimeSpeed < (loopTimeSpeed + changeSpeed)) ltemp=lspeed-1;
      else loopTimeSpeed = currentTimeSpeed;
    }
#ifdef DEBUG
  Serial.print("Speed after JBar limit ltemp= ");
  Serial.println(ltemp);
#endif

    /////////////     Read Brake Pot      ///////////////
    brakePot = analogRead(brake_Ch);
    brakePot = constrain (brakePot, brakemin, brakemax);   // constrain is here for possible future bounding
    brakeVal = map(brakePot, brakemin, brakemax, 0, 10);   // change the pat range to 0-10

#ifdef DEBUG
    if(brakeVal != brake_prev){  // If Brake has changed
      Serial.print("Brake Pot ");
      Serial.print(brakePot);
      Serial.print(" Brake Setting ");
      Serial.println(brakeVal);
      brake_prev = brakeVal;
    }
#else
#ifdef LEVER
    if(brakeVal != brake_prev){  // If Brake has changed
      Serial.print("Brake Pot ");
      Serial.print(brakePot);
      Serial.print(" Brake Setting ");
      Serial.println(brakeVal);
      brake_prev = brakeVal;
    }
#endif
#endif

    ////////////////////  Set Direction ////////////////////////////////
    if (jbarVal >=35)  {
      if (setF==1)  {
        set_forward();
        setF=0;
        delay (bounce_del);
      }
    } else setF=1;
    if (jbarVal <=25)  {
      if (setR==1)  {
        set_reverse();
        setR=0;
        delay (bounce_del);
      }
    } else setR=1;
    if ((setF==1)&&(setR==1)) {
      display.setColor(DBLACK);
      display.fillRect(70, 30, 30, 18);
      display.setColor(DWHITE);
      display.drawString(70,30, "---" );
      display.display();
    }    

    //////////////////// Steam Loop /////////////
  currentTimeSteam = millis();
    if((currentTimeSteam >= (loopTimeSteam + changeSteam)) && (digitalRead(coalStok) == HIGH) && (autoStok == HIGH)){
                                           // If time and coal not pushed and coal not auto-refilling
      curVal--;                            // Depletes steam
      if(curVal <=1)  curVal = 1;          // Stops at zero pressure
       loopTimeSteam = currentTimeSteam;
    }
    if((currentTimeSteam >= (loopTimeSteam + loop_sample_time)) && (digitalRead(coalStok) == LOW)){
                                           // If time and coal pushed
      curVal += 2;                         // Manually adds coal
      if(curVal >= 84)  curVal = 84;       // Stops adding coal
      loopTimeSteam = currentTimeSteam;
    }  
    if((curVal < 50) && (digitalRead(autoFireman) == LOW))  autoStok = LOW;
    if((currentTimeSteam >= (loopTimeSteam + loop_sample_time)) && (autoStok == LOW))  {
      curVal += 2;
      sound_playing = coalshovel_s;        // Plays sound while coal fills
      if(curVal >= 83){
        autoStok = HIGH;                   // Takes autoStok out of the refill loop
      }
      loopTimeSteam = currentTimeSteam;
    }        
    
//////////  Limit throttle based on steam level ///////
    if((curVal < 50) && (curVal >= 40)) ltemp = ltemp * .75;            
    if((curVal < 40) && (curVal >= 30)) ltemp = ltemp * .5;
    if((curVal < 30) && (curVal >= 20)) ltemp = ltemp * .25;
    if(curVal < 20) ltemp = 0;
#ifdef DEBUG
  //Serial.print("Speed after steam level limit ");
  //Serial.print(ltemp);
  //Serial.print(" curVal ");
  //Serial.println(curVal);
#endif

   /////////////////////          Water Loop         ////////////////
currentTimeWater = millis();
    if((currentTimeWater >= (loopTimeWater + changeWater)) && (digitalRead(waterInj) == HIGH) && (autoFill == HIGH)){
                              // If time and injector not pushed and water not auto re-filling regardless of autoFireman
      vgauge--;               // Depletes water
      if(vgauge <=1)  vgauge = 1;        // Stops at empty
      loopTimeWater = currentTimeWater;  // Reset time for next water depletion
    }
    if((currentTimeWater >= (loopTimeWater + loop_sample_time)) && (digitalRead(waterInj) == LOW)){
                                         // If time and injector pushed 
      vgauge+=2;                         // Manually fills water regardless of autoFireman
      tenderLevel--;                     // Lowers tender level by same amount
      if(vgauge >= 95)  vgauge = 95;     // Stops at full
      loopTimeWater = currentTimeWater;
    }
    if((vgauge < 50) && (digitalRead(autoFireman) == LOW))  autoFill = LOW;
    if((currentTimeWater >= (loopTimeWater + loop_sample_time)) && (autoFill == LOW))  {
      vgauge+=2;                          // Fills water while on autoFireman
      tenderLevel--;                      // Lowers tender level by same amount
      sound_playing = waterinject_s;                   // Plays sound while water fills
      if(vgauge >= 95)  autoFill = HIGH;  // Stop autoFill
      loopTimeWater = currentTimeWater;
    }
  
    tenderVal = (50 - (tenderLevel/10));  // Code to update tender level
    display.setColor(DWHITE);
    display.fillRect( 110, 10, 16, 54);
    display.setColor(DBLACK);
    display.fillRect( 111, 11, 14, 52);
    display.setColor(DWHITE);
    display.fillRect( 113, 13, 10, 50);
    display.setColor(DBLACK);
    display.fillRect( 112, 12, 12, tenderVal);
    display.display();
    tender_prev = tenderVal;

    ///////////////     Refill tender loop     ///////
    while((digitalRead(tenderFill) == LOW) && (tenderLevel < 500) && (lspeed==0))  {
      tenderLevel ++;
      tenderVal = (50 - (tenderLevel/10));
      display.setColor(DWHITE);
      display.fillRect( 110, 10, 16, 54);
      display.setColor(DBLACK);
      display.fillRect( 111, 11, 14, 52);
      display.setColor(DWHITE);
      display.fillRect( 113, 13, 10, 50);
      display.setColor(DBLACK);
      display.fillRect( 112, 12, 12, tenderVal);
      display.display();
      sound_playing = tenderfill_s;   // Plays sound while tender fills
      delay(60);
    }

    if(vgauge < 25) ltemp = 0;        // Things to stop the loco
    if(brakeVal >= 9) ltemp = 0;
    if(tenderLevel <= 0) ltemp = 0;
    
#ifdef DEBUG
  Serial.print("ltemp: ");
  Serial.print(ltemp);
  Serial.print("  lspeed: ");
  Serial.println(lspeed);
#endif
    // Periodic Speed update
//    if (ltemp != lspeed)  {  // If speed has changed
      lspeed = ltemp;
      Test = sound_playing;        //  DEGMod04
//  if((Test==5) || (Test==7) || (Test==8) || (Test==11) || (Test==12)) Bypass = true;     // DEGMod04
    Bypass = ((Test==5) || (Test==7) || (Test==8) || (Test==11) || (Test==12));     // DEGMod04 try a different way
#ifdef SOUND
   Serial.print("sound playing   ");
   Serial.println(sound_playing);
   Serial.print("lspeed   ");
   Serial.println(lspeed);
   Serial.print("sound on  ");
   Serial.println(sound_on);
   Serial.print("Test   ");
   Serial.println(Test);
   Serial.print("Bypass   ");
   Serial.println(Bypass);
#endif     
//    if ((lspeed==0) && (sound_on==true) && (sound_playing!=0))  all_sound_off();  //speed went to 0 so turn sounds off     DEGMod04
      if ((lspeed==0) && (sound_on==true) && (Bypass==true))  all_sound_off();      //speed to zero and selected sounds on   DEGMod04
      if (speed_repeat_ctr++ > speed_repeat_bump )  { // If time to resend speed
        speed_repeat_ctr = 1;
        set_speed();
      }
    ///////////////       Function Loop         /////////////// flag

    for (i=0; i<num_functions; i++)  {
      switch ( i )  {  
        //case 0:   // Headlight
        case 5:   // Dim Headlight
          ftn_temp = bool( digitalRead(function_pin[5]) );
          f0temp =   bool( digitalRead(function_pin[0]) );
          if (!ftn_temp) {                         // We're fully down
             if (fvalue[0]) { fvalue[0]=false; set_function ( 0 ); }
             if (fvalue[5]) { fvalue[5]=false; set_function ( 5 ); }
          }
            else if (ftn_temp && f0temp) {           // We're in the middle setting
              if ((!fvalue[0])) { fvalue[0]=true; set_function ( 0 ); }
              if ((!fvalue[5])) { fvalue[5]=true; set_function ( 5 ); }
              }
              else if (!f0temp) {                     // We're fully up
                if (fvalue[5]) { fvalue[5]=false;set_function ( 5 );}  // Turn off Dim leave Headlight on
                if (!fvalue[0]) { fvalue[0]=true; set_function ( 0 );}              //We came quickly from off so turn Headlight on
              }
          delay(100);
        break;
        case 2:    // Whistle
          if ( digitalRead( function_pin[2])== LOW ) {     // Whistle is a special case
            delay (short_whistle_time);                    // Let's see if its a short whistle
            if (digitalRead( function_pin[2])== HIGH) {    // Whistle Pull released in <short_whistle_time 0.4secs              xmits = "MTA"+DCCAdr_string+"<;>F13";          // So Short Whistle function is sent
              xmits = "MTA"+DCCAdr_string+"<;>F13";        // Signal Short Whistle Function 3
              client.println(xmits);
              delay (ldelay);
              xmits = "MTA"+DCCAdr_string+"<;>F03";        // Signal Short Whistle Function 3
              client.println(xmits);
              delay (ldelay);
            }
            else {
              display.setColor(DWHITE);
              display.drawString(foffset[2], 48, fcs[2]);
              display.display();
              xmits = "MTA"+DCCAdr_string+"<;>F12";
              client.println(xmits);
              delay(200);
              if (digitalRead( function_pin[2])== HIGH) {

              }
              while (digitalRead( function_pin[2])== LOW)  client.flush();
              delay (ldelay);
              xmits = "MTA"+DCCAdr_string+"<;>F02";
              client.println(xmits);
              client.flush();
              display.setColor(DBLACK);
              display.drawString(foffset[2], 48, fcs[2]);
              display.display();
            }
          }
        break;
        case 1:
        case 3:
        case 4:
        case 6: {
            if (!bool(digitalRead( function_pin[i])) != fvalue[i])  {   // If function switch has changed
            fvalue[i]= !fvalue[i];           // flip the old state
            set_function ( i );              // TOGGLE FUNCTION, see void set_function
            delay (100);
            }
          }
        break;
        default:
        break;
      }
    }

    ftn_temp = false;
    if(brakeVal >= 5) ftn_temp = true ;
    if(ftn_temp != bvalue) {
      bvalue = ftn_temp;
      set_brake ();           // Toggle the brake
      delay (bounce_del);
    }

    //delay (400);
	  client.print("*\n\0");       // Send a "Heart Beat" to the WiThrottle Server"

  /////////////////      DFPlayer Loop      ///////////////
  if (digitalRead(mute_sound)==HIGH)  {     // Continue on if the Mute switch is not set
  #ifdef SOUND
   Serial.println(" In unmute sound play"); 
   Serial.print("Old Sound   ");Serial.print(old_sound);Serial.print("   Sound Playing   ");Serial.println(sound_playing);
  #endif   
    old_sound = sound_playing;
    if (digitalRead(waterInj)==LOW)  {sound_playing = waterinject_s; set_volume_level=Throttle_audio_volume;}
    if (digitalRead(coalStok)==LOW)  {sound_playing = coalshovel_s; set_volume_level=Throttle_audio_volume;}
    if ((digitalRead(tenderFill)==LOW)&&(lspeed==0))  {sound_playing = tenderfill_s; set_volume_level=Throttle_audio_volume;}
    if (digitalRead(cylcockblow)==LOW)  {sound_playing =  blowdown_s; set_volume_level=Throttle_audio_volume;}

    // background cab sounds play if no sounds playing, 30% of the time, and speed is > threshold setting
    if ((sound_playing==0) && (random(1-99)>70) && (lspeed>background_sound_speed))  {
      sound_playing=random (4,13); 
      set_volume_level = background_sounds_volume;  // Set the background volume level (1-30)
    }
  #ifdef SOUND
   Serial.print(" Is sound on   ");Serial.println(sound_on); 
   Serial.print("Old Sound   ");Serial.print(old_sound);Serial.print("   Sound Playing   ");Serial.println(sound_playing);
  #endif       
    if (((sound_on==false) && (sound_playing!=0)) || (sound_on && (sound_playing!=old_sound)))  {
      sound_on = true;
  #ifdef SOUND
    Serial.print("  Set sound on    ");Serial.println(sound_on);
    Serial.print("  Play this sound   ");Serial.println(sound_playing);
  #endif     
//      old_sound = sound_playing;    //DEGMod03
      myDFPlayer.volume (set_volume_level);         // Set the default volume level (1-30)
      delay(audiocmddelay);                         // Wait for DFPlayer to process command
      myDFPlayer.play(sound_playing);               // Start playing sound clip
      delay(audiocmddelay);
      audio_limit= millis()+audio_track_time[sound_playing];
    } 
    else if (sound_on && (millis()>audio_limit))  all_sound_off ();  // Change to silence rapindly ends playing
  } else all_sound_off();     // Mute is on so force sound off  DEGMod01
/*    } else if (sound_on) {      //  only if this is the    DEGM0d01 
        all_sound_off();        //   first time here with Mute ON  DEGMod01
      }
*/
  ////////////////// SteamWater Loop ///////////////
    g = 1;
    tft.drawRect(dshift+4, 17, bar_Width, 97, WHITE);       // 
    currentWaterDraw = millis();
    if(currentWaterDraw >= (loopWaterDraw + loop_sample_time)){
      st2 = map(vgauge, 0, 100, (96 - 2), 0);                                    // 
      tft.fillRect(dshift+5, 18, (bar_Width - 2), st2, BLACK);                   // Empty
      tft.fillRect(dshift+5, (st2 + 19), (bar_Width - 2), (96 - 2 - st2), BLUE); // Fill Up
      loopWaterDraw = currentWaterDraw;
    }
    
    currentSteamDraw = millis();
    if(currentSteamDraw >= (loopSteamDraw + loop_sample_time)){
      drawNeedle(curVal, 94, 64, 33, BLACK, WHITE);
      oldVal = curVal;
      loopSteamDraw = currentSteamDraw;
    }

}    //  End of Loop    ///////////////////////////////////////////////////
void all_sound_off ()  {
      myDFPlayer.play(silence_s);               // Change to silence rapindly ends playing
      delay(audiocmddelay);
      sound_on = false;
      sound_playing = 0;
}
void set_speed ()  {
#ifdef DEBUG
   // Serial.print(" Set Speed ");
   // Serial.println(lspeed);
#endif
    // set Speed NO update if Neutral
    if ((prevSetSpeed > 0)||(setF==0)||(setR==0)) {                // if we're in FWD or we are in REV
      client.println( "MTA"+DCCAdr_string+"<;>V"+String(lspeed) );   // Set speed in JMRI
      display.setColor(DBLACK);
      display.fillRect(36, 30, 34, 18);
      display.setColor(DWHITE);
      display.drawString(36,30, String(lspeed) );
      display.display();
      prevSetSpeed = lspeed;
      delay(40);
    }
}

void set_function (byte fi) {
#ifdef DEBUG
    Serial.print("toggle F");
    Serial.println(fi);
#endif
    xmits = "MTA"+DCCAdr_string+"<;>F1"+String(function_map[fi]);
    client.println(xmits);            // Toggle Function
    delay(50);
    //xmits = "MTA"+DCCAdr_string+"<;>F0"+String(function_map[fi]);
    //client.println(xmits);
    if (fvalue [fi]) {
      display.setColor(DWHITE);
      display.drawString(foffset[fi], 48, fcs[fi]);
      display.display();
    }
    else  {
      display.setColor(DBLACK);
      display.drawString(foffset[fi], 48, fcs[fi]);
      display.display();
    }
    client.flush();
}

void set_brake() {                     // Toggle Function 4
    client.println("MTA"+DCCAdr_string+"<;>F1"+String(brake_sets_DCC_function));
    delay(50);
    client.println("MTA"+DCCAdr_string+"<;>F0"+String(brake_sets_DCC_function));
    client.flush();
}

void set_forward()  {
#ifdef DEBUG
    Serial.println("forward direction");
#endif
    client.println("MTA"+DCCAdr_string+"<;>R1");              // set forward direction
    display.setColor(DBLACK);
    display.fillRect(70, 30, 30, 18);
    display.setColor(DWHITE);
    display.drawString(70,30, "Fwd" );
    display.display();
}
void set_reverse()  {
#ifdef DEBUG
    Serial.println("reverse direction");
#endif
    client.println("MTA"+DCCAdr_string+"<;>R0");              // set reverse direction
    display.setColor(DBLACK);
    display.fillRect(70, 30, 30, 18);
    display.setColor(DWHITE);
    display.drawString(70,30, "Rev" );
    display.display();
}
void set_power_on()  {
  client.println("PPA1\n\0");            // set POWER ON
  delay(ldelay);
  client.flush();
}
/*
void set_power_off()  {
  client.println("PPA0\n\0");            // set POWER OFF
  delay(ldelay);
  client.flush();
}
void dispatch_throttle ()  {
  client.println("MTA"+DCCAdr_string+"<;>d");              // dispatch Throttle
  delay(ldelay);
  client.flush();
  display.setColor(DBLACK);
  display.fillRect(42, 12, 36, 18);
  display.setColor(DWHITE);
  display.drawString(42, 12, "???" );
  display.display();
}
void terminate_all ()  {
  #ifdef DEBUG
    Serial.println("Power OFF");
#endif
    set_power_off ();             // set POWER OFF
    delay(fdelay);
    dispatch_throttle ();         // dispatch throttle
    delay(fdelay);
    while (client.available()) {
      char c = client.read();
      Serial.write(c);
    }
#ifdef DEBUG
    Serial.println();
    Serial.println("end connection");
#endif
    client.stop();
    while (true) delay(1000);
}
*/

void drawNeedle(int16_t val, uint8_t x, uint8_t y, uint8_t r, uint16_t color, uint16_t bcolor) {
  uint8_t g;
  if (curVal > oldVal) {
    for (g = oldVal; g <= curVal; g++) {
      drawPointerHelper(g - 1, 94, 64, r, bcolor);
      drawPointerHelper(g, 94, 64, r, color);
      if ((curVal - oldVal) < (84)) delay(5);
    }
  }
  else {
    for (g = oldVal; g >= curVal; g--) {
      drawPointerHelper(g + 1, 94, 64, r, bcolor);
      drawPointerHelper(g, 94, 64, r, color);
      if ((oldVal - curVal) >= 84) {
        delay(5);
      } else {
        delay(9);
      }
    }
  }
}      //  end  drawNeedle()
void drawPointerHelper(int16_t val, uint8_t x, uint8_t y, uint8_t r, uint16_t color) {
  float dsec, toSecX, toSecY;
  int16_t minValue = 0;
  int16_t maxValue = 100;
  int fromDegree = 132;       //start
  int toDegree = 271;         //end
  if (val > maxValue) val = maxValue;
  if (val < minValue) val = minValue;
  dsec = (((float)(uint16_t)(val - minValue) / (float)(uint16_t)(maxValue - minValue) * toDegree) + fromDegree) * (PI / 180);
  toSecX = cos(dsec) * (r / 1.35);
  toSecY = sin(dsec) * (r / 1.35);
  tft.drawLine(x, y, 1 + x + toSecX, 1 + y + toSecY, color);
  tft.fillCircle(x, y, 2, color);
}      //   end  drawPointerHelper()

//  Wifi Command Calls
//
//  set_function ( xxx );       // Toggle Function xxx
//  dispatch_throttle ();       // dispatch throttle
//  set_forward();              // Set forward direction
//  set_reverse():              // Set reverse direction
//  set_speed();                // set speed based on global valie lspeed 
//
//  set_power_on ():            //
//  set_power_off ();           //
//  dispatch_throttle ();       //
//  terminate_all ();           //
//

@J-M-L explains it perfectly in #7.

Using an if statement, the value gets set to true only if at least one of the "or" parts is true.

It does not get set to false if all of them are false.

So if it was true going in, and all the elements were false, nothing sets it to false.

This is why we "chastised" you. @J-M-L was able to deduce the reason for your observation, which some of the rest of us would have spotted in context.

So you could… use an assignment, so the bool would get set true or false no matter what it was coming in, or use an else clause which woukd take care of it the same way.

    bool x = true;
    if (theSkyIsGreen) x = false;  // does not execute the assignment statement

while

    bool x = true;
    x = theSkyIsGreen;  // does set x false

as does

    bool x = true;
    if (theSkyIsGreen) x = false;
    else x = true;

Your other if statements may or not need the same attention.

Don't feel too bad, it's a subtle thing at first, and I will say it did not occur to me. And might never have. It would be a mysterious thing. There is no implicit taking care of the thing the else does.

Which all sounds more confusing, sry.

a7

Is it clearer now?

Thank you for taking the time for the detailed explanation. I am an old dog trying to learn new tricks - in this case C++ - which is a struggle for me. (Can you say Fortran or PL1?) I really appreciate both J-M-L and A7 answering.

So I learned a couple of things with this query.

Dale Gloer aka Selkirk5934