Receiving garbage data from ESP32

Hi guys, im new on this stuff, so dont blame me. I have used Chatgpt to make this code work on my arduino uno R4 Wifi, which also prints correct data. The program is set to send and read data from IR transmitter/receiver thru the TX and RX on the UNO R4 and D4 and D5 on my esp32
I am receiving correct numbers in the serial monitor but i want to make it work properly

The command needs to be send in 300 baud 7E2
and data received in 1200 baud 7E2

this is the ESP32 version (Arduino Nano ESP32) that reads the data, but with garbage as well

what am i doing wrong ?

#include <HardwareSerial.h>

#define PIN_LED LED_BUILTIN
#define KAMTIMEOUT 5000
#define BUFFER_SIZE 1500
#define RX_PIN D4 // Adjust for your specific board
#define TX_PIN D5

char rxdata[BUFFER_SIZE];
byte numRequest = 1;
char requests[] = {'1'}; // Changed to char to hold ASCII characters

void setup() {
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);

  Serial.begin(1200); // Use for debugging, keep at this baud rate
  Serial1.begin(300, SERIAL_7E2, RX_PIN, TX_PIN); // Start Serial1 for sending with 8N1 configuration for ASCII

  delay(15000); // Initial delay
}

void loop() {
  for (int i = 0; i < numRequest; i++) {
    kamReadReq(requests[i]);
    delay(15000); // Delay between requests
  }
}

void kamReadReq(char req) { // Parameter type changed to char
  // Configure Serial1 for sending the request at 300 baud
  Serial1.begin(300, SERIAL_7E2); // Change to 8N1 configuration
  Serial1.print("/#"); // Using print for ASCII characters
  Serial1.print(req);  // Using print for ASCII character
  Serial1.print('\r'); // Carriage return in ASCII
  Serial1.flush();     // Ensure command is sent

  // Switch Serial1 to receiving configuration at 1200 baud
  Serial1.begin(1200, SERIAL_7E2); // Keep 8N1 configuration for receiving

  unsigned short rxnum = kamReceive();

  // Debug output
  Serial.begin(1200);
  if (rxnum != 0) {
    Serial.println("Received response:");
    for (int i = 0; i < rxnum; i++) {
      Serial.print(rxdata[i]); // Print as is, as data is now ASCII
    }
    Serial.println();
  }
}

unsigned short kamReceive() {
  unsigned long rxindex = 0;
  unsigned long starttime = millis();

  int r = -1; // Changed to int to handle possible -1 return value from read()

  while (r != '\r') { // Use CR ('\r') as the end-of-message delimiter
    if (millis() - starttime > KAMTIMEOUT) {
      return rxindex;
    }
    if (rxindex >= BUFFER_SIZE) {
      return rxindex;
    }
    if (Serial1.available() > 0) {
      r = Serial1.read();
      if (r != -1) { // Only store if read() did not return -1
        rxdata[rxindex++] = r;
        starttime = millis(); // Reset the timeout timer on each byte received
      }
    }
  }
  return rxindex; 
}

the print looks like this (every numbers except some of the zeroes and garbage symbols are relevant data)

14:47:54.225 -> 0�9�93��0�30����0����5��0000000�0000000�0000000�0000000�0000000�0000000�00000�3��

14:48:16.235 -> Received response:

14:48:16.235 -> 0�9�93��0�30����0����5��0000000�0000000�0000000�0000000�0000000�0000000�00000�3��

14:48:38.257 -> Received response:

14:48:38.257 -> 0�9�93��0�30����0����5��0000000�0000000�0000000�0000000�0000000�0000000�00000�3��

14:49:00.234 -> Received response:

14:49:00.234 -> 0�9�93��0�30����0����5��0000000�0000000�0000000�0000000�0000000�0000000�00000�3��

the working code from my uno r4 wifi looks like this

#define PIN_LED        13  


#define KAMTIMEOUT   5000  
#define BUFFER_SIZE  1500

byte rxdata[BUFFER_SIZE];  

byte numRequest = 1; 
byte requests[]={'1'};

void setup () {

  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, 0);

  delay(15000);
}

void loop () {

  for(int i =0; i<numRequest; i++){
    kamReadReq(requests[i]);


    delay(15000);
  }
}


float kamReadReq(byte req) {
  

  byte sendmsg[] = { '/', '#', req, 0x0D, 0x0A};

  int rxnum=0;
  byte single = 0;


  for (int i = 0; i < BUFFER_SIZE; i++) {
    rxdata[i]= 8;
  }


  Serial1.begin(300); 
  for (int i = 0; i < 5; i++) {
  Serial1.write(sendmsg[i]); 
  }
  Serial1.end();
  Serial1.flush();


  Serial1.begin(1200, SERIAL_7E2);

  rxnum = kamReceive();
  Serial1.end();
  Serial1.flush();


  Serial.begin(1200);
    if(rxnum != 0) {
        Serial.println("");
        Serial.print("Writing: ");


        Serial.print("kWh: ");
        for(int i = 0; i < 7; i++) {
            Serial.print((char)(rxdata[i]));
        }

        Serial.print(", m3: ");
        for(int i = 7; i < 15; i++) { 
            Serial.print((char)(rxdata[i])); 
        }
        
        Serial.println(); 
    }
    Serial.flush();
    Serial.end();
    return 0;
}

