Problems reading / using strings from serial port

I've been trying to modify a working sketch provided with the TFT_HX8357 libraries. Basic setup was working, using an NTP demo on the WeMOS D1 (Retired) board. It's working fine, sending a UTC string and a local time string out its serial port every second. I had used the MegaMultiSerial demo sketch to read the data from the D1 and send it out the serial port connected to the computer. Worked great. When I started to modify the sketch to incorporate the TFT display, that's when I started having problems.

I'm trying to get a two-to-four line display showing the date and time in both UTC and local time. (Ham radio operator, so UTC is handy.) Eventually, once I get the basic functionality down, I can add alarms, timers, etc. But, I can't seem to get anything legible to display on the TFT, nor determine if I've got a line that is UTC or local time.

I'd love some help on this!

WeMOS D1 code (comments removed for space):

/*
 Udp NTP Client

 Get the time from a Network Time Protocol (NTP) time server

 created 4 Sep 2010 by Michael Margolis
 modified 9 Apr 2012 by Tom Igoe
 updated for the ESP8266 12 Apr 2015  by Ivan Grokhotkov

 This code is in the public domain.
 */
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Time.h>
#include <Timezone.h>
#include <SoftwareSerial.h>
SoftwareSerial ESPSerial(0,1);

TimeChangeRule myDST = {"EDT", Second, Sun, Mar, 2, -240};    //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {"EST", First, Sun, Nov, 2, -300};     //Standard time = UTC - 5 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr;        //pointer to the time change rule, use to get TZ abbrev
time_t utc, local;

char ssid[] = "*************";  //  your network SSID (name)
char pass[] = "********";       // your network password

unsigned int localPort = 2390;      // local port to listen for UDP packets

IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

WiFiUDP udp;

void setup()
{
  Serial.begin(9600);
  Serial.println();
  Serial.println();

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
}

void loop()
{
  WiFi.hostByName(ntpServerName, timeServerIP); 

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  delay(1000);
  
  int cb = udp.parsePacket();
  if (!cb) {
  }
  else {
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer


    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;


    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 - seventyYears;


    time_t utcCalc = epoch;

    Serial.println();
    utc = epoch;
    printTime(utc, "UTC");
    printDate(utc, "UTC");
    local = myTZ.toLocal(utc, &tcr);
    printTime(local, tcr -> abbrev);
    printDate(local, tcr -> abbrev);
    delay(100);

  }

}


unsigned long sendNTPpacket(IPAddress& address)
{
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

void printTime(time_t t, char *tz)
{
    sPrintI00(hour(t));
    sPrintDigits(minute(t));
    sPrintDigits(second(t));
    Serial.print(' ');
    Serial.print(tz);
    Serial.println();

}

void printDate(time_t t, char *tz)
{
    Serial.print(dayShortStr(weekday(t)));
    Serial.print(' ');
    sPrintI00(day(t));
    Serial.print(' ');
    Serial.print(monthShortStr(month(t)));
    Serial.print(' ');
    Serial.print(year(t));
    Serial.print(' ');
    Serial.print(tz);
    Serial.println();

}

void sPrintI00(int val)
{
    if (val < 10) Serial.print('0');
    Serial.print(val, DEC);
    return;
}

void ESPsPrintI00(int val)
{
    if (val < 10) ESPSerial.print('0');
    ESPSerial.print(val, DEC);
    return;
}

void sPrintDigits(int val)
{
    Serial.print(':');
    if(val < 10) Serial.print('0');
    Serial.print(val, DEC);
}

void ESPsPrintDigits(int val)
{
    ESPSerial.print(':');
    if(val < 10) ESPSerial.print('0');
    ESPSerial.print(val, DEC);
}

Mega2560/TFT code:

/*
  A digital clock using a TFT LCD screen to show the time.
  Uses NTP data from connected WeMOS D1

  Based on clock sketch by Gilchrist 6/2/2014 1.0 and the example with the TFT_HX8357 libs.

*/

#include <TFT_HX8357.h>
#include <User_Setup.h>
#define TFT_GREEN 0x7E0

TFT_HX8357 tft = TFT_HX8357();       // Invoke custom library

unsigned int colour = 0;

void setup() {

  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setTextSize(1);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);

  // targetTime = millis() + 1000;

    Serial.begin(9600);
    Serial1.begin(9600);
  
}

