Software Serialport Referencing in a Structure

Hi

I am trying a New project on Serial Devices and came across this Syntax which i couldn,t Understand how are u declaring a Serial Device using its address in the structure.

struct conv{
  conv(HardwareSerial* serialPort)
      : serialPort(serialPort),          
        suspended(false){}

  HardwareSerial* serialPort;
  bool suspended;  
};

// Map to physical port layout
conv convs[4] = 
{
  {&Serial1}, {&Serial2}, {&Serial3}, {&Serial4}
};

I Would like to make my own part where i can replace HardwareSerial with SoftwareSerial

conv convs[2]{
{port1(2,3)}, {port1(4,5)}
};

where 2&3 are different for each port in the array.

1 Like

do you really need a class?

SoftwareSerial comPorts[] = {{2,3}, {4,5}};

if you want to give them names

SoftwareSerial  port1(2,3);
SoftwareSerial  port2(4,5);
SoftwareSerial * comPorts[]  = {&port1, &port2};

note that SoftwareSerial is really poor at dealing with multiple instances... so not sure what you'll get from that

I already have it running in a array.

Yes i will be needing a class cause i will be declaring more Variables in it.

well just build a class in the same way then and you instantiate in the constructor

#include <SoftwareSerial.h>

class demo {
  public:
    demo(const byte rx, const byte tx) {
      serialPort = new SoftwareSerial(rx, tx);
    }

    SoftwareSerial* serialPort;
};


demo comPorts[] = {{2, 3}, {4, 5}};

Thanks That Helped me

by the way, as you instantiated something with new, this class needs a destructor where you call delete (and copy constructor and copy assignment operator likely)

see The rule of three/five/zero

if you declare the object as a Stream (if that was your hint), then you can't use listen() which will be needed to handle multiple SoftwareSerial lines in parallel.

I am able to listen to the ports but i need to do it one after another which i have no problem in.

And yes i found the post Serial port as a variabe helpful cause i can access more no of ports on MEGA and store the data corresponding to it in the structure or class as well as booleans and other variables also.

Thank u everyone i guess this post would be open in case of another doubt or error

unless you have a very specific project where you control when the modules attached to the serial ports "speak" to you (ie you ping them, they answer otherwise they are quiet), and that the flow is reasonable and you don't need to go faster than 9600 bauds then using multiple SoftwareSerial is just calling for trouble..

get a proper hardware with multiple hardware ports...

Why the dynamic allocation?

To introduce the rule as training practice since OP wanted to do a class. (I was looking for an answer with more code but no destructor, so. a learning opportunity but did not happen)

Feel free to suggest an alternative

Maybe something like this?

class mySoftwareSerial {
public:
  mySoftwareSerial(uint8_t rx, uint8_t tx, int var)
    : comPort(SoftwareSerial(rx, tx)), var(var) {}

  SoftwareSerial comPort;
  int var;
};

Or using class inheritance, e.g.,

class mySoftwareSerial : public SoftwareSerial {
public:
  mySoftwareSerial(uint8_t rx, uint8_t tx, int var)
    : SoftwareSerial(rx, tx), var(var) {}

  int var;
};

In both cases the array can be initialised as follows.

mySoftwareSerial comPorts[] = {{2, 3, 0}, {4, 5, 1}};

Disclaimer: untested code.

yes that would work

Using a naked new should be avoided (C++ Core Guidelines ES.60: Avoid new and delete outside resource management functions, R.11: Avoid calling new and delete explicitly), and you shouldn't use raw pointers that own memory (C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning).

The concern of resource management should be cleanly separated from the application logic that actually uses the SoftwareSerial instance. Such a resource management class should then follow the rule of three/five, and the class that uses it should follow the rule of zero.

If you have access to the standard library, you can use std::unique_ptr to manage the resource.


In this case, however, no dynamic allocation is necessary, simply have the SoftwareSerial object as a member variable:

class Demo {
  public:
    Demo(uint8_t rx_pin, uint8_t tx_pin)
      : serialPort {rx_pin, tx_pin} {}

    SoftwareSerial serialPort;
};

Inheritance is not appropriate here, because there is no is-a relationship: a class that uses a serial port for communication is not itself a serial port.

I can not tell. What gives it away?

This one worked for me without Dynamic memory allocation and easier to access.

How do i assign the rx and tx values from setup by using values from another array of pins.

Is the answer not already given in post #13 and #14? The first suggestion in post #13 is almost equivalent to the one you are using now, except it has an extra variable (var) as an example.

That was pre-declaring the values for the new class but how do i assign value to it taken from another array of int which storrs the pin numbers. Like


Demo ports[],port;

ports[i]=port(rx[i],tx[i]);

Something like this. Correct me if i am wrong.

Do you mean something like this?

uint8_t const rx[] = {2, 4};
uint8_t const tx[] = {3, 5};
Demo ports[] = {{rx[0], tx[0]}, {rx[1], tx[1]}};