Developing a Class

I have been trying to develop a class that allows me to do debugging displays to a SoftwareSerial port of my choosing. My intent is to provide the baud rate and pin # to the constructor. I wouldn't be surprised if I'm reinventing something that has been done 1000 times. I look upon it as a learning exercise.
In the code I've provided, I get a compile error saying the 'identifier (mySerial) has not been declared in the current scope'. I understand the error -- I'm just not good enough with classes to solve it. Here is the sketch:

#include <SoftwareSerial.h>
class Dbg {
  private:
	  int baud, TxPin;
  public:
	  Dbg (int baud, int TxPin) {
      this->baud  = baud;
      this->TxPin = TxPin;
    }
    void begin() {
      // setup SoftwareSerial ???
      SoftwareSerial mySerial = SoftwareSerial(0,TxPin);
      mySerial.begin(baud);
    }
    void prt(char* txt) {
      mySerial.println(txt);
    }
};//Dbg

char msg[] = "debug msg";
Dbg  dbg   = Dbg(9600,10); //baud,TxPin

void setup() {
  dbg.begin();
  dbg.prt(msg);
}
void loop() {}

The object is created in "begin()" but I want to use it in "prt()".
I'm not sure how to solve it.
Thanks --Ray

Make this a private member.

Edit: or make your class inherit from Software Serial.

I'm not sure what you are saying.

OK, thanks.

When you do this your mySerial instance is short lived… (a local variable) so goes out of scope and is not known to the other member functions.

Best probably would be to instantiate the Stream you want to use outside your class and pass that Stream pointer or reference to your constructor.

This would allow the debug info to go to hardware or software serial for example

imho it's not a good idea to do a .begin() of a stream in the class.
If you need a Stream in your class,
give the user the oportuinity to hand over a Stream in the constructor.
So the user can decide if he wans to use hwserial, softserial, altserial.
He can change the baudrate, bits/stopbits/parity ... whatever the stream offers.

On the other hand I don't see what your class should do anyway.
Currently you have an object called dbg which can be used to print something.
What have you achieved in comparison of a global object

SoftwareSerial dbg (10, 11);
and

dbg.begin(9600); // in setup
?

OK, I think I understand what you've said. I believe it to be essentially the same as what J-M-L Jackson told me? Is that correct?

Also, here is the code I'm trying to run. The output shows up on the Serial Monitor (HW), but I don't see anything on PuTTY, who is monitoring Pin 2 on the Nano (the Tx pin).

#include <SoftwareSerial.h>
#define BAUD  4800
#define TXPIN 2
#define RXPIN 3
class Dbg {
  private:
	  int baud, TxPin;
    SoftwareSerial mySerial = SoftwareSerial(3,TxPin);
  public:
	  Dbg (int baud, int TxPin) {
      this->baud  = baud;
      this->TxPin = TxPin;
    }
    void begin() {
      mySerial.begin(baud);
    }
    void prt(char* txt) {
      Serial.print("Serial:");Serial.println(txt);
      mySerial.println(txt);
    }
};//Dbg

char msg[] = "debug msg";
Dbg  dbg   = Dbg(BAUD,TXPIN);

void setup() {
  Serial.begin(115200);
  
  dbg.begin();
  dbg.prt(msg);
}
void loop() {}

TxPin doesn't have a defined value at this point.

I like the idea of passing a Stream reference in, but remember that Stream cannot set signalling parameters like line speed, so these have to be done externally.

Yes, I think so. I need to be able to do 2 things:

  1. understand why what I now have does not work!
  2. be able to write a line of code like this: 'dbg("some text");' anywhere I need it during debugging and have the output go to a pin I have previously chosen to monitor with a terminal program like PuTTY.

Do you think you could help me achieve both objectives?
Thanks -Ray

I thought the TxPin had a value as a private member being set by the constructor?

this
"dbg("

trailer header should be always printed, despite of using print, println with any type of variable?

But you haven't called the Dbg constructor there.

It's akin to this

char value = Serial.read ();

void setup ()
{
  Serial.begin (115200);
}

void loop () {}

I'm not really sure what you mean by the term 'trailer', however, I'm not concerned at the moment with EOL terminators or NOT and I'm not currently concerned with data type. I use strings mostly.

I see what you're saying -- I can't see how to fix it.

class Dbg {
  public:  
    Dbg (Stream& serial_) : serial (serial_) {};

  private:
    Stream& serial;

So the caller provides a software or hardware serial device.

It has been too long since I used C++ in any amount. I'm having too much trouble remembering how C++ classes are constructed.
I think I do remember the use of the syntax xxx : yyy.
I believe the colon indicates inheritance.
I'm probably going to have to abandon this effort and just rely on other techniques like preprocessor macros -- it won't be as good, but I can get it developed easier.

Thanks for your help so far -- I'm trying to split my time between programming microcontrollers and my piano lessons and right now the piano is losing.

AWOL was faster, anyway:

constexpr byte rxPin = 2;                         // for Softserial
constexpr byte txPin = 3;

#include <SoftwareSerial.h>
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

class Dbg {
    Stream *interface;                // pointer to the used serial interface

    public :
    Dbg (Stream &interface) : interface {&interface}  {}

    void prt(char* txt) {
      interface->print("dbg(\"");
      interface->print(txt);
      interface->print("\")");
    }
};

Dbg dbg(mySerial);

char msg[] = "debug msg";

void setup() {
  pinMode(11, OUTPUT); digitalWrite(11, HIGH); // that's just for me, because my test is done in RS485
  
  mySerial.begin(4800);
  dbg.prt(msg);
}

void loop() {

}

prints

dbg("debug msg")

on SoftSerial.

if you comment the SoftSerial and replace it with

HardwareSerial &mySerial = Serial;    // HW Serial

it will just work on HW Serial ...

Thanks for the reply. I'm not able to really understand it at this time.
I'd have to go back to the books -- it's been too long.

I especially have some trouble understanding the line:
"Dbg (Stream &interface) : interface {&interface} {}"

I think it makes use of inheritance and I think the "interface" in the middle is a reserved word, while the other uses of that string of characters are user defined identifiers. If that is correct, then the other 2 (not the middle one) could be something else like "strm1", for example?
Is that correct?

no. It's a member initializer list --> https://en.cppreference.com/w/cpp/language/constructor

if it were inheritance, you would need a base class to inherit from.

"interface" has no meaning. you can call it "stream" or "foo" also... doesn't matter.

I probably didn't make my clear enough.
I intended to use a macro called dbg so I wouldn't have to write "mySerial.print()".

So, it is the parameter "sometext" that should be printed.
e.g. dbg("Hello"); would be the equivalent of mySerial.print("Hello");

Thanks