// infrastructure
// routine IDs 2xxx

#define TAB '\t'
         const char BLANK               = ' ';
         const char CR                  = '\n';
         const bool DisallowTimeSetting = false;
         const char DOT                 = '.';
         const char EXCLAIM             = '!';
         const char HYPHEN              = '-';
         const char LF                  = 10;
const unsigned long msOneSecond         = 1000;
const unsigned long msOneMinute         = 60 * msOneSecond;
         const char nullstring[]        = "";
         const char PERIOD              = DOT;
         const char RPAR                = ')';
               char SLASH               = '/';

          const int DotInterval = 30 * msOneSecond;
          
elapsedMillis elmsSinceTickled;
unsigned long GrossDumpSize;

void Hang(const char Reason[]);
void Hang()                             { Hang("(unknown reason)"); }

class tInfrastructure
  { public:
               bool Debugging;
      tGlobalStatus GlobalStatus;
               bool InIDE;
               bool Interrupting;
               bool ShutDownRequested;

      void BadNews(const char Message[], const int MessageID);
      void Blink(int N);
      void CheckWindowsConnection();
      bool ConfirmNotDumping(const char Message[]);
      bool IsGrounded(const int ThePin);
      void SayInIDE(const char Message[]);
      void SetGlobalStatus(const tGlobalStatus NewStatus);          // deferred to infrastructure2
      void setup();
      void TellWindows(const char Message[], const int MessageID);  // ..
      void TellWindows(const int MessageID);                        // ..

      // ********* implicit arguments ***********************************
      void BadNews(const char Message[])      { BadNews(Message, btwUnknown); }
      void TellWindows(const char Message[])  { TellWindows(Message, btwUnknown); }
  }; // tInfrastructure

void tInfrastructure::BadNews(const char Message[], const int MessageID)
  { TellWindows(Message, MessageID);
    Hang(Message);
  } // tInfrastructure::BadNews

void tInfrastructure::Blink(int N)
  { // used only during main setup
    const int msBlink = 200;
    for (int I = 1; I <= N; I++)
      { digitalWrite(pinBlink, LOW);
        delay(msBlink);
        digitalWrite(pinBlink, HIGH);
        delay(msBlink);
      }
    digitalWrite(pinBlink, LOW);
    delay(msOneSecond);
  } // tInfrastructure::Blink

void tInfrastructure::CheckWindowsConnection()
  { const int TooLong = 10 * msOneMinute;
    char Message[100];

    if (elmsSinceTickled > TooLong)
     { sprintf(Message, "elmsSinceTickled = %d, TooLong = %d\n",
                        (int)elmsSinceTickled, TooLong);
       TellWindows(Message, btwTimedOut);
       SetGlobalStatus(gsNotConnected);
     }
  } // tInfrastructure::CheckWindowsConnection()

bool tInfrastructure::ConfirmNotDumping(const char Message[])
  { // routine ID 2009
    // tell windows that request unavailable
    bool Result = ((GlobalStatus != gsDumpInProgress) or InIDE);

    if (not Result)
      { char Msg[100];
        sprintf(Msg, "%s request not accepted during dumping", Message);
        TellWindows(Msg, btwDebugging);
      }
    return Result;
  } // tInfrastructure::ConfirmNotDumping

bool tInfrastructure::IsGrounded(const int ThePin)
  { // routine ID 2040
    pinMode(ThePin, INPUT_PULLUP);
    return (digitalRead(ThePin) == LOW);
  } // tInfrastructure::IsGrounded

void tInfrastructure::SayInIDE(const char Message[])
  { if (InIDE)
      { Serial.printf("In IDE: %s\n", Message); }
  } // tInfrastructure::SayInIDE

void tInfrastructure::setup()
  { // for top-level setup
    pinMode(pinBlink, OUTPUT);
    pinMode(pinConnectedToWindows, OUTPUT);
    digitalWrite(pinConnectedToWindows, LOW);
    GlobalStatus = gsNotConnected;
    Interrupting = false;
    InIDE = IsGrounded(pinGNDInIDE);
    Debugging = IsGrounded(pinGNDDebug);
    if (Debugging)
      { SayInIDE("debugging"); }
    ShutDownRequested = false;
  } // tInfrastructure::setup

tInfrastructure Infrastructure;

void Hang(const char Reason[])
  { // routine ID 0040
    Infrastructure.SayInIDE(Reason);
    Serial.printf("Giving up because %s", Reason);
    while (true);
  } // Hang

// ********** table of contents ************************************
int  StringToInt(char str[], const int First, const int Last);
int  StringToInt(char Str[], const int Limit);



// ******** substance ********************************************
int StringToInt(char str[], const int First, const int Last)
  { // 1-based
    int Result = 0;
    for (int I = First; I <= Last; I++)
      { Result = 10 * Result + str[I-1] - '0'; }
    return Result;
  } // StringToInt(char str[], const int First, const int Last)

int StringToInt(char Str[], const int Limit)
  { // routine ID 2060
    int Result = 0;

    for (int I = 0; (Str[I] != 0) and (I <= Limit); I++)
      { Result = 10 * Result + Str[I] - '0'; }

    return Result;
  } // StringToInt(char Str[], const int Limit)




// **************** end infrastructure ******************************************