unsigned short kamReceive() {

  unsigned long rxindex = 0;
  unsigned long starttime = millis();
  
  byte r=0;
 
 
  while(r != 0x03){
 
    if(millis()-starttime > KAMTIMEOUT) {
      return rxindex;
    }
    if(rxindex>=BUFFER_SIZE){
      return rxindex;
    }

    
    while(Serial1.available()>0) {
      
      r = Serial1.read();    
      rxdata[rxindex] = r;
      rxindex++; 
      starttime = millis();
    }
  }
  return rxindex; 
}

IMHO people should stop doing this sh*tty things, and start studying with their own brain.

What do you mean with that? Are you talking about TWO different serial ports, or the same serial will constantly switch between the two different settings? Never had/seen such kind of requirement, so please describe what you need to do in detail.
I see you (ok, it wasn't you, it's that dumb ChatGPT I suppose...) start two serials with the two settings:

  Serial.begin(1200); // Use for debugging, keep at this baud rate
  Serial1.begin(300, SERIAL_7E2, RX_PIN, TX_PIN); // Start Serial1 for sending with 8N1 configuration for ASCII

but on the function "kamReadReq()" I also see you call the begin() method to change the speed:

  // Configure Serial1 for sending the request at 300 baud
  Serial1.begin(300, SERIAL_7E2); // Change to 8N1 configuration
  Serial1.print("/#"); // Using print for ASCII characters
  Serial1.print(req);  // Using print for ASCII character
  Serial1.print('\r'); // Carriage return in ASCII
  Serial1.flush();     // Ensure command is sent

  // Switch Serial1 to receiving configuration at 1200 baud
  Serial1.begin(1200, SERIAL_7E2); // Keep 8N1 configuration for receiving

It isn't recommended to call "begin()" except for the first time on setup().
So, what is the right handling of those serial lines? What are you trying to connect to?

i got a Kamstrup Energy Monitor, that uses IR to transmit data, its basically the same project as this one LINK but just on a esp32 .
The protocol for some reason is using two different configurations: Most of requests are sent using 300baud, 7E2. and response is transmitted using 1200vaud, 7E2 The request "/!?" uses 300baud, 7E2 for both sending request and recieving the response.
the requirements to send commands and receive data
image
image

Pretty strange behaviour, I wonder why they used such kind of protocol (instead of sending and receiving everything at 1200, it isn't a hard thing to do even as hardware solution, it just need a small buffer).

BTW, I found someone with a correct way to change baud rate on the fly and it looks like you could solve that garbage from the output:

Serial.flush(); // wait for last transmitted data to be sent 
Serial.begin(newBaudRate);
while(Serial.available()) Serial.read(); // empty  out possible garbage from input buffer
// if the device was sending data while you changed the baud rate, the info in the input buffer
// is corrupted.

Let me know.

PS: And please stop using ChatGPT for coding...

Here you can read the complete thread:

There is an AltSoftwareSerial for ESP32.
Using that and the UART (Serial2) might be easier than changing the bps on the fly.
(Transmit on one, receive on the other).

The following sketch Verifies/Compiles It doesn't include the UART and it's Untested --

#include <SoftwareSerial.h>

#define MYPORT_TX 12
#define MYPORT_RX 13

EspSoftwareSerial::UART myPort;

//[...]

void setup ()
{
  Serial.begin(115200); // Standard hardware serial port

  myPort.begin(1200, SWSERIAL_7E2, MYPORT_RX, MYPORT_TX, false);
  if (!myPort) 
  { // If the object did not initialize, then its configuration is invalid
    Serial.println("Invalid EspSoftwareSerial pin configuration, check config"); 
    while (1) 
    { // Don't continue with invalid configuration
      delay (1000);
    }
  }
} 

void loop ()
{
  
}

Ok, blame me instead. That's ok, I have broad shoulders. Garbage characters like that are very common with mismatched baud rates. Is there a reason you can't match yours? Your code that Chat GPT wrote sets one rate at 1200 baud for debugging, according to the comment in that line. Why not just match the two baud rates? What's the worst that happens? It doesn't work? It doesn't work now, so...

Smart solution, using one serial at 1200 to send commands and another one at 300 to receive only could do the job (then connecting RX to one serial port and TX to the other).

I can't get why using a "software serial" instead of using the physical UARTs available on ESP32. Like using Serial for debugging, and Serial1 for TX at 300 and Serial2 for RX at 300 (or vice versa). It could also be ok, as the baud rates are very low...

Anyway, I suggest @abdul06 to give it a try.

Note: I have never had the need to use Serial1 on ESP32 but I read that UART1 needs a pin reassignment before it can be used, be advised.

PS: if that code has been created by ChatGPT, I don't know if he has anough experience to make the changes...

Serial2, from what I read, is the only one that is "in the clear".

Yes, but I read that even if UART1 is "internal", can be used by assigning two of the other available GPIOs.

As I said before, I never had to do that, and at the moment I don't have an ESP32 at hand to test that, but it makes sense. Using the existing HardwareSerials could avoid the SoftwareSerial library usage (also making the code a bit smaller).

In line with your previous missive, I'm not holding my breath pending anyone's synthesis.

Oh, ChatGPT, Lord of us all - wouldst thou reveal unto me 'the code' (using the ESP32's hardware uarts)?

You can map the pins for Serial1 with for example:

Serial1.begin(9600, SERIAL_8N1, RX1, TX1);

@noobmastha Thanks, I'm good here.
UART1/Serial1 is, or can be, associated with SPI Flash access.
In offering suggestions (Viz. Espsoftserial), I was trying to avoid problems.
I'm not as 'in the dark' as you may figure.
And it looks like the OP is uninterested.

I suspect this doesn't involve specifically the use of a Nano ESP32 either.