How detect if serial data stops coming in[SOLVED]

I've been battling the last couple of days on/off, Mostly tonight.
Has you may have seen my last few posts in trying to over come this but I keep hitting a brick wall with it.
The code below using an ESP32 works perfectly in sending the data while the digital level is on and does not miss a beat. and trying to set a flag once the serial data stops coming in.
Has the code stands at the moment on powering up the ESP32 without the digital level the been switched on it's sending this below to the serial monitor. (great)

Data.test variable  = 20 = // no data flag
receiveUntilTimeout = 0 // no data flag
newData = 0

I turn on the digital level it sending the correct data out and then I get on the serial monitor

Data.test variable  = 10 /data is good
receiveUntilTimeout = 1 //data is good 
newData = 0

I then turn of the digital level and data stops sending but the flags are been been rest as I added some code to send the data to the serial monitor every second and can see that the flags do not get reset.
Code:

/*********
   #### TX CODE ####
  Wireless SPI-TRONIC Pro 3600 Digital Protractor
  General Information
  The Pro 3600 has an ASCII-format RS-232 compatible serial port for remote angle readout.
  The T&B Ansley 609-1027 connector on the back of the Pro3600 mates with industry
  standard cables. Angles are calculated and transmitted every 8/15 second (533 msec)
  Angle Output Format:
  The ASCII angle output may be read by a computer, or may directly drive a printer. Measured
  angles cover a full 360° range and the readout is between -180.00° and +180.00°.
  Format:
  <sign> XXX.XX <carriage return><line feed>
  examples:
  + 124.50
  + 32.70
  + 9.38
  - 4.32
  - 179.9
*********/
#include <esp_now.h>
#include <WiFi.h>
#include <TimedAction.h>
#include <HardwareSerial.h>
HardwareSerial MySerial(1);// MySerial.begin(9600, SERIAL_8N1, 16, 17);
const byte numChars = 9; //Number of bits to get
char receivedChars[numChars];//store the value of imcoming data
uint8_t broadcastAddress[] = {0X24, 0X6F, 0X28, 0XB3, 0XF3, 0XE0}; //MAC adress been sent to
boolean newData = false;
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long  timeReceived = 0;
#define ECHO_TO_SERIAL 1 //change to zero = no serial output
boolean receiveUntilTimeout = false;
// constants won't change:
const long interval = 1000;           // interval at which to blink (milliseconds)

typedef struct Data_struct {
  int test = 10;
  char receivedChars[numChars];   // an array to store the received data
} Data_struct;
Data_struct Data;

void printRecord(Print* pr, char sep = ',') {
  pr->print(Data.receivedChars[0]); // Print btye 0
  pr->print(Data.receivedChars[1]); // Print btye 1
  pr->print(Data.receivedChars[2] ); // Print btye 2
  pr->print(Data.receivedChars[3]); // Print btye 3
  pr->print(Data.receivedChars[4]); // Print btye 4
  pr->print(Data.receivedChars[5]); // Print btye 5
  pr->print(Data.receivedChars[6] ); // Print btye 6
  pr->print(Data.receivedChars[7]); // Print btye 7
  pr->print(Data.receivedChars[8]); // Print btye 7
  pr->print(sep);
  pr->print(Data.test); // Print btye 7
  pr->print(sep);
  pr->print(receiveUntilTimeout);
  pr->print(sep);
  pr->print(newData); // Print btye 7
  pr->print(sep);
  pr->println();

}

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  // Serial.print("Packet to: ");
  // Copies the sender mac address to a string
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  //Serial.print(macStr);
  // Serial.print(" send status:\t");
  // Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
  Serial.begin(9600);
  MySerial.begin(9600, SERIAL_8N1, 16, 17);
  Serial.println("<Arduino is ready>");
  WiFi.mode(WIFI_STA);
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_register_send_cb(OnDataSent);
  // register peer
  esp_now_peer_info_t peerInfo;
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
}