void loop() {

  int   timeIn[22];
  char  *timeUTC, *timeLocal;
  
 
  if (Serial1.available() >= 22) {
    for (int i=0; i<=21; i++) {
      timeIn[i] = Serial.read();
      Serial.write(timeIn[i]);
    }
    timeIn[22] = '\0';
  }

  // Update digital time
  int xpos = 90;
  int ypos = 85; // Top left corner of clock text, about half way down
  int ysecs = ypos + 24;
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.setTextSize(2);
  tft.drawString(timeUTC, xpos, ypos, 1);
  tft.drawString(timeLocal, xpos, ypos+1, 2);

}

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

...R

That helped a great deal!

I still have issues, but I'm working through them. Current Mega2560 code follows:

/*
  A digital clock using a TFT LCD screen to show the time.
  Demonstrates use of the font printing routines.

  It uses the serial output of a WeMOS D1 (Retired) using NTP to set the time
  
  Based on clock sketch by Gilchrist 6/2/2014 1.0

*/

#include <TFT_HX8357.h>
#include <User_Setup.h>
#define TFT_GREEN 0x7E0

#include <string.h>

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    
    while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

TFT_HX8357 tft = TFT_HX8357();       // Invoke custom library
unsigned int colour = 0;


void setup() {
  // put your setup code here, to run once:

  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setTextSize(1);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);

  // targetTime = millis() + 1000;

    Serial.begin(9600);
    Serial1.begin(9600);
    Serial.println("Starting up...");
  
}

void loop() {

  char *dateUTC, *timeUTC, *dateLocal, *timeLocal;

  recvWithEndMarker();
  showNewData();

  char *timeIn = receivedChars;
 
  if (timeIn[0] == '0' || timeIn[0] == '1' || timeIn[0] == '2' ) {
    int p = strstr(timeIn, "UTC");
    if ( p ) {
      timeUTC = timeIn;
    } else {
      timeLocal = timeIn;
    }
  } else {
    int p = strstr(timeIn, "UTC");
    if ( p ) {
      dateUTC = timeIn;
    } else {
      dateLocal = timeIn;
    }
  }

  newData = false;
 
  // Update digital time
  int xpos = 90;
  int ypos = 85; // Top left corner of clock text, about half way down
  int ysecs = ypos + 24;
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.setTextSize(3);
  tft.drawString(dateUTC, xpos, ypos, 1);
  Serial.println(dateUTC);
  tft.drawString(timeUTC, xpos, ypos+30, 1);
  Serial.println(timeUTC);
  tft.drawString(dateLocal, xpos, ypos+60, 1);
  Serial.println(dateLocal);
  tft.drawString(timeLocal, xpos, ypos+90, 1);
  Serial.println(timeLocal);
  delay(1000);
}

Okay, so I seem to be getting some form of garbled data from the serial lines. Current code:

/*
  A digital clock using a TFT LCD screen to show the time.
  Demonstrates use of the font printing routines.

  It uses the serial output of a WeMOS D1 (Retired) using NTP to set the time
  
  Based on clock sketch by Gilchrist 6/2/2014 1.0

*/

#include <TFT_HX8357.h>
#include <User_Setup.h>
#define TFT_GREEN 0x7E0

#include <string.h>
#include <math.h>

const byte numChars = 20;
const byte timeWidth = 12;
const byte dateWidth = numChars;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;

    ndx = 0;
    for ( int i = 0; i == numChars ; i++) {
      receivedChars[i] = '\0';
    }
    
    while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        // Serial.println("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

TFT_HX8357 tft = TFT_HX8357();       // Invoke custom library
unsigned int colour = 0;


