#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
const byte maxInputSize = 16;
char userInput[maxInputSize + 1];
enum t_userInput {NO_INPUT, PARTIAL, OVERFLOW, CORRECT};
void displayRemainingTime(uint16_t t_s) {
static byte lastDisplay = 0xFFFF;
if (t_s == lastDisplay) return;
lastDisplay = t_s;
char message[10];
snprintf(message, sizeof message, "%u s", t_s);
lcd.setCursor(9, 1);
lcd.print(F(" ")); // erase what was there
lcd.setCursor(16 - strlen(message), 1);
lcd.print(message);
}
t_userInput getUserInput(uint32_t maxWait, char endMarker = '\n') {
t_userInput inputType = NO_INPUT;
uint32_t startTime = millis();
byte currentPos = 0;
while (millis() - startTime <= maxWait) {
yield();
int r = Serial.read();
displayRemainingTime((maxWait - (millis() - startTime)) / 1000ul);
if (r == -1) continue;
startTime = millis(); // got something, postpone end of user iinput
if (r == endMarker) {
inputType = CORRECT;
break;
} else {
if (currentPos < maxInputSize) {
userInput[currentPos++] = r;
inputType = PARTIAL;
} else {
inputType = OVERFLOW;
break;
}
}
}
userInput[currentPos] = '\0';
lcd.setCursor(9, 1);
lcd.print(F(" ")); // erase what was there
return inputType;
}
void setup() {
Serial.begin(115200); Serial.println();
lcd.init();
lcd.backlight();
}
void loop() {
lcd.clear();
lcd.print(F("- Your message -"));
t_userInput status = getUserInput(10000ul);
lcd.clear();
switch (status) {
case NO_INPUT: lcd.setCursor(0, 0); lcd.print(F("Time out")); break;
case PARTIAL: lcd.setCursor(0, 0); lcd.print(F("Partial input")); lcd.setCursor(0, 1); lcd.print(userInput); break;
case OVERFLOW: lcd.setCursor(0, 0); lcd.print(F("Overflow")); lcd.setCursor(0, 1); lcd.print(userInput); break; // there might still be data in the incoming buffer...
case CORRECT: lcd.setCursor(0, 0); lcd.print(F("User message OK")); lcd.setCursor(0, 1); lcd.print(userInput); break;
}
delay(3000);
}