Pointer fails sporadic

Hi

I developed a Library to communicate with some RS485 devices. My Code uses a pointer to a Stream for abstracting HardwareSerial or SoftwareSerial and support multiple Serial’s in parallel.

The Code works 99% of time fine. But at 1% i got a really curious behavior.
For me it looks like the pointer to the Stream (_stream) doesnt work.
Usualy [color=navy]_stream->write(...)[/color] writes a byte to the corresponding Serial-Port.
But in these 1%, the same code doesn’t write anything out to the Serial-Port.
[color=navy]_stream->write(GNMSUP1_FRAMESTART1);[/color] doesnt work, neither [color=navy]_stream->write(0x77);//DEV//[/color].
But when i talk direct to the Serial (Serial1 in this Case), it works always fine: [color=navy]Serial1.write(0x99);//DEV//[/color]

After it fails some times it becomes working fine again (without any reset or user-interaction). So the pointer shoud be intact.
I’m confused. Can anybody epxplan what happens and support me with a helpful suggestion or solution?

Thanks
Andi

Here is the (relevant?) part of the Code. You find the full Library attached.

// H File, private
#define GNMSUP1_FRAMESTART1                              0xAA
HardwareSerial*   _hwStream;
SoftwareSerial*   _swStream;
Stream*           _stream;
    


// CPP File

// Constructor's (One for HW-Serial and one for SoftwareSerial. Currently use: HW-Serial.)
gnMsup1::gnMsup1(HardwareSerial& device) {
  _hwStream = &device;
}
gnMsup1::gnMsup1(SoftwareSerial& device) {
  _swStream = &device;
}

bool gnMsup1::begin(int32_t baudRate) {
  if (_hwStream) {                                                                            // Call Begin Function of corresponding SerialObject, wait till ready and assign it to _stream...
    _hwStream->begin(baudRate);
    while (!_hwStream) {}
    _stream = (Stream*)_hwStream;
  } else {
    _swStream->begin(baudRate);
    while (!_swStream) {}
    _stream = (Stream*)_swStream;
  }
  return true;
}

bool gnMsup1::_sendFrame() {
  while (_stream->available()) {
    _stream->read();
  }
  
	digitalWrite(25, HIGH);//DEV//
  _stream->write(GNMSUP1_FRAMESTART1);     	// THIS SHOUD BE THE CODE, but it doesnt work every time.
  _stream->write(0x77);//DEV//							// This behavious the same as the line above.
	Serial1.write(0x99);//DEV//								// This works always.
  Serial1.flush();//DEV//  
	digitalWrite(25, LOW);//DEV//
	
	//...
}

How I have debugd this?
I use a Arduino Mega 2560 with a custom designed Shield with some MAX485 and other Stuff on it.
It behaves the same regardless if I use the Arduino with or without the Shield.
I attached a Logic-Analyzer to monitor Serial1.RX, Serial1.TX and my “Debug-Pin (D25)”. I pull D25 high before writing the Stream and release it to low afterwards. The Logic-Analyzer shows now the Serial-Data in between. When it works, I got 0xAA (GNMSUP1_FRAMESTART1), 0x77 and 0x99.
I attached an Oscilloscope and all the voltage levels looking all ok.

gnMsup1.zip (34.4 KB)

Your code is incomplete and does not compile. Therefore, there’s no way to tell why it doesn’t work.

these are incorrect    while (!_hwStream) {}or    while (!_swStream) {}

In sketches when you seewhile(!Serial) ;you are actually calling the overloaded bool operator on the Serial class. For Arduino where it requires a connexion to the host, there is a different code (depends on platform)

what you do is looping while the pointer is not NULL and since it has been initialized, it's not...

I'm not sure why you feel there is a need to differentiate between HW and SW Serial. Your class could just have a pointer to a Stream as its instance variable.

Adafruit Fona class does this for example. look at this example

In the constructor they don't do much (attach the reset pin) and in the begin() method that's where they pass the reference to the Serial port (HW or SW) which is received as a reference to Stream and they extract the pointer to that reference.

Thank you for the reply.

I corrected the code in the constructor.
But because my code fails sporadic during runtime (means during the long life of the object), it cannot caused by the constructor. For me it looks like in some condition the pointer gets overwritten, but just in the context of the function. Because later in code it seems to work again.
But i cannot find a place where i overwrite the pointer?

I also checked the recursions, but they never occour.

But still maybe somewhere in the direction of memory-management? Because the first calls are always success and after a few hundreds of calls the failure appears.

only way to help you out is if you create a minimal script that demonstrate the issue

Its not so easy to provide an autonomous working example that uses still the same code, because there are slaves and a MQTT Server involved.
But i have done a additional debug-test and confirmed that the pointer _steam gets overwritten as i speculated before. See the additional line below.

On the console i got now a ton of the same output (6F7 seems the correct address for the pointer) and then i got 82E and the failure. But what part of my code is capable of temporary overwrite a pointer? I dont get it...

...
[color=green]6F7
6F7
6F7
6F7[/color]
[color=red][b]82E[/b][/color]
ERR: CR TIMEOUT...
[color=red][b]82E[/b][/color]
ERR: CR TIMEOUT...
[color=green]6F7[/color]
[color=red][b]82E[/b][/color]
ERR: CR TIMEOUT...
bool gnMsup1::_sendFrame(uint8_t address, uint8_t serviceNumber, uint8_t subserviceNumber, bool serviceFlag, bool pushFlag, bool waitForPushAnswer, bool commitReceivedFlag, bool retryOnCrFailure, uint8_t payload[], uint8_t payloadSize) {
digitalWrite(20, LOW);//DEV//
digitalWrite(21, LOW);//DEV//
digitalWrite(22, LOW);//DEV//
digitalWrite(24, LOW);//DEV//
digitalWrite(25, LOW);//DEV//
digitalWrite(21, HIGH);//DEV//
digitalWrite(21, LOW);//DEV//
[b]Serial.println((uint16_t) &_stream, HEX);//DEV//[/b]

what part of my code is capable of temporary overwrite a pointer? I dont get it...

An array overflow somewhere?

Array was a realy good keyword!

It seems like i was trying to catch a phantom...
As mentioned, i use multiple instances of my class for multiple serial interfaces. They where in an array grouped together and i see the "errors" of the second channel whitch polls from time to time its slaves. And of course i cannot see any data on the Serial1 when they where sendt to Serial2!
As soon as i just use one interface, it works fine...

Sorry - but you really helped me to get there.

/* //DEV//
gnMsup1 rs485net[3] = { gnMsup1(Serial1, gnMsup1::RS485, RS485DE1, gnMsup1::Master),
                       gnMsup1(Serial2, gnMsup1::RS485, RS485DE2, gnMsup1::Master),
                       gnMsup1(Serial3, gnMsup1::RS485, RS485DE3, gnMsup1::Master)};
*/ //DEV//
gnMsup1 rs485net[1] = { gnMsup1(Serial1, gnMsup1::RS485, RS485DE1, gnMsup1::Master)};

With your arrays created as such you can’t guarantee when they will be instantiated compared to the rest of the initialization of your arduino.

I would recommend to dynamically instantiate (new ...) them in the setup() once the init() phase is complete.