void setup() {
  // put your setup code here, to run once:

  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setTextSize(1);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);

  // targetTime = millis() + 1000;

    Serial.begin(9600);
    Serial1.begin(9600);
    // Serial.println("Starting up...");
  
}

void loop() {

  // char *dateUTC, *timeUTC, *dateLocal, *timeLocal;
  char dateUTC[dateWidth], timeUTC[timeWidth], dateLocal[dateWidth], timeLocal[timeWidth];

  recvWithEndMarker();
  showNewData();

  char timeIn[numChars+1];
  strcpy(timeIn, receivedChars);
 
  if (timeIn[0] == '0' || timeIn[0] == '1' || timeIn[0] == '2' ) {
    int p = strstr(timeIn, "UTC");
    if ( p ) {
      strncpy(timeUTC,timeIn, timeWidth);
    } else {
      strncpy(timeLocal,timeIn, timeWidth);
    }
  } else {
    int p = strstr(timeIn, "UTC");
    if ( p ) {
      strncpy(dateUTC,timeIn, dateWidth);
    } else {
      strncpy(dateLocal,timeIn, dateWidth);
    }
  }

  newData = false;
 
  // Update digital time
  int xpos = 10;
  int ypos = 45; // Top left corner of clock text, about half way down
  int ysecs = ypos + 24;
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.setTextSize(4);
  tft.drawString(dateUTC, xpos, ypos, 1);
  tft.drawString(timeUTC, xpos, ypos+50, 1);
  tft.drawString(dateLocal, xpos, ypos+100, 1);
  tft.drawString(timeLocal, xpos, ypos+150, 1);
  
  // Debugging code to send what we receive to the Serial Monitor once a second
  if (!(fmod (millis(), 1000) ) ){
    Serial.println(dateUTC);
    Serial.println(timeUTC);
    Serial.println(dateLocal);
    Serial.println(timeLocal);
  }
  
}

Roommate helped me figure out that I needed to use either strcpy() or strncpy() instead of trying to simply assign a pointer to a pointer. (DOH!) However, neither the 1s debug output, nor the TFT display are showing properly. The TFT shows oddball characters (sixteenth note, heart, other such kruft), while the serial debug output (going to the serial monitor of the IDE) shows truncated, inappropriately concatenated and otherwise garbled text.

When I was simply copying one byte at a time from Serial1 to Serial, all worked well. Now...not so good.

You have not provided much information from which to help you.

Is the function showNewData() dislaying the correct data?

If not post an example of what it does display and an example of what it should display.

...R

Output from showNewData()

18:28:51 UTC

Sun 31 Dec 2017 UTC
13:28:51 EST



18:28:52 UTC

Sun 31 Dec 2017 UTC
13:28:52 EST



18:28:53 UTC

Sun 31 Dec 2017 UTC
13:28:53 EST

It SHOULD display

Sun 31 Dec 2017 UTC
18:28:52 UTC
Sun 31 Dec 2017 EST
13:28:52 EST

Sun 31 Dec 2017 UTC
18:28:53 UTC
Sun 31 Dec 2017 EST
13:28:53 EST

Sun 31 Dec 2017 UTC
18:28:54 UTC
Sun 31 Dec 2017 EST
13:28:54 EST

You have the line

newData = false;

in two places - lines 58 and 111.

Temporarily comment out line 111 and see what happens.

...R

Not much difference.

So, I tried commenting out line 58 and uncommenting 111. Same thing.

Then temporarily modify the function recvWithEndMarker() so it prints the ASCII value of every character it receives.
I think this will do it

    while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
        Serial.println((byte) rc); //  <---------new

but I always get mixed up with the correct code for this

My guess is that there are extra characters in your data stream that are the cause of the problem.

...R

Output:

50
50
58
53
52
58⸮⸮⸮⸮j
49
13
10


50
50
58
53
52
58
51
57
32
85
84
67
13
10
22:54:39 UTC

84
117
101
32
48
50
32
74
97
110
32
50
48
49
56
32
85
84
67
13
10
Tue 02 Jan 2018 UTC
49
55
58
53
52
58
51
57
32
69
83
84
13
10
17:54:39 EST

