How to implement tabbed serial print? TRACE macro ?

An old TRACE macro implemented in ancient C++ samples I have lost long time ago basically formatted / tabbed the serial outputs so they can be easier associated with current “stack” level.

Here is what it looked , nice tabbed / aligned to each function level

Function test variable XYZ
Variable XYZ is…
Function Analyze variable X
Variable X is …

Function Analyze variable y
Variable Y is …
Function Size of variable y
Variable Y greater that 10
Function Analyze variable Z
Variable Z is …
Function test variable ABC
Variable XYZ is…

Anybody knows what I am referring to and or know how to implement it in Arduno code?
I think the key was advancing / retracting global variable " tab " in each TRACE macro.

I think what you are looking for is the \t character to send a tab.

Serial.println("Text without indentation");
Serial.println("\tText indented one level");
Serial.println("\t\tText indented two levels");

It seems what you are describing is more automated though, but I'm not sure I understand the question in that case.

you need something like this

//
//    FILE: debugDemo.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo, should be a class
//    DATE: 2015-01-10
//     URL: http://forum.arduino.cc/index.php?topic=370903.0
//
// Released to the public domain
//

int dbglevel = 0;

void setup()
{
  Serial.begin(115200);
  Serial.print("Start ");
  Serial.println(__FILE__);
  x();

  Serial.println(fac(10));
}

void loop()
{
}

void x()
{
  dbgEnter(__FUNCTION__);
  dbgPrint("before call ");
  intermediate();
  dbgPrint("in between");
  workhorse();
  dbgPrint("I'm here");
  intermediate();
  dbgPrint("big step");
  dbgLeave(__FUNCTION__);
}

void intermediate()
{
  dbgEnter(__FUNCTION__);
  dbgPrint("should work");
  workhorse();
  dbgPrint("twice");
  workhorse();
  dbgLeave(__FUNCTION__);
}


void workhorse()
{
  dbgEnter(__FUNCTION__);
  dbgPrint("abcdef");
  dbgLeave(__FUNCTION__);
}

int fac(uint32_t n)
{
  dbgEnter(__FUNCTION__);
  dbgPrint(n);
  if (n == 1)
  {
    uint32_t val = 1;
    dbgLeave(__FUNCTION__);
    return val;
  }
  else
  {
    uint32_t val = n * fac(n - 1);
    dbgLeave(__FUNCTION__);
    return val;
  }
}



void dbgEnter(const char *str)
{
  ++dbglevel;
  for (int i = 0; i < dbglevel; i++) Serial.print("  ");
  Serial.print("enter ");
  Serial.println(str);
}

void dbgPrint(const char *str)
{
  for (int i = 0; i < dbglevel; i++) Serial.print("  ");
  Serial.println(str);
}

void dbgPrint(uint32_t val)
{
  for (int i = 0; i < dbglevel; i++) Serial.print("  ");
  Serial.println(val);
}

void dbgLeave(const char *str)
{
  for (int i = 0; i < dbglevel; i++) Serial.print("  ");
  Serial.print("leave ");
  Serial.println(str);
  --dbglevel;
}

Should be a debugClass, derived from Print, with an internal stack of function names or so.

Used a similar trick in my XML writer - http://forum.arduino.cc/index.php?topic=197823.0
to get indentation right.

you could even use

void workhorse()
{
  dbgEnter(__FUNCTION__);
  dbgPrint(__LINE__);
  dbgLeave(__FUNCTION__);
}

Those could also be used in

define TRACE(msg) { Serial.print(FUNCTION); Serial.print("\t"); Serial.print(LINE); Serial.println(msg); }

(without the identation)

Thanks, that is what I am looking for. I'll need to study all of your code. I already use print(func_) , but I need to make the number of tabs variable according to how deep is the "stack". . I think I need to "wrap" standard Serial. print inside this TRACE macro. That is OK if starting new code , but I got tons of code I would like to modify and I do not trust the IDE "find" and "replace". I'll give is a shot anyway. Thanks again.

found some time to wrap it in a class - to be refactored into a .h/.cpp file

//
//    FILE: debugClass.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo
//    DATE: 2015-01-10
//     URL: http://forum.arduino.cc/index.php?topic=370903.0
//
// Released to the public domain
//

// initial version
class Debug
{
  public:
    Debug()
    {
      _level = 0;
      _disable = false;
    };

    void enable(bool b)
    {
      _disable = !b;
    }

    void indent(bool b)
    {
      _indentFlag = b;
    }

    void enter(const char *msg)
    {
      if (_disable) return;
      ++_level;
      _indent();
      Serial.print("enter ");
      Serial.println(msg);
    }

    void print(const char *msg)
    {
      if (_disable) return;
      _indent();
      Serial.println(msg);
    }

    void print(uint32_t val)
    {
      if (_disable) return;
      _indent();
      Serial.println(val);
    }

    void assert(bool expr, const char *msg)
    {
      if (_disable) return;
      _indent();
      if (!expr) this->print(msg);
    }

    void leave(const char *msg)
    {
      if (_disable) return;
      _indent();
      Serial.print("leave ");
      Serial.println(msg);
      --_level;
    }

  private:
    int _level = 0;
    bool _disable = false;
    bool _indentFlag = true;

    void _indent()
    {
      if (_indentFlag) for (int i = 0; i < _level; i++) Serial.print("  ");
    }
};

Debug dbg;

void setup()
{
  Serial.begin(115200);
  Serial.print("\nStart ");
  Serial.println(__FILE__);
  x();

  Serial.println(fac(6));
  dbg.enable(false);
  Serial.println(fac(10));
  dbg.enable(true);
  dbg.assert(fac(2) == 3, "FOUT");
  dbg.assert(fac(2) == 2, "OK");
  int val = analogRead(A0);
  dbg.enable(val > 100);
  x();
}

void loop()
{
}

void x()
{
  dbg.enter(__FUNCTION__);
  dbg.print("before call ");
  intermediate();
  dbg.print("in between");
  workhorse();
  dbg.print("I'm here");
  intermediate();
  dbg.print("big step");
  dbg.leave(__FUNCTION__);
}

void intermediate()
{
  dbg.enter(__FUNCTION__);
  dbg.print("should work");
  workhorse();
  dbg.print("twice");
  workhorse();
  dbg.leave(__FUNCTION__);
}


void workhorse()
{
  dbg.enter(__FUNCTION__);
  dbg.print(__LINE__);
  dbg.leave(__FUNCTION__);
}

int fac(uint32_t n)
{
  dbg.enter(__FUNCTION__);
  dbg.print(n);
  if (n == 1)
  {
    uint32_t val = 1;
    dbg.leave(__FUNCTION__);
    return val;
  }
  else
  {
    uint32_t val = n * fac(n - 1);
    dbg.leave(__FUNCTION__);
    return val;
  }
}

an int and 2 extra defines should do it

int dbgindent = 0;

#define ENTER(msg) { dbgindent ++; TRACE(msg); }
#define LEAVE(msg) { TRACE(msg); dbgindent --; }
#define TRACE(msg) { for(int i=0;i<dbgindent ;i++) Serial.print(" "); Serial.println(msg); }

not 100% proof but maybe good enough

Rob, just added some test traces to my main program and it works as expected. Thanks, you ARE THE MAN!

I think macros are neat!

Welcome