I need some help with serial communication between an ESP32 and a computer when using a terminal emulator.
Yes, I have read the “Serial Input Basics”, and quite a few more web pages or Youtube clips.
Here’s what it’s about:
I am making a system where an ESP32 takes readings from a DHT22, and uses those readings in order to set or reset a relay connected to a heating system if below or above a previously set reference temperature.
This works as intended.
Temperature and humidity readings and relay status are then sent to a MQTT broker over WiFi.
This works as intended.
The system will be installed at a location 80 km from where I live, so I want the user to be able to change certain configuration parameters without the need for me to be present (e.g. IP addresses, or temperature cutoff point or whatever). Those parameters are stored in nvs (using the Preferences.h library) and read if and when required.
This works as intended.
The idea is that the parameters can be changed through a serial connection between a the ESP32 and a computer running PuTTY or similar software. The user doesn’t have the skills, and is not interested in acquiring them, to change program code, run the Arduino IDE or VS Code …, but he will be able to follow a written procedure and execute it correctly.
Now here’s my problem : when I run the example shown below from within the terminal in VS Code on my computer, I can enter a text string, and send it to the ESP32 with a single newline (Enter key). When I do the same thing through a connection over PuTTY, I need to hit Enter twice before I get the “I received …” message (see the code below). VS Code behaves in the same way on a Windows and on a Linux computer, same goes for PuTTY
Additionally : when I press backspace, the cursor in the terminal window doesn't go to the left in order to erase or overwrite what I entered previously - but that's less important at this point in time.
I have played with the configuration settings in PuTTY (specifically Terminal – Implicit CR with every LF and vice-versa), but that doesn’t seem to have any influence – guess I’m not looking at the right place.
Here is the program code :
main.cpp
#include <Arduino.h>
#include "_utilities.h"
/*-----------------------------------------------------------*/
void setup()
{
Serial.begin(9600);
Serial.setTimeout(10000); // system allows for up to 10 seconds time between
// keystrokes - how's that for user support !
Serial.print("\n\n");
} // end setup()
/*-----------------------------------------------------------*/
void loop()
{
Serial.print("Enter some text (maximum 16 characters) : ");
_SerialInput(readBuffer,16);
Serial.print("\n\nI received : "); Serial.print(readBuffer); Serial.print("\n\n");
} // end loop()
/*-----------------------------------------------------------*/
_utilities.h
#include <Arduino.h>
char readBuffer[256];
void _SerialInput(char* buf, int maxLen);
_utilities.cpp
#include <Arduino.h>
void _SerialInput(char* buf, int maxLen)
{
char c[1]; c[0] = 0; // this will be used when reading the serial port
int loopCounter = 0, bufIndex = 0; // local variables
bool inputFinished = false;
for ( loopCounter = 0; loopCounter < maxLen; loopCounter++)
buf[loopCounter] = 0; // fill buffer bytes up to maxLen with nulls
while (!Serial.available()) // as long as there are no bytes available
; // do nothing
while (inputFinished == false) // wait until we have received a signal that input is done
// the signal takes the form of a newline character (see below)
{
if (Serial.available()) // here they are, start reading and processing
{
(void) Serial.readBytes(c,1); // read exactly one character from the serial input
switch(c[0]) // validation of just-entered character
{
// printable characters - acceptable
case 32 ... 125:
buf[bufIndex] = c[0]; // copy the just-read character to the readbuffer
Serial.print(c[0]); // show the character on the screen - that's what this function is about
bufIndex++; // position index pointer ready for next read
if (bufIndex > maxLen-1) // but avoid overflow
inputFinished = true;
break; // thank you, next
// some acceptable non-printable characters
case 8:
// backspace
bufIndex--; // bring buffer index one position backwards
if (bufIndex < 0)
bufIndex = 0; // but avoid underflow
break;
case 10: // line feed
case 13: // carriage return
// this is where it ends: when the user enters newline, CR, LF ..., we consider
// that there's no more input
// newline character is no part of the string that will be returned from this function
buf[bufIndex] = 0; // write NULL character at the current position
(void) Serial.readBytes(c,1);// flush the serial inputbuffer in case of double-byte input
inputFinished = true; // signal that we're done
break;
// other non-printable character, just reject
default:
// do nothing : don't copy input byte, don't update buffer index position
break;
} // end switch(c[0])
} // end if(Serial.available())
} // end while(inputFinished == false)
return; // and that's it
}
any creative ideas are welcome.
Thanks in advance