84
117
101
32
48
50
32
74
97
110
32
50
48
49
69
83
84
13
10
Tue 02 Jan 201EST

13
10


50
50
58
53
52
58
52
48
32
85
84
67
13
10
22:54:40 UTC

84
117
101
32
48
50
32
74
97
110
32
50
48
49
56
32
85
84
67
13
10
Tue 02 Jan 2018 UTC
49
55
58
53
52
58
52
48
32
69
83
84
13
10
17:54:40 EST

84
117
101
32
48
50
32
74
97
110
32
50
48
49
13
10


50
50
58
53
52
58
52
49
32
85
84
67
13
10
22:54:41 UTC

84
117
101
32
48
50
32
74
97
110
32
50
48
49
56
32
85
84
67
13
10
Tue 02 Jan 2018 UTC
49
55
58
53
52
58
52
49
32
69
83
84
13
10
17:54:41 EST

84
117
101
32
48
50
32
74
97
110
32
50
48
49
13
10


50
50
58
53
52
58
52
50
32
85
84
67
13
10
22:54:42 UTC

84
117
101
32
48
50
32
74
97
110
32
50
48
49
56
32
85
84
67
13
10
Tue 02 Jan 2018 UTC
49
55
58
53
52
58
52
50
32
69
83
84
13
10
17:54:42 EST

84
117
101
32
48
50
32
74
97
110
32
50
48
49
13
10


50
50
58
53
52
58
52
51
32
85
84
67
13
10
22:54:43 UTC

try this... a functional approach, checking to see if you are getting data correctly:

/*
  A digital clock using a TFT LCD screen to show the time.
  Demonstrates use of the font printing routines.

  It uses the serial output of a WeMOS D1 (Retired) using NTP to set the time
  
  Based on clock sketch by Gilchrist 6/2/2014 1.0

*/

#include <TFT_HX8357.h>
#include <User_Setup.h>
#define TFT_GREEN 0x7E0

#include <string.h>
#include <math.h>

template<class T> inline Print &operator << (Print &object, T argument)
{
  object.print(argument);
  return object;
}

const size_t MAX_MESSAGE_BUFFER_LENGTH = 32;

TFT_HX8357 tft = TFT_HX8357();       // Invoke custom library
unsigned int colour = 0;

void setup() 
{
  Serial.begin(9600);
  Serial1.begin(9600);
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(1);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
}

void loop() 
{
  if(const char* newMessage = checkForNewMessage(Serial1, '\n'))
  {
    Serial << (F("Just Recieved:\t")) << (newMessage) << (F("\n"));
    if (strstr(newMessage, "DST")
    {
      parseDstMessageAndUpdateDisplay(newMessage);
    }
    else if (strstr(newMessage, "UTC"))
    {
      Serial << (F("UTC Message"));
    }
  }
}

void parseDstMessageAndUpdateDisplay(const char* mssg)
{
  Serial << (F("Parsing Message: \t")) << (mssg);
  char newMssg[strlen(mssg) + 1];
  // insert your parsing function here:

  // insert your display update here
}

const char* checkForNewMessage(Stream& stream, const char endMarker)
{
  static char incomingMessage[MAX_MESSAGE_LENGTH] = "";
  static byte idx = 0;
  if(stream.available())
  {
    incomingMessage[idx] = stream.read();
    if(incomingMessage[idx] == endMarker)
    {
      incomingMessage[idx] = '\0';
      idx = 0;
      return incomingMessage;
    }
    else
    {
      idx++;
      if(idx > MAX_MESSAGE_LENGTH - 1)
      {
        //stream.print(F("{\"error\":\"message too long\"}\n"));  //you can send an error to sender here
        idx = 0;
        incomingMessage[idx] = '\0';
      }
    }
  }
  return nullptr;
}

then you can get the parse and update display function back in...

Referring to Reply #9 most of the inputs result in the correct output but some of them don't seem to cause any output.

My guess is that some of the time data is arriving while the variable newData is set to true.

Post the latest version of your program.

...R