void loop() {
  recvWithEndMarker();
  if (newData ) { //new data received from eLevel
    newData = false;
    Data.test = 10;
#if ECHO_TO_SERIAL // Send debug to serial port if enabled
    printRecord(&Serial);
#endif //ECHO_TO_SERIAL
    Send_data();
  }

  //testing code
  //This only works on power up gives serail data out
  //turn pro3600 on then off nothing else happens
  if (!receiveUntilTimeout)// debugging method 1
    //  if (!receiveUntilTimeout && !newData)// debugging method 2
  {
    Data.test = 20; // no data
    Data.receivedChars[0] = 0;
    Data.receivedChars[1] = 0;
    Data.receivedChars[0] = 0;
    receiveUntilTimeout = false;// change it to reset
#if ECHO_TO_SERIAL
    printRecord(&Serial);
#endif //ECHO_TO_SERIAL
    // Someone is (or at least was) listening
    // Tell them your life story
  }
  // just for debuging
  /*
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;

      //send data outside the while loop
    #if ECHO_TO_SERIAL
      printRecord(&Serial);
    #endif //ECHO_TO_SERIAL
    }
  */
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
  if (Serial.available() > 0 && newData == false) { // Tried this
    //  while (Serial.available() > 0 && newData == false) { //tried this
    receiveUntilTimeout = true; //tried here
    rc = Serial.read();
    if (rc != endMarker) {
      Data.receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      Data.receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
      //  receiveUntilTimeout = true; //tried here
    }
  }
}

void Send_data() {
  esp_err_t result1 = esp_now_send(broadcastAddress, (uint8_t *) &Data, sizeof(Data));
}

Is there a way I can achieve this so that the flags get set to 20,1,0 when there is no serial data been received ?

Steveiboy:
I've been battling the last couple of days on/off, Mostly tonight.

Has you may have seen my last few posts in trying to over come this but I keep hitting a brick wall with it.

The code below using an ESP32 works perfectly in sending the data while the digital level is on and does not miss a beat. and trying to set a flag once the serial data stops coming in.

Has the code stands at the moment on powering up the ESP32 without the digital level the been switched on it's sending this below to the serial monitor. (great)

I turn on the digital level it sending the correct data out and then I get on the serial monitor

I then turn of the digital level and data stops sending but the flags are been been rest as I added some code to send the data to the serial monitor every second and can see that the flags do not get reset.
Code:

What does that mean?

Idahowalker:
What does that mean?

I'm trying to detect if the EPS32 stops receiving Serial data and trying to set some error flags. I'm using the ESP_NOW to send over wifi.

