I have this project that assumes I will be using all of 3 UART`s. Two of them for MITM/Interceptor of other devices communications, and one for debugging since I am still learning.
After some problems with Serial1 I have came to a point in which it is all good (after remapping GPIO`s), but Serial2 started acting. If I disable it below debug line goes away.
#include <Arduino.h>
#include <HardwareSerial.h>
void setup()
{
Serial.begin(9600);
// UART1 -> Serial1
// RX Pin -> GPIO 14
// TX Pin -> GPIO 12
// Speaker
Serial1.begin(57600, SERIAL_8O1, 4, 2);
// // UART2 -> Serial2
// // RX Pin -> GPIO 16
// // TX Pin -> GPIO 17
// // Console
Serial2.begin(57600, SERIAL_8O1, 16 ,17);
}
void loop()
{
if (Serial2.available())
{ // If anything comes in Serial2,
Serial1.write(Serial2.read()); // read it and send it out Serial1 (pins 0 & 1)
Serial.println("console_says: " + char(Serial2.read()));
}
if (Serial1.available())
{ // If anything comes in Serial1 (pins 0 & 1)
Serial2.write(Serial1.read()); // read it and send it out Serial2
Serial.println("speaker_says: " + char(Serial1.read()));
}
}
Unfortunately my current config spits %6u][E][%s:%u] %s(): Serial number is invalid, please use numers from 0 to %u
I am to little experienced to evaluate if this will have any impact on communication, but sure it has bad impact on debugging.
Digging down I figured out it comes (kind of obvious) from HardwareSerial.cpp.
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
{
if(_uart_nr >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
return;
}
So:
It is weird that %u parameter is not outputted properly in serial monitor - and i can see that this by itself can be a problem since it is part of condition.
SOC_UART_NUM variable comes from IDF libsoc_caps.h (IDF lib?) which states amount of accessible UARTs. All in all when testing it expands to 3 as it should.
_uart_nr I cant tell if this is behaving right but i have tried to fix this issue by adressing Serial 1 and 2 like so with no avail.
HardwareSerial Serial1(1); //if using UART1
HardwareSerial Serial2(2); //if using UART2
Also this is a double read. You call Serial2.read() once, which consumes the received character, and writes it to Serial1, then you do another read, wich either returns -1 (0xffffffff, ‘no character available’) or a new character if one really arrived, and try to write it to Serial.
Thank you both very much, it made significant difference.
Now it is not complaining about serial number.
Downside is that for some reason now only speaker ( in fact I think it is console but considering described protocoll it talks to much) is sending messages.
Switching terminal (Serial) to HEX does not give me any values according to above protocol.
I have already tried to change that GPIO2 (connected with onboard LED) thinking that this may be the cause.
It will take some time but I will try to debug things on my side once more.
for future research I have eddited:
void loop() {
streamSerial2Serial(Serial1, Serial2, "speaker"); //* to match my physical connection
streamSerial2Serial(Serial2, Serial1, "console"); //* to match my physical connection
streamSerial2Serial(Serial, Serial1, "terminal"); //* to be able to inject commands
}
Mh this is also not right because with the %s in printf you’re interpreting buffer as a zero-terminated string, however there’s no guarantee that it is. You would have to allocate buffer with one more byte and initialize it with all-zeroes, then it’s safe to handle as a null-terminated ASCII string.
But the protocol is a binary one anyways so it’ll not be ASCII readable text, but should be HEX encoded.
I would propose
void streamSerial2Serial(Stream& source, Stream& dest, const char* name) {
int length = source.available(); // check if data is available on source
if (length <= 0) return; // no data available? nothing to do... return!
char buffer[length]; // create correct sized buffer
source.readBytes(buffer, length); // read data from source into buffer
dest.write(buffer, length); // write buffer to dest
Serial.printf("%s says (hex):\n", name); // debug output
for(int i = 0; i < length; i++) {
uint8_t d = buffer[i];
if(d < 0x10) Serial.print("0");
Serial.print(d, HEX);
Serial.print(' ');
}
Serial.println();
}
I have improved wiring and now can see both console and speaker talking but console is complaining about lack of connection.
I will try Your code tomorrow and if something will be off I will try to hook up logic analyzer and if something I will test code with some ESP-based UART device.
Of course you’re absolutely right. I had implemented the debug output later and hadn’t thought about it.
For the sake of completeness, here is the correct implementation for ASCII-based protocols.
void streamSerial2Serial(Stream& source, Stream& dest, const char* name) {
int length = source.available(); // check if data is available on source
if (length <= 0) return; // no data available? nothing to do... return!
char buffer[length+1]; // create correct sized buffer + 1 byte for null-termination
buffer[length] = '\0'; // add zero termination at the end of the buffer
source.readBytes(buffer, length); // read data from source into buffer
dest.write(buffer, length); // write buffer to dest
Serial.printf("%s says: %s\r\n", name, buffer); // debug output to Serial
}
I can confirm that current config is working good with my test setup. I have made dummy ESP8266 UART device sending 3 bytes of data to ESP32 on Serial1. Serial 2 has jumper on TX and RX so full circle, takes about 0,59ms. Looks good, and similar configuration had worked with ESPhome effectively allowing console and speaker talk to each other. I have to investigate my previous setup.
Edit. Yep ! everything works now. I had most simple UART fault in my setup
Thank You For helping me out.