Serial input reading troubles

Hello folks,
I am trying to sniff a serial communication between a PC and a solar inverter. They communicate via HC-12 433MHz modules, one attached to a laptop serial port and the other embedded into inverter. Both are configured at 9600,n,8,1 and it works fine using Termite to send and receive telegrams on the laptop.
To sniff the link I attached an Arduino Uno to a second laptop but had not been able to receive telegrams from neither of the other two nodes. I spent many weeks browsing forums looking for a clue but it seems serial communication is not a hot theme anymore.
I had traced the problem to the link between the sniffer's HC-12 and Arduino Uno by using a signal analyzer, which was able to capture flawlessly the PC inquiry to inverter.


The answer is missing because the inverter is farther away to be within reach of sniffer's shorter antenna.
Follows a scheme of the sniffer, it is extremely simple Arduino UNO and HC-12
Actually RXD is tied to pin2 and TXD to pin3. The scheme was a guide.

I'd like to include its code too and found no way to do it in a proper way, but since it is also very simple I decided to copy/paste it here, sorry about that:

#include <SoftwareSerial.h>
SoftwareSerial HC12(2,3); // RX pino 2 , TX pino 3

String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete

void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
HC12.begin(9600); // Porta Serial do HC12
}

void loop() {
if (HC12.available()) {
// get the new byte:
char inChar = (char)HC12.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}

// print the string when a newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}

Those who can decode bytes just by their pattern will find the last byte in the logic analyzer picture is 0x64 instead of \n but even adding the expected terminator it made no difference. Here follows a picture of the actual sniffer and yes, that is an XP laptop to host the sniffer.

The newer one is were I run Termite to talk to the inverter. I would be very grateful for any help you can give. Thanks in advance and take care.

You are using a String to collect and print the data. Are you sure the data is actually readable ASCII characters?

Try a character array and print each character as HEX value. Or even better don not store them at all and send them strait to the Serial Monitor (as HEX value of course).

RXD on the HC12 is input to the radio module, and TXD is output from the radio module. If your description is correct, you have connected RXD to the SoftwareSerial receive pin and TXD to the SoftwareSerial transmit pin. You need to reverse those.

Another potential issue is that there are many counterfeit HC-12 modules out there, whose frequencies are not exactly the same as each others'. Sometimes "HC-12" modules from different vendors will not be able to communicate with each other.

Thank you for the suggestion. I already know it is not readable, the query telegram is always the same 14-byte sequence (f2 fe 12 12 d6 e9 1b 00 00 40 00 08 cf 65), as well as the response wich include an acknowledge echo of query plus another 14-byte variable response like (0e ab 59 10 01 3b 37 37 00 00 04 43 13 88) for instance.
I used the aforementioned code because my original one was not producing any output to the monitor. My guess is the /n missing prevents correct function. Perhaps it is better to read exactly 14 chars and send them individually to the monitor but I've done some tests and discovered HC12.available() never gets TRUE.
It is strange because the signal analyzer clearly shows the bytes arriving.

Thank you for the answer.
I'll try reversing RXD an TXD and post the results.
Regarding counterfeit modules frequency issue, I think it is not the case since the logic analyzer connected to the very same pins got the bytes correctly.
The problem lies in the communication between HC-12 and Arduino, by some reason the function HC-12.available() stay stuck with FALSE even when the logic analizer shows clearly there was available bytes. To be sure I made this test with and without logic analizer connected and both got same results.

Hello
Did you check the software protocol without the HF-part, using two Arduino only?

Hi @paulpaulson,
Do you mean placing an Arduino in lieu of the inverter? I did not understood how to do it.
I have three nodes: the PC querying, the inverter answering and the Arduino trying to snoop into the chat. Neither the PC nor the inverter has any Arduino within, they have only the same HF modules I am using to sniff with the Arduino.

Hello
That was a misunderstanding from my side.
You are sure that the external devices uses the same modulation as the HC-12 expects?

My final objective is indeed using the Arduino instead of the laptop to query and receive inverter answer. But I have no way of getting inside inverter to run TX, RX and ground wires from it.
As for the protocol it is rather straightforward: just send that 14-byte query and wait for the 28-byte answer.
I guess my real problem is to make HC12.available() transition to TRUE when a byte arrives.

Yes, I am. All modules use the factory-set configuration.

the baurate matches ?

What was the result?

Same result no matter reversed or not. All 3 HC-12 are with same setup: 9600,n,8,1

Geee! Discovered how to post code! I will try a new code:

#include <SoftwareSerial.h>
SoftwareSerial HC12(2,3);      // RX pino 2 , TX pino 3

String inputString = "";         // a String to hold incoming data

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
  HC12.begin(9600);            // Porta Serial do HC12
}

void loop() { // read 14-byte echo plus 14-byte answer
  for (int i=1; i<=28; i=i+1) {
  if (HC12.available()) {
    // get the new byte:
    char inChar = (char)HC12.read();
    // add it to the inputString:
    inputString += inChar;
    }
    // do something else while waiting
  }  
  
  // print the string
  {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
  }
}  

Wow! Seems it almost worked. Just a little correction for stop printing after telegram received will do, I hope.

I can see in the Monitor Serial it prints a string but it keeps printing blank lines over and over. If I remove the multiple /// on that two lines to avoid printing when noting was received it shows nothing on Monitor Serial.

#include <SoftwareSerial.h>
SoftwareSerial HC12(2,3);      // RX pino 2 , TX pino 3

int i;
boolean messageReceived = false;
String inputString = "";         // a String to hold incoming data

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
  HC12.begin(9600);            // Porta Serial do HC12
}

void loop() { // read 14-byte echo plus 14-byte answer
  if (HC12.available()) {
  messageReceived = true;
  for (i=1; i<=28; i=i+1) {
    // get the new byte:
    char inChar = (char)HC12.read();
    // add it to the inputString:
    inputString += inChar;
    }
  }  
  
  // print the string
  
///////////////   if (messageReceived) { 
    Serial.println(inputString);
    // clear the string and reset buffer:
    inputString = "";
    messageReceived = false;
///////////////    }
}  


Unfortunately the Sun is going down soon and the inverter will stop answering queries. New tests only tomorrow...

Hello
Try this snippet containing a modification of your sketch.
This modification was not tested.

void loop() { // read 14-byte echo plus 14-byte answer
int charCnt=0; 
do {
	if (HC12.available()) {
    char inChar = (char)HC12.read();
    inputString += inChar;
	charCnt++;
	}
} while (charCnt==28); 
void loop() { // read 14-byte echo plus 14-byte answer
  if (HC12.available()) {
  messageReceived = true;
  for (i=1; i<=28; i=i+1) {
    // get the new byte:
    char inChar = (char)HC12.read();
    // add it to the inputString:
    inputString += inChar;
    }
  } 

This does not look correct. You should not set the messageReceived = true until the 28 bytes have been read. The code set it true if only one byte is available. You proceed to read 28 bytes in the for loop whether they are available or not.

Try

 if (HC12.available()==28) {

I had a look at a HC-12 datasheet. It said 3.2 - 5.5V DC power supply but 3.3V TTL for RXD and TXD. As far as I know the Arduino Uno is 5V. You might want to use another 3.3V Arduino or a logic level shifter.

Your Logic Analyzer can likely handle both. That is why you see a valid signal in the Saleae software.

I am not sure whether the datasheet is from the original manufacturer and whether the HC-12 is supplied by only one company. Please have a look at the datasheet from your source.