If (serial data is coming set error flags to ){
10,1 so that I know data is coming in from the digital level
else if (no serial data coming in set error flags to){
20,0 so that I know no serial data is coming in from the digital level
}

The end goal is to send the 20,1 to the receiver so I can be alerted that there is a problem.
But at the moment once Serial data stops coming in from the digital level and with sending the debugging to the serial monitor the error flags are not been rest.
Hopefully this make it a bit clearer. The incoming data as a start maker of +/- and the end marker is the new line (\n)

What is the length of time that no serial data coming in is an error?

Let's say your serial data stops for 3ms. an error is produced.

So you can have a variable.

int TheMilliSecondsReceivingaSerialThingy = millis();

in the receive serial routine is a

line of code that resets the millis time TheMilliSecondsReceivingaSerialThingy =millis() every time a serial thingy is received.

In your main loop you check to see if TheMilliSecondsReceivingaSerialThingy has reached or exceeded 3. When it does you can TheMilliSecondsHasExpiredThing.

Frankly, this would be a lot easier if you were using the ESP32 OS freeRTOS.

I have this task that runs in its own thread on its own time.

If MQTT data a stops coming in then error, reset.

void fmqttWatchDog( void * paramater )
{
  int maxNonMQTTresponse = 5;
  for (;;)
  {
    vTaskDelay( 1000 );
    if ( mqttOK >= maxNonMQTTresponse )
    {
      ESP.restart();
    }
  }
  vTaskDelete( NULL );
}

The task checks for mqttOK equal 5 and if it does reset the ESP32.

here this task sets mqttOK back to 0

void fparseMQTT( void *pvParameters )
{
  struct stu_message px_message;
  for (;;)
  {
    //wait 'forever' or until a message arrives in the queue
    if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
    {
      xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
      mqttOK = 0;
      xSemaphoreGive( sema_mqttOK );
      if ( px_message.topic == topicRemainingMoisture_0 )
      {
        x_eData.RM0  = String(px_message.payload).toFloat();
      }
    } //if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
  } //for(;;)
  vTaskDelete( NULL );
} // void fparseMQTT( void *pvParameters )

this task increments mqttOK

void DoTheBME680Thing( void *pvParameters )
{
  SPI.begin(); // initialize the SPI library
  vTaskDelay( 10 );
  if (!bme.begin()) {
    log_i("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  xEventGroupSetBits( eg, evtWaitForBME );
  TickType_t xLastWakeTime    = xTaskGetTickCount();
  const TickType_t xFrequency = 1000 * 15; //delay for mS
  int sendLRDataTrigger       = 240; // 1 hour-ish = 240
  int sendLRdataCount         = sendLRDataTrigger - 1; //send linear regression data when count is reached
  for (;;)
  {
    x_eData.Temperature  = bme.readTemperature();
    x_eData.Temperature  = ( x_eData.Temperature * 1.8f ) + 32.0f; // (Celsius x 1.8) + 32
    x_eData.Pressure     = bme.readPressure();
    x_eData.Pressure     = x_eData.Pressure / 133.3223684f; //converts to mmHg
    sendLRdataCount++;
    if ( sendLRdataCount >= sendLRDataTrigger )
    {
      xQueueOverwrite( xQ_lrData, (void *) &x_eData.Pressure ); // send to trends
      sendLRdataCount    = 0;
    }
    x_eData.Humidity     = bme.readHumidity();
    x_eData.IAQ          = fCalulate_IAQ_Index( bme.readGas(), x_eData.Humidity );
    //log_i( " temperature % f, Pressure % f, Humidity % f IAQ % f", x_eData.Temperature, x_eData.Pressure, x_eData.Humidity, x_eData.IAQ);
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    if ( MQTTclient.connected() )
    {
      MQTTclient.publish( topicInsideTemp, String(x_eData.Temperature).c_str() );
      vTaskDelay( 3 ); // gives the Raspberry Pi 4 time to receive the message and process
      MQTTclient.publish( topicInsideHumidity, String(x_eData.Humidity).c_str() );
      vTaskDelay( 3 ); // delay for RPi
      MQTTclient.publish( topicInsidePressure, String(x_eData.Pressure).c_str() );
      vTaskDelay( 3 ); // delay for RPi
      MQTTclient.publish( topicInsideIAQ, String(x_eData.IAQ).c_str() );
    }
    xSemaphoreGive( sema_MQTT_KeepAlive );
    xSemaphoreGive( sema_PublishPM ); // release publish of dust density
    xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
    mqttOK ++;
    xSemaphoreGive( sema_mqttOK );
    xQueueOverwrite( xQ_eData, (void *) &x_eData );// send data to display
    //
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    // log_i( "DoTheBME280Thing high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete ( NULL );
}

Thanks for your input, That's beyond me and don't totally understand it, I've not done anything done with freeRTOS that's something that I would have to look into and learn.

You can still do post#3.

Thanks Idahowalker
Just as I thought it turned out to be simple solution in the end after you have explained it in post #3.
I've added the code as you described and it's now working great,
I can now add the other bits of code now and add an led to flash as well to alert me something is wrong.

I blame the wife kept asking just do this little job for me (got to keep her happy) :), In the end I lost myself what I tried and what worked/not worked. Note to self do this type of stuff when wife not around and keep it simple :slight_smile:

Once again you thank you, you have been a great help

change your title to include "[SOLVED]"

+1 to you.

Oh, the freeRTOS code does the same thing as post#3.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.